Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetoot...
authorDavid S. Miller <davem@davemloft.net>
Wed, 2 Aug 2017 00:42:58 +0000 (17:42 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 2 Aug 2017 00:42:58 +0000 (17:42 -0700)
Johan Hedberg says:

====================
pull request: bluetooth-next 2017-08-01

Here's our first batch of Bluetooth patches for the 4.14 kernel:

 - Several new USB IDs for the btusb driver
 - Memory leak fix in btusb driver
 - Cleanups & fixes to hci_nokia, hci_serdev and hci_bcm drivers
 - Fixed cleanup path in mrf24j40 (802.15.4) driver probe function
 - A few other smaller cleanups & fixes to drivers

Please let me know if there are any issues pulling. Thanks.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
1855 files changed:
Documentation/ABI/testing/sysfs-class-mtd
Documentation/DMA-API-HOWTO.txt
Documentation/DMA-API.txt
Documentation/DMA-ISA-LPC.txt
Documentation/DMA-attributes.txt
Documentation/IPMI.txt
Documentation/IRQ-affinity.txt
Documentation/IRQ-domain.txt
Documentation/IRQ.txt
Documentation/Intel-IOMMU.txt
Documentation/SAK.txt
Documentation/SM501.txt
Documentation/bcache.txt
Documentation/bt8xxgpio.txt
Documentation/btmrvl.txt
Documentation/bus-virt-phys-mapping.txt
Documentation/cachetlb.txt
Documentation/cgroup-v2.txt
Documentation/circular-buffers.txt
Documentation/clk.txt
Documentation/core-api/kernel-api.rst
Documentation/cpu-load.txt
Documentation/cputopology.txt
Documentation/crc32.txt
Documentation/crypto/asymmetric-keys.txt
Documentation/dcdbas.txt
Documentation/debugging-via-ohci1394.txt
Documentation/dell_rbu.txt
Documentation/device-mapper/dm-raid.txt
Documentation/devicetree/bindings/ata/sata_rcar.txt
Documentation/devicetree/bindings/clock/img,boston-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt
Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
Documentation/devicetree/bindings/mmc/img-dw-mshc.txt
Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
Documentation/devicetree/bindings/mtd/denali-nand.txt
Documentation/devicetree/bindings/mtd/elm.txt
Documentation/devicetree/bindings/mtd/gpmc-nand.txt
Documentation/devicetree/bindings/mtd/gpmc-nor.txt
Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
Documentation/devicetree/bindings/mtd/gpmi-nand.txt
Documentation/devicetree/bindings/mtd/microchip,mchp23k256.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/mtk-nand.txt
Documentation/devicetree/bindings/mtd/nand.txt
Documentation/devicetree/bindings/mtd/partition.txt
Documentation/devicetree/bindings/net/brcm,amac.txt
Documentation/devicetree/bindings/net/brcm,bgmac-nsp.txt [deleted file]
Documentation/devicetree/bindings/net/gpmc-eth.txt
Documentation/devicetree/bindings/net/mediatek-net.txt
Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt
Documentation/devicetree/bindings/ptp/brcm,ptp-dte.txt
Documentation/devicetree/bindings/pwm/pwm-meson.txt
Documentation/devicetree/bindings/pwm/pwm-stm32.txt
Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt
Documentation/devicetree/bindings/rtc/brcm,brcmstb-waketimer.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/cortina,gemini.txt [deleted file]
Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
Documentation/devicetree/bindings/serial/fsl-imx-uart.txt
Documentation/digsig.txt
Documentation/driver-api/basics.rst
Documentation/efi-stub.txt
Documentation/eisa.txt
Documentation/fault-injection/fault-injection.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/vfs.txt
Documentation/flexible-arrays.txt
Documentation/futex-requeue-pi.txt
Documentation/gcc-plugins.txt
Documentation/highuid.txt
Documentation/hw_random.txt
Documentation/hwspinlock.txt
Documentation/input/index.rst
Documentation/intel_txt.txt
Documentation/io-mapping.txt
Documentation/io_ordering.txt
Documentation/iostats.txt
Documentation/irqflags-tracing.txt
Documentation/isa.txt
Documentation/isapnp.txt
Documentation/kdump/kdump.txt
Documentation/kernel-per-CPU-kthreads.txt
Documentation/kobject.txt
Documentation/kprobes.txt
Documentation/kref.txt
Documentation/ldm.txt
Documentation/lockup-watchdogs.txt
Documentation/lzo.txt
Documentation/mailbox.txt
Documentation/memory-barriers.txt
Documentation/memory-hotplug.txt
Documentation/men-chameleon-bus.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/strparser.txt
Documentation/nommu-mmap.txt
Documentation/ntb.txt
Documentation/numastat.txt
Documentation/padata.txt
Documentation/parport-lowlevel.txt
Documentation/percpu-rw-semaphore.txt
Documentation/phy.txt
Documentation/pi-futex.txt
Documentation/pnp.txt
Documentation/preempt-locking.txt
Documentation/printk-formats.txt
Documentation/pwm.txt
Documentation/rbtree.txt
Documentation/remoteproc.txt
Documentation/rfkill.txt
Documentation/robust-futex-ABI.txt
Documentation/robust-futexes.txt
Documentation/rpmsg.txt
Documentation/rtc.txt
Documentation/security/keys/core.rst
Documentation/sgi-ioc4.txt
Documentation/siphash.txt
Documentation/smsc_ece1099.txt
Documentation/static-keys.txt
Documentation/svga.txt
Documentation/tee.txt
Documentation/this_cpu_ops.txt
Documentation/trace/ftrace.txt
Documentation/translations/ko_KR/memory-barriers.txt
Documentation/unaligned-memory-access.txt
Documentation/vfio-mediated-device.txt
Documentation/vfio.txt
Documentation/virtual/kvm/api.txt
Documentation/virtual/kvm/msr.txt
Documentation/xillybus.txt
Documentation/xz.txt
Documentation/zorro.txt
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/include/uapi/asm/ioctls.h
arch/arc/include/asm/Kbuild
arch/arc/include/uapi/asm/Kbuild
arch/arc/mm/dma.c
arch/arm/include/asm/Kbuild
arch/arm/include/asm/bug.h
arch/arm/include/asm/cacheflush.h
arch/arm/include/asm/flat.h
arch/arm/include/asm/kexec.h
arch/arm/include/asm/kvm_hyp.h
arch/arm/include/asm/uaccess.h
arch/arm/include/asm/ucontext.h
arch/arm/include/uapi/asm/Kbuild
arch/arm/kernel/bios32.c
arch/arm/kernel/machine_kexec.c
arch/arm/kernel/setup.c
arch/arm/kernel/signal.c
arch/arm/mach-omap2/hsmmc.c
arch/arm/mach-omap2/hsmmc.h
arch/arm/mach-sa1100/jornada720_ssp.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mm/dma-mapping-nommu.c
arch/arm/mm/dma-mapping.c
arch/arm64/Kconfig
arch/arm64/include/asm/Kbuild
arch/arm64/include/asm/atomic_lse.h
arch/arm64/include/asm/bug.h
arch/arm64/include/asm/stackprotector.h
arch/arm64/include/asm/string.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/uaccess.h
arch/arm64/include/uapi/asm/Kbuild
arch/arm64/kernel/cpu_ops.c
arch/arm64/kernel/smp.c
arch/arm64/kernel/topology.c
arch/arm64/kernel/traps.c
arch/arm64/lib/copy_page.S
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/mmap.c
arch/arm64/mm/mmu.c
arch/arm64/mm/numa.c
arch/blackfin/include/asm/Kbuild
arch/blackfin/include/asm/bug.h
arch/blackfin/include/asm/flat.h
arch/blackfin/include/asm/nmi.h
arch/blackfin/include/uapi/asm/Kbuild
arch/blackfin/kernel/flat.c
arch/blackfin/kernel/nmi.c
arch/c6x/include/asm/Kbuild
arch/c6x/include/asm/flat.h
arch/c6x/include/uapi/asm/Kbuild
arch/cris/arch-v10/drivers/gpio.c
arch/cris/include/asm/Kbuild
arch/cris/include/uapi/asm/Kbuild
arch/frv/include/asm/tlbflush.h
arch/h8300/include/asm/Kbuild
arch/h8300/include/asm/flat.h
arch/h8300/include/uapi/asm/Kbuild
arch/hexagon/include/asm/Kbuild
arch/hexagon/include/uapi/asm/Kbuild
arch/ia64/include/asm/Kbuild
arch/ia64/include/asm/uaccess.h
arch/ia64/kernel/machine_kexec.c
arch/ia64/kernel/mca.c
arch/ia64/sn/pci/pcibr/pcibr_ate.c
arch/ia64/sn/pci/tioce_provider.c
arch/m32r/include/asm/Kbuild
arch/m32r/include/asm/flat.h
arch/m32r/include/uapi/asm/Kbuild
arch/m68k/coldfire/intc-simr.c
arch/m68k/include/asm/Kbuild
arch/m68k/include/asm/flat.h
arch/m68k/include/asm/uaccess.h
arch/m68k/include/uapi/asm/Kbuild
arch/metag/include/asm/Kbuild
arch/metag/include/uapi/asm/Kbuild
arch/microblaze/include/asm/Kbuild
arch/microblaze/include/asm/flat.h
arch/microblaze/include/uapi/asm/Kbuild
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/boot/dts/img/Makefile
arch/mips/boot/dts/img/boston.dts [new file with mode: 0644]
arch/mips/boot/dts/mti/sead3.dts
arch/mips/configs/ar7_defconfig
arch/mips/configs/ath79_defconfig
arch/mips/configs/bcm63xx_defconfig
arch/mips/configs/bigsur_defconfig
arch/mips/configs/bmips_be_defconfig
arch/mips/configs/capcella_defconfig
arch/mips/configs/cavium_octeon_defconfig
arch/mips/configs/ci20_defconfig
arch/mips/configs/cobalt_defconfig
arch/mips/configs/decstation_defconfig
arch/mips/configs/e55_defconfig
arch/mips/configs/fuloong2e_defconfig
arch/mips/configs/generic/board-boston.config [new file with mode: 0644]
arch/mips/configs/gpr_defconfig
arch/mips/configs/ip22_defconfig
arch/mips/configs/ip27_defconfig
arch/mips/configs/ip28_defconfig
arch/mips/configs/ip32_defconfig
arch/mips/configs/jazz_defconfig
arch/mips/configs/jmr3927_defconfig
arch/mips/configs/lasat_defconfig
arch/mips/configs/lemote2f_defconfig
arch/mips/configs/loongson3_defconfig
arch/mips/configs/malta_kvm_defconfig
arch/mips/configs/malta_kvm_guest_defconfig
arch/mips/configs/malta_qemu_32r6_defconfig
arch/mips/configs/maltaaprp_defconfig
arch/mips/configs/maltasmvp_defconfig
arch/mips/configs/maltasmvp_eva_defconfig
arch/mips/configs/maltaup_defconfig
arch/mips/configs/markeins_defconfig
arch/mips/configs/mips_paravirt_defconfig
arch/mips/configs/mpc30x_defconfig
arch/mips/configs/msp71xx_defconfig
arch/mips/configs/mtx1_defconfig
arch/mips/configs/nlm_xlp_defconfig
arch/mips/configs/nlm_xlr_defconfig
arch/mips/configs/pnx8335_stb225_defconfig
arch/mips/configs/qi_lb60_defconfig
arch/mips/configs/rb532_defconfig
arch/mips/configs/rbtx49xx_defconfig
arch/mips/configs/rm200_defconfig
arch/mips/configs/rt305x_defconfig
arch/mips/configs/sb1250_swarm_defconfig
arch/mips/configs/tb0219_defconfig
arch/mips/configs/tb0226_defconfig
arch/mips/configs/tb0287_defconfig
arch/mips/configs/workpad_defconfig
arch/mips/generic/Kconfig
arch/mips/generic/Makefile
arch/mips/generic/board-sead3.c
arch/mips/generic/init.c
arch/mips/generic/vmlinux.its.S
arch/mips/generic/yamon-dt.c [new file with mode: 0644]
arch/mips/include/asm/Kbuild
arch/mips/include/asm/branch.h
arch/mips/include/asm/cmpxchg.h
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/cpu-type.h
arch/mips/include/asm/cpu.h
arch/mips/include/asm/irq.h
arch/mips/include/asm/mach-ath25/cpu-feature-overrides.h
arch/mips/include/asm/mach-au1x00/cpu-feature-overrides.h
arch/mips/include/asm/mach-bcm63xx/cpu-feature-overrides.h
arch/mips/include/asm/mach-cobalt/cpu-feature-overrides.h
arch/mips/include/asm/mach-dec/cpu-feature-overrides.h
arch/mips/include/asm/mach-generic/mc146818rtc.h
arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h
arch/mips/include/asm/mach-ip27/cpu-feature-overrides.h
arch/mips/include/asm/mach-ip28/cpu-feature-overrides.h
arch/mips/include/asm/mach-ip32/cpu-feature-overrides.h
arch/mips/include/asm/mach-jz4740/cpu-feature-overrides.h
arch/mips/include/asm/mach-loongson64/boot_param.h
arch/mips/include/asm/mach-loongson64/cpu-feature-overrides.h
arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h
arch/mips/include/asm/mach-rc32434/cpu-feature-overrides.h
arch/mips/include/asm/mach-rm/cpu-feature-overrides.h
arch/mips/include/asm/mach-sibyte/cpu-feature-overrides.h
arch/mips/include/asm/mach-tx49xx/cpu-feature-overrides.h
arch/mips/include/asm/machine.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/module.h
arch/mips/include/asm/pgalloc.h
arch/mips/include/asm/smp.h
arch/mips/include/asm/spinlock.h
arch/mips/include/asm/spinlock_types.h
arch/mips/include/asm/syscall.h
arch/mips/include/asm/uaccess.h
arch/mips/include/asm/uasm.h
arch/mips/include/asm/vdso.h
arch/mips/include/asm/yamon-dt.h [new file with mode: 0644]
arch/mips/include/uapi/asm/inst.h
arch/mips/include/uapi/asm/ioctls.h
arch/mips/kernel/Makefile
arch/mips/kernel/branch.c
arch/mips/kernel/cmpxchg.c [new file with mode: 0644]
arch/mips/kernel/cps-vec.S
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/mips-cm.c
arch/mips/kernel/module-rela.c [deleted file]
arch/mips/kernel/module.c
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/proc.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/setup.c
arch/mips/kernel/smp-cps.c
arch/mips/kernel/smp.c
arch/mips/kernel/syscall.c
arch/mips/kernel/unaligned.c
arch/mips/lib/memcpy.S
arch/mips/loongson64/common/env.c
arch/mips/loongson64/common/init.c
arch/mips/loongson64/loongson-3/irq.c
arch/mips/loongson64/loongson-3/smp.c
arch/mips/math-emu/cp1emu.c
arch/mips/mm/c-r4k.c
arch/mips/mm/dma-default.c
arch/mips/mm/tlbex.c
arch/mips/mm/uasm-micromips.c
arch/mips/mm/uasm-mips.c
arch/mips/mm/uasm.c
arch/mips/net/Makefile
arch/mips/vdso/gettimeofday.c
arch/mn10300/include/asm/bug.h
arch/mn10300/include/asm/nmi.h
arch/mn10300/kernel/mn10300-watchdog-low.S
arch/mn10300/kernel/mn10300-watchdog.c
arch/nios2/include/asm/Kbuild
arch/nios2/include/asm/signal.h [deleted file]
arch/nios2/include/uapi/asm/Kbuild
arch/openrisc/include/asm/Kbuild
arch/openrisc/include/uapi/asm/Kbuild
arch/parisc/configs/712_defconfig
arch/parisc/configs/a500_defconfig
arch/parisc/configs/b180_defconfig
arch/parisc/configs/c3000_defconfig
arch/parisc/configs/c8000_defconfig
arch/parisc/configs/default_defconfig
arch/parisc/configs/generic-32bit_defconfig
arch/parisc/configs/generic-64bit_defconfig
arch/parisc/include/asm/Kbuild
arch/parisc/include/asm/bug.h
arch/parisc/include/asm/pdcpat.h
arch/parisc/include/asm/uaccess.h
arch/parisc/include/uapi/asm/Kbuild
arch/parisc/include/uapi/asm/ioctls.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/firmware.c
arch/parisc/kernel/irq.c
arch/parisc/kernel/pdt.c
arch/parisc/kernel/process.c
arch/parisc/kernel/vmlinux.lds.S
arch/powerpc/Kconfig
arch/powerpc/Makefile
arch/powerpc/include/asm/atomic.h
arch/powerpc/include/asm/book3s/64/hash.h
arch/powerpc/include/asm/book3s/64/mmu.h
arch/powerpc/include/asm/book3s/64/pgalloc.h
arch/powerpc/include/asm/book3s/64/pgtable.h
arch/powerpc/include/asm/book3s/64/radix.h
arch/powerpc/include/asm/bug.h
arch/powerpc/include/asm/mmu_context.h
arch/powerpc/include/asm/nmi.h
arch/powerpc/include/asm/opal-api.h
arch/powerpc/include/asm/pgtable.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/smp.h
arch/powerpc/include/asm/uaccess.h
arch/powerpc/include/uapi/asm/ioctls.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/cpu_setup_power.S
arch/powerpc/kernel/dt_cpu_ftrs.c
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/fadump.c
arch/powerpc/kernel/idle_book3s.S
arch/powerpc/kernel/kvm.c
arch/powerpc/kernel/mce_power.c
arch/powerpc/kernel/misc_64.S
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/watchdog.c [new file with mode: 0644]
arch/powerpc/kvm/book3s_64_mmu_hv.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/lib/feature-fixups.c
arch/powerpc/lib/sstep.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/mmap.c
arch/powerpc/mm/mmu_context_book3s64.c
arch/powerpc/mm/pgtable-hash64.c
arch/powerpc/mm/pgtable-radix.c
arch/powerpc/mm/pgtable_64.c
arch/powerpc/mm/subpage-prot.c
arch/powerpc/mm/tlb-radix.c
arch/powerpc/perf/isa207-common.c
arch/powerpc/perf/power9-events-list.h
arch/powerpc/perf/power9-pmu.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/powernv/opal.c
arch/powerpc/platforms/powernv/setup.c
arch/powerpc/platforms/pseries/reconfig.c
arch/s390/include/asm/bug.h
arch/s390/include/asm/uaccess.h
arch/s390/kernel/machine_kexec.c
arch/s390/kernel/perf_cpum_sf.c
arch/s390/kernel/setup.c
arch/s390/kvm/kvm-s390.c
arch/s390/mm/pgtable.c
arch/sh/include/asm/Kbuild
arch/sh/include/asm/bug.h
arch/sh/include/asm/flat.h
arch/sh/include/asm/stackprotector.h
arch/sh/include/uapi/asm/Kbuild
arch/sh/include/uapi/asm/ioctls.h
arch/sh/mm/cache-sh5.c
arch/sparc/include/asm/Kbuild
arch/sparc/include/asm/nmi.h
arch/sparc/include/asm/trap_block.h
arch/sparc/include/asm/uaccess_64.h
arch/sparc/include/uapi/asm/Kbuild
arch/sparc/include/uapi/asm/ioctls.h
arch/sparc/kernel/mdesc.c
arch/sparc/kernel/nmi.c
arch/sparc/kernel/pci_sun4v.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/sun4v_ivec.S
arch/sparc/kernel/traps_64.c
arch/tile/include/asm/Kbuild
arch/tile/include/asm/uaccess.h
arch/tile/include/uapi/arch/abi.h
arch/tile/include/uapi/arch/intreg.h [new file with mode: 0644]
arch/tile/include/uapi/asm/Kbuild
arch/tile/mm/init.c
arch/um/Makefile
arch/um/drivers/stdio_console.c
arch/um/include/asm/common.lds.S
arch/um/include/asm/io.h [new file with mode: 0644]
arch/um/include/shared/os.h
arch/um/include/shared/skas/stub-data.h
arch/um/kernel/physmem.c
arch/um/kernel/trap.c
arch/um/kernel/um_arch.c
arch/um/kernel/umid.c
arch/um/os-Linux/execvp.c
arch/um/os-Linux/main.c
arch/um/os-Linux/mem.c
arch/um/os-Linux/skas/process.c
arch/um/os-Linux/start_up.c
arch/um/os-Linux/umid.c
arch/um/os-Linux/util.c
arch/unicore32/include/asm/Kbuild
arch/unicore32/include/uapi/asm/Kbuild
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/boot/Makefile
arch/x86/boot/compressed/Makefile
arch/x86/boot/compressed/misc.c
arch/x86/boot/string.c
arch/x86/configs/i386_defconfig
arch/x86/configs/x86_64_defconfig
arch/x86/crypto/sha1_ssse3_glue.c
arch/x86/entry/entry_64.S
arch/x86/events/core.c
arch/x86/events/intel/core.c
arch/x86/events/intel/cstate.c
arch/x86/events/intel/ds.c
arch/x86/events/intel/lbr.c
arch/x86/events/intel/uncore_snbep.c
arch/x86/events/perf_event.h
arch/x86/include/asm/bug.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/entry_arch.h
arch/x86/include/asm/hardirq.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/io.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/kprobes.h
arch/x86/include/asm/kvm_emulate.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/mmu_context.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/stackprotector.h
arch/x86/include/asm/string_32.h
arch/x86/include/asm/string_64.h
arch/x86/include/asm/svm.h
arch/x86/include/asm/uaccess.h
arch/x86/include/uapi/asm/kvm_para.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/apic/hw_nmi.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/crash.c
arch/x86/kernel/devicetree.c
arch/x86/kernel/irq.c
arch/x86/kernel/irqinit.c
arch/x86/kernel/kprobes/core.c
arch/x86/kernel/kvm.c
arch/x86/kernel/reboot.c
arch/x86/kvm/Kconfig
arch/x86/kvm/hyperv.c
arch/x86/kvm/hyperv.h
arch/x86/kvm/i8254.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu.c
arch/x86/kvm/mmu.h
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lib/memcpy_32.c
arch/x86/math-emu/Makefile
arch/x86/math-emu/fpu_emu.h
arch/x86/math-emu/reg_compare.c
arch/x86/mm/mmap.c
arch/x86/platform/intel-mid/device_libs/platform_max7315.c
arch/x86/platform/uv/tlb_uv.c
arch/x86/um/os-Linux/registers.c
arch/x86/um/setjmp_32.S
arch/x86/um/setjmp_64.S
arch/x86/um/user-offsets.c
arch/x86/xen/mmu_pv.c
arch/x86/xen/smp_pv.c
arch/x86/xen/time.c
arch/xtensa/include/asm/Kbuild
arch/xtensa/include/asm/fb.h [deleted file]
arch/xtensa/include/asm/flat.h
arch/xtensa/include/uapi/asm/Kbuild
arch/xtensa/include/uapi/asm/ioctls.h
block/bfq-iosched.c
block/bfq-iosched.h
block/bfq-wf2q.c
block/blk-core.c
block/blk-mq-cpumap.c
certs/Makefile
crypto/af_alg.c
crypto/authencesn.c
drivers/acpi/ec.c
drivers/acpi/internal.h
drivers/acpi/irq.c
drivers/acpi/nfit/core.c
drivers/acpi/numa.c
drivers/acpi/sleep.c
drivers/acpi/x86/utils.c
drivers/android/binder.c
drivers/ata/Kconfig
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/sata_rcar.c
drivers/atm/zatm.c
drivers/base/dma-coherent.c
drivers/base/dma-mapping.c
drivers/base/power/domain.c
drivers/base/power/sysfs.c
drivers/base/property.c
drivers/base/regmap/regmap-w1.c
drivers/block/nbd.c
drivers/block/virtio_blk.c
drivers/block/xen-blkfront.c
drivers/char/random.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/imgtec/Kconfig [new file with mode: 0644]
drivers/clk/imgtec/Makefile [new file with mode: 0644]
drivers/clk/imgtec/clk-boston.c [new file with mode: 0644]
drivers/clocksource/timer-of.c
drivers/cpufreq/arm_big_little.c
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/dbx500-cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/mt8173-cpufreq.c
drivers/cpufreq/qoriq-cpufreq.c
drivers/crypto/Kconfig
drivers/crypto/atmel-sha.c
drivers/crypto/bcm/spu2.c
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/caamhash.c
drivers/crypto/caam/key_gen.c
drivers/crypto/cavium/cpt/cptvf_algs.c
drivers/crypto/cavium/nitrox/nitrox_main.c
drivers/crypto/chelsio/chcr_algo.c
drivers/crypto/chelsio/chcr_crypto.h
drivers/crypto/inside-secure/safexcel.c
drivers/dax/device-dax.h
drivers/dax/device.c
drivers/dax/pmem.c
drivers/dax/super.c
drivers/devfreq/governor_userspace.c
drivers/devfreq/rk3399_dmc.c
drivers/devfreq/tegra-devfreq.c
drivers/dma-buf/dma-fence.c
drivers/dma-buf/sync_debug.c
drivers/dma-buf/sync_file.c
drivers/firmware/efi/libstub/Makefile
drivers/fsi/fsi-core.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdkfd/kfd_device.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
drivers/gpu/drm/amd/include/kgd_kfd_interface.h
drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
drivers/gpu/drm/bridge/panel.c
drivers/gpu/drm/drm_dp_aux_dev.c
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_framebuffer.c
drivers/gpu/drm/drm_ioc32.c
drivers/gpu/drm/drm_vblank.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/exynos/exynos_drm_mic.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i915/gvt/cmd_parser.c
drivers/gpu/drm/i915/gvt/display.c
drivers/gpu/drm/i915/gvt/gtt.c
drivers/gpu/drm/i915/gvt/handlers.c
drivers/gpu/drm/i915/gvt/kvmgt.c
drivers/gpu/drm/i915/gvt/scheduler.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_clflush.c
drivers/gpu/drm/i915/i915_gem_clflush.h
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_vma.h
drivers/gpu/drm/i915/intel_cdclk.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_engine_cs.c
drivers/gpu/drm/i915/intel_fbdev.c
drivers/gpu/drm/i915/intel_gvt.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c
drivers/gpu/drm/i915/selftests/mock_gem_device.c
drivers/gpu/drm/imx/ipuv3-plane.c
drivers/gpu/drm/imx/parallel-display.c
drivers/gpu/drm/mediatek/Makefile
drivers/gpu/drm/mediatek/mtk_disp_color.c [new file with mode: 0644]
drivers/gpu/drm/mediatek/mtk_disp_ovl.c
drivers/gpu/drm/mediatek/mtk_drm_crtc.c
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
drivers/gpu/drm/mediatek/mtk_drm_drv.c
drivers/gpu/drm/mediatek/mtk_drm_drv.h
drivers/gpu/drm/mediatek/mtk_drm_plane.c
drivers/gpu/drm/mediatek/mtk_dsi.c
drivers/gpu/drm/mediatek/mtk_hdmi.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgf119.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm200.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgf119.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/radeon_kfd.c
drivers/gpu/drm/rockchip/Kconfig
drivers/gpu/drm/rockchip/cdn-dp-core.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
drivers/gpu/drm/vc4/vc4_crtc.c
drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
drivers/gpu/drm/vmwgfx/vmwgfx_context.c
drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
drivers/gpu/host1x/dev.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-ortek.c
drivers/hid/usbhid/hid-core.c
drivers/hv/channel.c
drivers/hwmon/applesmc.c
drivers/ide/ide-timings.c
drivers/infiniband/core/addr.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/roce_gid_mgmt.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/bnxt_re/Kconfig
drivers/infiniband/hw/bnxt_re/bnxt_re.h
drivers/infiniband/hw/bnxt_re/ib_verbs.c
drivers/infiniband/hw/bnxt_re/ib_verbs.h
drivers/infiniband/hw/bnxt_re/main.c
drivers/infiniband/hw/bnxt_re/qplib_fp.c
drivers/infiniband/hw/bnxt_re/qplib_fp.h
drivers/infiniband/hw/bnxt_re/qplib_sp.c
drivers/infiniband/hw/bnxt_re/qplib_sp.h
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/hfi1/chip.c
drivers/infiniband/hw/hfi1/qp.c
drivers/infiniband/hw/hfi1/qp.h
drivers/infiniband/hw/hns/hns_roce_hw_v1.c
drivers/infiniband/hw/hns/hns_roce_main.c
drivers/infiniband/hw/i40iw/i40iw.h
drivers/infiniband/hw/i40iw/i40iw_cm.c
drivers/infiniband/hw/i40iw/i40iw_ctrl.c
drivers/infiniband/hw/i40iw/i40iw_main.c
drivers/infiniband/hw/i40iw/i40iw_puda.c
drivers/infiniband/hw/i40iw/i40iw_utils.c
drivers/infiniband/hw/i40iw/i40iw_verbs.c
drivers/infiniband/hw/i40iw/i40iw_verbs.h
drivers/infiniband/hw/mlx4/cm.c
drivers/infiniband/hw/mlx4/cq.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/mcg.c
drivers/infiniband/hw/mlx4/mlx4_ib.h
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mlx4/srq.c
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/qedr/verbs.c
drivers/infiniband/hw/qib/qib_qp.c
drivers/infiniband/hw/qib/qib_verbs.h
drivers/infiniband/sw/rdmavt/qp.c
drivers/infiniband/sw/rxe/rxe_net.c
drivers/infiniband/sw/rxe/rxe_resp.c
drivers/infiniband/sw/rxe/rxe_verbs.c
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/iser/iser_initiator.c
drivers/infiniband/ulp/iser/iser_verbs.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/keyboard/gpio_keys.c
drivers/input/misc/xen-kbdfront.c
drivers/input/serio/i8042.c
drivers/irqchip/irq-digicolor.c
drivers/irqchip/irq-gic-realview.c
drivers/irqchip/irq-mips-cpu.c
drivers/irqchip/irq-mips-gic.c
drivers/isdn/divert/isdn_divert.c
drivers/isdn/hardware/avm/c4.c
drivers/isdn/hardware/eicon/divasmain.c
drivers/isdn/hardware/mISDN/avmfritz.c
drivers/isdn/hardware/mISDN/hfcmulti.c
drivers/isdn/hardware/mISDN/hfcpci.c
drivers/isdn/hardware/mISDN/netjet.c
drivers/isdn/hardware/mISDN/w6692.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/hfc4s8s_l1.c
drivers/isdn/hisax/hisax_fcpcipnp.c
drivers/lightnvm/pblk-rb.c
drivers/lightnvm/pblk-read.c
drivers/lightnvm/pblk.h
drivers/md/bitmap.c
drivers/md/dm-bufio.c
drivers/md/dm-integrity.c
drivers/md/dm-raid.c
drivers/md/dm-table.c
drivers/md/dm-verity-fec.c
drivers/md/dm-zoned-metadata.c
drivers/md/dm-zoned-reclaim.c
drivers/md/dm-zoned-target.c
drivers/md/md.c
drivers/md/md.h
drivers/md/raid1-10.c [new file with mode: 0644]
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5-ppl.c
drivers/md/raid5.c
drivers/mmc/core/block.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sunxi-mmc.c
drivers/mmc/host/tmio_mmc_core.c
drivers/mmc/host/wbsd.c
drivers/mtd/Kconfig
drivers/mtd/Makefile
drivers/mtd/bcm47xxpart.c
drivers/mtd/chips/cfi_cmdset_0020.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/Makefile
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/mchp23k256.c [new file with mode: 0644]
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/serial_flash_cmds.h
drivers/mtd/devices/st_spi_fsm.c
drivers/mtd/maps/physmap_of_gemini.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/atmel/nand-controller.c
drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h
drivers/mtd/nand/denali_dt.c
drivers/mtd/nand/denali_pci.c
drivers/mtd/nand/docg4.c
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/fsmc_nand.c
drivers/mtd/nand/gpmi-nand/gpmi-lib.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.h
drivers/mtd/nand/hisi504_nand.c
drivers/mtd/nand/jz4780_nand.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/mtk_ecc.c
drivers/mtd/nand/mtk_ecc.h
drivers/mtd/nand/mtk_nand.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_micron.c
drivers/mtd/nand/orion_nand.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/qcom_nandc.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sh_flctl.c
drivers/mtd/nand/sunxi_nand.c
drivers/mtd/nand/tango_nand.c
drivers/mtd/nand/vf610_nfc.c
drivers/mtd/parsers/Kconfig [new file with mode: 0644]
drivers/mtd/parsers/Makefile [new file with mode: 0644]
drivers/mtd/parsers/parser_trx.c [new file with mode: 0644]
drivers/mtd/spi-nor/Kconfig
drivers/mtd/spi-nor/aspeed-smc.c
drivers/mtd/spi-nor/atmel-quadspi.c
drivers/mtd/spi-nor/cadence-quadspi.c
drivers/mtd/spi-nor/fsl-quadspi.c
drivers/mtd/spi-nor/hisi-sfc.c
drivers/mtd/spi-nor/intel-spi.c
drivers/mtd/spi-nor/mtk-quadspi.c
drivers/mtd/spi-nor/nxp-spifi.c
drivers/mtd/spi-nor/spi-nor.c
drivers/mtd/spi-nor/stm32-quadspi.c
drivers/mtd/tests/subpagetest.c
drivers/mux/Kconfig
drivers/mux/mux-core.c
drivers/net/appletalk/ipddp.c
drivers/net/bonding/bond_main.c
drivers/net/dsa/b53/b53_common.c
drivers/net/dsa/lan9303-core.c
drivers/net/dsa/lan9303.h
drivers/net/dsa/lan9303_i2c.c
drivers/net/dsa/lan9303_mdio.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/apple/mace.c
drivers/net/ethernet/aurora/nb8800.c
drivers/net/ethernet/broadcom/Kconfig
drivers/net/ethernet/broadcom/bgmac-platform.c
drivers/net/ethernet/broadcom/bgmac.c
drivers/net/ethernet/broadcom/bgmac.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnxt/Makefile
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.h
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c [new file with mode: 0644]
drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h [new file with mode: 0644]
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/broadcom/genet/bcmgenet.h
drivers/net/ethernet/broadcom/genet/bcmmii.c
drivers/net/ethernet/cavium/liquidio/lio_ethtool.c
drivers/net/ethernet/cavium/liquidio/liquidio_common.h
drivers/net/ethernet/cavium/liquidio/octeon_console.c
drivers/net/ethernet/cavium/liquidio/octeon_device.h
drivers/net/ethernet/cavium/thunder/thunder_bgx.c
drivers/net/ethernet/cavium/thunder/thunder_bgx.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
drivers/net/ethernet/emulex/benet/be_roce.c
drivers/net/ethernet/faraday/ftgmac100.c
drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fec_mpc52xx.c
drivers/net/ethernet/freescale/fman/fman.c
drivers/net/ethernet/freescale/fman/fman_port.c
drivers/net/ethernet/freescale/fman/mac.c
drivers/net/ethernet/freescale/fsl_pq_mdio.c
drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/ibm/emac/core.c
drivers/net/ethernet/ibm/emac/debug.h
drivers/net/ethernet/ibm/emac/mal.c
drivers/net/ethernet/ibm/emac/rgmii.c
drivers/net/ethernet/ibm/emac/tah.c
drivers/net/ethernet/ibm/emac/zmii.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_nvm.c
drivers/net/ethernet/intel/i40e/i40e_ptp.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40evf/i40e_osdep.h
drivers/net/ethernet/intel/i40evf/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/i40evf.h
drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
drivers/net/ethernet/intel/i40evf/i40evf_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.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/ixgbe/ixgbe_x550.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/mediatek/Kconfig
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/mediatek/mtk_eth_soc.h
drivers/net/ethernet/mellanox/mlx4/alloc.c
drivers/net/ethernet/mellanox/mlx4/cq.c
drivers/net/ethernet/mellanox/mlx4/en_cq.c
drivers/net/ethernet/mellanox/mlx4/en_main.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/icm.c
drivers/net/ethernet/mellanox/mlx4/icm.h
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx4/mr.c
drivers/net/ethernet/mellanox/mlx4/qp.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/mellanox/mlx4/srq.c
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en_clock.c
drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/eq.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
drivers/net/ethernet/mellanox/mlx5/core/lag.c
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
drivers/net/ethernet/mellanox/mlx5/core/sriov.c
drivers/net/ethernet/mellanox/mlxsw/reg.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/moxa/moxart_ether.c
drivers/net/ethernet/moxa/moxart_ether.h
drivers/net/ethernet/netronome/nfp/nfp_main.c
drivers/net/ethernet/netronome/nfp/nfp_net_common.c
drivers/net/ethernet/netronome/nfp/nfp_net_main.c
drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
drivers/net/ethernet/netronome/nfp/nfp_port.c
drivers/net/ethernet/netronome/nfp/nfp_port.h
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
drivers/net/ethernet/qlogic/qed/qed_dev.c
drivers/net/ethernet/qlogic/qed/qed_dev_api.h
drivers/net/ethernet/qlogic/qed/qed_hsi.h
drivers/net/ethernet/qlogic/qed/qed_l2.c
drivers/net/ethernet/qlogic/qed/qed_l2.h
drivers/net/ethernet/qlogic/qed/qed_main.c
drivers/net/ethernet/qlogic/qed/qed_mcp.c
drivers/net/ethernet/qlogic/qed/qed_mcp.h
drivers/net/ethernet/qlogic/qed/qed_sriov.c
drivers/net/ethernet/qlogic/qed/qed_sriov.h
drivers/net/ethernet/qlogic/qed/qed_vf.c
drivers/net/ethernet/qlogic/qed/qed_vf.h
drivers/net/ethernet/qlogic/qede/qede.h
drivers/net/ethernet/qlogic/qede/qede_ethtool.c
drivers/net/ethernet/qlogic/qede/qede_filter.c
drivers/net/ethernet/qlogic/qede/qede_main.c
drivers/net/ethernet/qualcomm/emac/emac.c
drivers/net/ethernet/sgi/ioc3-eth.c
drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/sun/sunhme.h
drivers/net/ethernet/tehuti/tehuti.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/ethernet/toshiba/tc35815.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/geneve.c
drivers/net/hamradio/dmascc.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c
drivers/net/irda/mcs7780.c
drivers/net/ntb_netdev.c
drivers/net/phy/Kconfig
drivers/net/phy/marvell.c
drivers/net/phy/mdio-bcm-unimac.c
drivers/net/phy/mdio-mux-mmioreg.c
drivers/net/phy/mdio-mux.c
drivers/net/phy/phy.c
drivers/net/ppp/ppp_generic.c
drivers/net/ppp/pptp.c
drivers/net/team/team.c
drivers/net/tun.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/huawei_cdc_ncm.c
drivers/net/usb/smsc95xx.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/vxlan.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
drivers/net/wireless/intel/iwlwifi/dvm/tx.c
drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c
drivers/net/wireless/intel/iwlwifi/pcie/tx.c
drivers/net/wireless/ralink/rt2x00/rt2800lib.c
drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c
drivers/net/wireless/realtek/rtlwifi/wifi.h
drivers/ntb/hw/Kconfig
drivers/ntb/hw/Makefile
drivers/ntb/hw/amd/ntb_hw_amd.c
drivers/ntb/hw/amd/ntb_hw_amd.h
drivers/ntb/hw/idt/Kconfig [new file with mode: 0644]
drivers/ntb/hw/idt/Makefile [new file with mode: 0644]
drivers/ntb/hw/idt/ntb_hw_idt.c [new file with mode: 0644]
drivers/ntb/hw/idt/ntb_hw_idt.h [new file with mode: 0644]
drivers/ntb/hw/intel/ntb_hw_intel.c
drivers/ntb/hw/intel/ntb_hw_intel.h
drivers/ntb/ntb.c
drivers/ntb/ntb_transport.c
drivers/ntb/test/ntb_perf.c
drivers/ntb/test/ntb_pingpong.c
drivers/ntb/test/ntb_tool.c
drivers/nvdimm/core.c
drivers/nvme/host/core.c
drivers/nvme/host/fc.c
drivers/nvme/host/pci.c
drivers/nvme/target/admin-cmd.c
drivers/nvme/target/configfs.c
drivers/nvme/target/core.c
drivers/nvme/target/fc.c
drivers/nvme/target/nvmet.h
drivers/nvmem/rockchip-efuse.c
drivers/of/irq.c
drivers/of/of_mdio.c
drivers/parisc/pdc_stable.c
drivers/pci/host/pcie-rockchip.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/pme.c
drivers/perf/arm_pmu.c
drivers/perf/arm_pmu_platform.c
drivers/perf/qcom_l2_pmu.c
drivers/phy/broadcom/Kconfig
drivers/platform/mips/cpu_hwmon.c
drivers/platform/x86/alienware-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_telemetry_debugfs.c
drivers/platform/x86/panasonic-laptop.c
drivers/platform/x86/peaq-wmi.c
drivers/platform/x86/samsung-laptop.c
drivers/platform/x86/silead_dmi.c
drivers/platform/x86/toshiba_acpi.c
drivers/power/supply/twl4030_charger.c
drivers/pwm/core.c
drivers/pwm/pwm-bfin.c
drivers/pwm/pwm-cros-ec.c
drivers/pwm/pwm-hibvt.c
drivers/pwm/pwm-meson.c
drivers/pwm/pwm-sun4i.c
drivers/pwm/pwm-tegra.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/class.c
drivers/rtc/interface.c
drivers/rtc/nvmem.c [new file with mode: 0644]
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-brcmstb-waketimer.c [new file with mode: 0644]
drivers/rtc/rtc-core.h
drivers/rtc/rtc-dev.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds3232.c
drivers/rtc/rtc-ftrtc010.c [moved from drivers/rtc/rtc-gemini.c with 50% similarity]
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-nuc900.c
drivers/rtc/rtc-opal.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-rv8803.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-st-lpc.c
drivers/rtc/rtc-stm32.c
drivers/rtc/rtc-sysfs.c
drivers/s390/char/vmcp.c
drivers/s390/cio/chp.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/qeth_l3_main.c
drivers/scsi/cxlflash/main.c
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
drivers/scsi/hpsa.c
drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
drivers/scsi/ibmvscsi_tgt/libsrp.h
drivers/scsi/isci/request.c
drivers/scsi/libfc/fc_disc.c
drivers/scsi/qedf/qedf_main.c
drivers/scsi/qedi/qedi.h
drivers/scsi/qedi/qedi_fw.c
drivers/scsi/qedi/qedi_main.c
drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h [new file with mode: 0644]
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/sg.c
drivers/scsi/smartpqi/smartpqi.h
drivers/scsi/virtio_scsi.c
drivers/spmi/spmi-pmic-arb.c
drivers/spmi/spmi.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/comedi/drivers/ni_mio_common.c
drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
drivers/staging/mt29f_spinand/mt29f_spinand.c
drivers/staging/rtl8188eu/core/rtw_cmd.c
drivers/staging/rtl8188eu/os_dep/usb_intf.c
drivers/staging/sm750fb/ddk750_chip.c
drivers/staging/sm750fb/sm750.c
drivers/staging/speakup/main.c
drivers/staging/speakup/spk_priv.h
drivers/staging/speakup/spk_ttyio.c
drivers/staging/vboxvideo/Kconfig [new file with mode: 0644]
drivers/staging/vboxvideo/Makefile [new file with mode: 0644]
drivers/staging/vboxvideo/TODO [new file with mode: 0644]
drivers/staging/vboxvideo/hgsmi_base.c [new file with mode: 0644]
drivers/staging/vboxvideo/hgsmi_ch_setup.h [new file with mode: 0644]
drivers/staging/vboxvideo/hgsmi_channels.h [new file with mode: 0644]
drivers/staging/vboxvideo/hgsmi_defs.h [new file with mode: 0644]
drivers/staging/vboxvideo/modesetting.c [new file with mode: 0644]
drivers/staging/vboxvideo/vbox_drv.c [new file with mode: 0644]
drivers/staging/vboxvideo/vbox_drv.h [new file with mode: 0644]
drivers/staging/vboxvideo/vbox_err.h [new file with mode: 0644]
drivers/staging/vboxvideo/vbox_fb.c [new file with mode: 0644]
drivers/staging/vboxvideo/vbox_hgsmi.c [new file with mode: 0644]
drivers/staging/vboxvideo/vbox_irq.c [new file with mode: 0644]
drivers/staging/vboxvideo/vbox_main.c [new file with mode: 0644]
drivers/staging/vboxvideo/vbox_mode.c [new file with mode: 0644]
drivers/staging/vboxvideo/vbox_prime.c [new file with mode: 0644]
drivers/staging/vboxvideo/vbox_ttm.c [new file with mode: 0644]
drivers/staging/vboxvideo/vboxvideo.h [new file with mode: 0644]
drivers/staging/vboxvideo/vboxvideo_guest.h [new file with mode: 0644]
drivers/staging/vboxvideo/vboxvideo_vbe.h [new file with mode: 0644]
drivers/staging/vboxvideo/vbva_base.c [new file with mode: 0644]
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_auth.c
drivers/target/iscsi/iscsi_target_configfs.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_parameters.c
drivers/target/iscsi/iscsi_target_parameters.h
drivers/target/iscsi/iscsi_target_tpg.c
drivers/target/iscsi/iscsi_target_tpg.h
drivers/target/iscsi/iscsi_target_util.c
drivers/target/iscsi/iscsi_target_util.h
drivers/target/loopback/tcm_loop.c
drivers/target/loopback/tcm_loop.h
drivers/target/target_core_alua.c
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_fabric_configfs.c
drivers/target/target_core_fabric_lib.c
drivers/target/target_core_file.c
drivers/target/target_core_iblock.c
drivers/target/target_core_internal.h
drivers/target/target_core_pr.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_pscsi.h
drivers/target/target_core_rd.c
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_tmr.c
drivers/target/target_core_tpg.c
drivers/target/target_core_transport.c
drivers/target/target_core_user.c
drivers/target/target_core_xcopy.c
drivers/thermal/broadcom/bcm2835_thermal.c
drivers/thermal/cpu_cooling.c
drivers/thermal/fair_share.c
drivers/thermal/hisi_thermal.c
drivers/thermal/imx_thermal.c
drivers/thermal/int340x_thermal/acpi_thermal_rel.c
drivers/thermal/int340x_thermal/int3403_thermal.c
drivers/thermal/step_wise.c
drivers/thermal/ti-soc-thermal/ti-thermal-common.c
drivers/thermal/user_space.c
drivers/thunderbolt/switch.c
drivers/thunderbolt/tb.h
drivers/thunderbolt/tb_msgs.h
drivers/tty/pty.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/imx.c
drivers/tty/serial/ioc3_serial.c
drivers/tty/serial/ioc4_serial.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/st-asc.c
drivers/usb/class/cdc-acm.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc3/core.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/function/f_mass_storage.c
drivers/usb/gadget/function/f_uac1.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/udc/Kconfig
drivers/usb/gadget/udc/renesas_usb3.c
drivers/usb/gadget/udc/snps_udc_plat.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/pci-quirks.h
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/serial/safe_serial.c
drivers/usb/storage/isd200.c
drivers/usb/typec/ucsi/ucsi.h
drivers/vfio/pci/vfio_pci.c
drivers/vfio/vfio.c
drivers/vhost/net.c
drivers/vhost/scsi.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/vhost/vsock.c
drivers/video/console/mdacon.c
drivers/video/fbdev/aty/atyfb_base.c
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/fsl-diu-fb.c
drivers/video/fbdev/intelfb/intelfbdrv.c
drivers/video/fbdev/matrox/matroxfb_base.c
drivers/video/fbdev/omap/lcdc.c
drivers/video/fbdev/omap/omapfb_main.c
drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c
drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c
drivers/video/fbdev/pxafb.c
drivers/video/fbdev/sh_mobile_lcdcfb.c
drivers/video/fbdev/uvesafb.c
drivers/video/fbdev/vermilion/cr_pll.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_ring.c
drivers/w1/masters/omap_hdq.c
drivers/w1/w1.c
drivers/xen/balloon.c
drivers/xen/events/events_base.c
drivers/xen/grant-table.c
drivers/xen/xen-balloon.c
drivers/xen/xen-scsiback.c
drivers/xen/xen-selfballoon.c
drivers/xen/xenfs/super.c
fs/9p/v9fs.c
fs/9p/v9fs.h
fs/9p/vfs_super.c
fs/Kconfig
fs/affs/super.c
fs/afs/misc.c
fs/afs/rxrpc.c
fs/afs/super.c
fs/befs/btree.c
fs/befs/linuxvfs.c
fs/bfs/inode.c
fs/binfmt_flat.c
fs/btrfs/compression.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/inode.c
fs/btrfs/raid56.c
fs/btrfs/send.c
fs/btrfs/super.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/ceph/dir.c
fs/cifs/cifsfs.c
fs/dcache.c
fs/debugfs/inode.c
fs/efivarfs/super.c
fs/eventpoll.c
fs/ext2/acl.c
fs/ext2/inode.c
fs/f2fs/acl.c
fs/f2fs/checkpoint.c
fs/f2fs/file.c
fs/f2fs/sysfs.c
fs/filesystems.c
fs/fs-writeback.c
fs/gfs2/dir.c
fs/hfsplus/posix_acl.c
fs/hugetlbfs/inode.c
fs/iomap.c
fs/isofs/inode.c
fs/isofs/isofs.h
fs/jfs/acl.c
fs/jfs/resize.c
fs/jfs/super.c
fs/lockd/clnt4xdr.c
fs/lockd/clntxdr.c
fs/lockd/mon.c
fs/lockd/svc.c
fs/lockd/svc4proc.c
fs/lockd/svcproc.c
fs/lockd/xdr.c
fs/lockd/xdr4.c
fs/mount.h
fs/namei.c
fs/namespace.c
fs/nfs/Makefile
fs/nfs/callback.c
fs/nfs/callback.h
fs/nfs/callback_proc.c
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/export.c [new file with mode: 0644]
fs/nfs/file.c
fs/nfs/filelayout/filelayout.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/mount_clnt.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs42proc.c
fs/nfs/nfs42xdr.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c
fs/nfs/nfs4idmap.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4trace.h
fs/nfs/nfs4xdr.c
fs/nfs/pagelist.c
fs/nfs/pnfs_nfs.c
fs/nfs/proc.c
fs/nfs/super.c
fs/nfs/unlink.c
fs/nfs/write.c
fs/nfsd/current_stateid.h
fs/nfsd/nfs2acl.c
fs/nfsd/nfs3acl.c
fs/nfsd/nfs3proc.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsd.h
fs/nfsd/nfsfh.h
fs/nfsd/nfsproc.c
fs/nfsd/nfssvc.c
fs/nfsd/nfsxdr.c
fs/nfsd/xdr.h
fs/nfsd/xdr3.h
fs/nfsd/xdr4.h
fs/nsfs.c
fs/omfs/inode.c
fs/orangefs/super.c
fs/overlayfs/dir.c
fs/overlayfs/inode.c
fs/overlayfs/namei.c
fs/overlayfs/overlayfs.h
fs/overlayfs/readdir.c
fs/overlayfs/super.c
fs/overlayfs/util.c
fs/pipe.c
fs/proc/base.c
fs/proc/internal.h
fs/proc/proc_sysctl.c
fs/pstore/inode.c
fs/pstore/internal.h
fs/pstore/platform.c
fs/ramfs/inode.c
fs/reiserfs/bitmap.c
fs/reiserfs/super.c
fs/reiserfs/xattr_acl.c
fs/super.c
fs/tracefs/inode.c
fs/ubifs/crypto.c
fs/ubifs/dir.c
fs/ubifs/file.c
fs/ubifs/journal.c
fs/ubifs/key.h
fs/ubifs/super.c
fs/ubifs/tnc.c
fs/ubifs/tnc_commit.c
fs/ubifs/ubifs.h
fs/ubifs/xattr.c
fs/udf/file.c
fs/udf/inode.c
fs/udf/super.c
fs/udf/udftime.c
fs/xfs/kmem.h
fs/xfs/libxfs/xfs_attr.c
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_dir2_data.c
fs/xfs/libxfs/xfs_quota_defs.h
fs/xfs/libxfs/xfs_refcount.c
fs/xfs/xfs_attr_list.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_qm.c
fs/xfs/xfs_reflink.c
fs/xfs/xfs_symlink.c
include/acpi/acpi_numa.h
include/asm-generic/uaccess-unaligned.h [deleted file]
include/drm/bridge/dw_hdmi.h
include/dt-bindings/clock/boston-clock.h [new file with mode: 0644]
include/linux/backing-dev.h
include/linux/binfmts.h
include/linux/bpf-cgroup.h
include/linux/bpf_verifier.h
include/linux/cdev.h
include/linux/ceph/ceph_features.h
include/linux/clk.h
include/linux/compiler-gcc.h
include/linux/compiler.h
include/linux/cpu_cooling.h
include/linux/cpufreq.h
include/linux/crash_core.h
include/linux/cred.h
include/linux/dax.h
include/linux/dcache.h
include/linux/dma-fence.h
include/linux/dma-mapping.h
include/linux/ethtool.h
include/linux/eventpoll.h
include/linux/flat.h
include/linux/fs.h
include/linux/fs_struct.h
include/linux/ftrace.h
include/linux/fwnode.h
include/linux/gfp.h
include/linux/hugetlb.h
include/linux/ipc.h
include/linux/ipc_namespace.h
include/linux/ipv6.h
include/linux/irq.h
include/linux/jhash.h
include/linux/kernel.h
include/linux/kexec.h
include/linux/key-type.h
include/linux/kmod.h
include/linux/kobject.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/llist.h
include/linux/lockd/lockd.h
include/linux/lockd/xdr.h
include/linux/lockd/xdr4.h
include/linux/lsm_hooks.h
include/linux/migrate.h
include/linux/mlx4/device.h
include/linux/mlx5/mlx5_ifc.h
include/linux/mm_types.h
include/linux/module.h
include/linux/mount.h
include/linux/msg.h
include/linux/mtd/nand.h
include/linux/mtd/partitions.h
include/linux/mtd/spi-nor.h
include/linux/net.h
include/linux/netdev_features.h
include/linux/netdevice.h
include/linux/netfilter.h
include/linux/nfs4.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/nfs_page.h
include/linux/nfs_xdr.h
include/linux/nmi.h
include/linux/ntb.h
include/linux/nvme-fc.h
include/linux/nvme.h
include/linux/nvmem-provider.h
include/linux/once.h
include/linux/path.h
include/linux/perf/arm_pmu.h
include/linux/phy.h
include/linux/pid_namespace.h
include/linux/platform_data/hsmmc-omap.h
include/linux/platform_data/mdio-bcm-unimac.h [new file with mode: 0644]
include/linux/platform_data/usb-ohci-s3c2410.h
include/linux/proc_ns.h
include/linux/qed/qed_eth_if.h
include/linux/qed/qed_if.h
include/linux/random.h
include/linux/rtc.h
include/linux/sched.h
include/linux/sched/signal.h
include/linux/sctp.h
include/linux/sem.h
include/linux/shm.h
include/linux/skbuff.h
include/linux/slab.h
include/linux/string.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/svc_rdma.h
include/linux/sunrpc/xdr.h
include/linux/sysctl.h
include/linux/tcp.h
include/linux/trace_events.h
include/linux/tty.h
include/linux/tty_driver.h
include/linux/usb/audio-v2.h
include/linux/usb/cdc_ncm.h
include/linux/user_namespace.h
include/linux/utsname.h
include/linux/uuid.h
include/linux/vfio.h
include/linux/wait.h
include/linux/workqueue.h
include/net/9p/client.h
include/net/9p/transport.h
include/net/af_unix.h
include/net/neighbour.h
include/net/net_namespace.h
include/net/netlink.h
include/net/sctp/command.h
include/net/sctp/sctp.h
include/net/sock.h
include/net/strparser.h
include/net/tcp.h
include/net/udp.h
include/net/udp_tunnel.h
include/rdma/ib_addr.h
include/rdma/ib_verbs.h
include/rdma/rdma_vt.h
include/rdma/rdmavt_qp.h
include/scsi/scsi_proto.h
include/target/iscsi/iscsi_target_core.h
include/target/target_core_backend.h
include/target/target_core_base.h
include/target/target_core_fabric.h
include/trace/events/mmflags.h
include/uapi/asm-generic/ioctls.h
include/uapi/linux/ethtool.h
include/uapi/linux/kcmp.h
include/uapi/linux/kvm.h
include/uapi/linux/netlink.h
include/uapi/linux/rtnetlink.h
include/uapi/linux/rxrpc.h [moved from include/linux/rxrpc.h with 54% similarity]
include/uapi/linux/sem.h
include/uapi/linux/snmp.h
include/uapi/linux/target_core_user.h
include/uapi/linux/tcp.h
include/uapi/linux/usb/audio.h
include/xen/balloon.h
init/main.c
ipc/msg.c
ipc/sem.c
ipc/shm.c
ipc/util.c
ipc/util.h
kernel/Makefile
kernel/audit.c
kernel/bpf/devmap.c
kernel/bpf/inode.c
kernel/bpf/syscall.c
kernel/bpf/verifier.c
kernel/cgroup/cgroup-internal.h
kernel/cgroup/cgroup.c
kernel/cpu.c
kernel/crash_core.c
kernel/events/core.c
kernel/fork.c
kernel/futex.c
kernel/irq/chip.c
kernel/irq/cpuhotplug.c
kernel/irq/internals.h
kernel/irq/manage.c
kernel/irq/pm.c
kernel/kcmp.c
kernel/kexec.c
kernel/kexec_core.c
kernel/kexec_file.c
kernel/kexec_internal.h
kernel/kmod.c
kernel/ksysfs.c
kernel/locking/rtmutex.c
kernel/sched/core.c
kernel/sched/cpufreq_schedutil.c
kernel/sched/cputime.c
kernel/sched/deadline.c
kernel/sysctl.c
kernel/sysctl_binary.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_kprobe.c
kernel/trace/trace_stack.c
kernel/watchdog.c
kernel/watchdog_hld.c
kernel/workqueue.c
lib/Kconfig.debug
lib/Makefile
lib/atomic64_test.c
lib/fault-inject.c
lib/nlattr.c
lib/percpu_counter.c
lib/rhashtable.c
lib/string.c
lib/test_kmod.c [new file with mode: 0644]
lib/test_rhashtable.c
lib/test_sysctl.c [new file with mode: 0644]
lib/test_uuid.c
mm/hugetlb.c
mm/internal.h
mm/memory.c
mm/mempolicy.c
mm/mmap.c
mm/page-writeback.c
mm/page_alloc.c
mm/sparse-vmemmap.c
mm/util.c
mm/vmalloc.c
mm/vmscan.c
net/9p/client.c
net/9p/trans_fd.c
net/9p/trans_rdma.c
net/bluetooth/6lowpan.c
net/bridge/br_device.c
net/bridge/br_input.c
net/ceph/ceph_common.c
net/ceph/messenger.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/compat.c
net/core/dev.c
net/core/dev_ioctl.c
net/core/ethtool.c
net/core/fib_rules.c
net/core/filter.c
net/core/neighbour.c
net/core/netpoll.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/dccp/feat.c
net/dccp/input.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/dsa/dsa2.c
net/ipv4/af_inet.c
net/ipv4/fib_frontend.c
net/ipv4/fib_semantics.c
net/ipv4/ip_output.c
net/ipv4/netfilter/nf_tables_arp.c
net/ipv4/proc.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_bbr.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/tcp_probe.c
net/ipv4/tcp_timer.c
net/ipv4/tcp_westwood.c
net/ipv4/udp.c
net/ipv4/udp_tunnel.c
net/ipv6/af_inet6.c
net/ipv6/exthdrs.c
net/ipv6/ip6_output.c
net/ipv6/output_core.c
net/ipv6/syncookies.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/kcm/kcmproc.c
net/kcm/kcmsock.c
net/netfilter/core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_nat_core.c
net/netfilter/nfnetlink.c
net/netfilter/x_tables.c
net/netfilter/xt_recent.c
net/openvswitch/conntrack.c
net/packet/af_packet.c
net/rds/send.c
net/rxrpc/ar-internal.h
net/rxrpc/protocol.h [moved from include/rxrpc/packet.h with 78% similarity]
net/sched/act_api.c
net/sched/sch_fq.c
net/sctp/chunk.c
net/sctp/outqueue.c
net/sctp/sm_make_chunk.c
net/sctp/sm_statefuns.c
net/smc/Kconfig
net/smc/af_smc.c
net/smc/smc_clc.c
net/smc/smc_core.c
net/smc/smc_core.h
net/smc/smc_ib.c
net/smc/smc_ib.h
net/smc/smc_rx.c
net/smc/smc_tx.c
net/smc/smc_wr.c
net/smc/smc_wr.h
net/socket.c
net/strparser/strparser.c
net/sunrpc/auth_gss/gss_krb5_crypto.c
net/sunrpc/auth_gss/gss_rpc_upcall.c
net/sunrpc/auth_gss/gss_rpc_xdr.c
net/sunrpc/auth_gss/gss_rpc_xdr.h
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/clnt.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/stats.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/Makefile
net/sunrpc/xprtrdma/fmr_ops.c
net/sunrpc/xprtrdma/frwr_ops.c
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/svc_rdma_marshal.c [deleted file]
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
net/sunrpc/xprtrdma/svc_rdma_rw.c
net/sunrpc/xprtrdma/svc_rdma_sendto.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtrdma/xprt_rdma.h
net/sunrpc/xprtsock.c
samples/bpf/tcbpf2_kern.c
samples/bpf/test_tunnel_bpf.sh
samples/kfifo/dma-example.c
scripts/Makefile.headersinst
scripts/checkpatch.pl
scripts/dtc/dtx_diff
scripts/gdb/linux/constants.py.in
scripts/gdb/linux/dmesg.py
scripts/gdb/linux/proc.py
scripts/parse-maintainers.pl [new file with mode: 0644]
security/Kconfig
security/keys/compat_dh.c
security/keys/dh.c
security/keys/internal.h
sound/core/pcm_native.c
sound/drivers/opl4/opl4_lib.c
sound/isa/msnd/msnd_midi.c
sound/isa/msnd/msnd_pinnacle.c
sound/pci/fm801.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
tools/include/uapi/linux/bpf.h
tools/kvm/kvm_stat/kvm_stat
tools/lib/bpf/Makefile
tools/lib/bpf/bpf.c
tools/lib/bpf/bpf.h
tools/perf/builtin-kmem.c
tools/perf/ui/browser.c
tools/perf/util/evsel.c
tools/perf/util/machine.c
tools/testing/selftests/bpf/test_align.c
tools/testing/selftests/bpf/test_maps.c
tools/testing/selftests/bpf/test_progs.c
tools/testing/selftests/bpf/test_verifier.c
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_eventname.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_module.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc
tools/testing/selftests/kmod/Makefile [new file with mode: 0644]
tools/testing/selftests/kmod/config [new file with mode: 0644]
tools/testing/selftests/kmod/kmod.sh [new file with mode: 0644]
tools/testing/selftests/ntb/ntb_test.sh
tools/testing/selftests/sysctl/Makefile
tools/testing/selftests/sysctl/common_tests [deleted file]
tools/testing/selftests/sysctl/config [new file with mode: 0644]
tools/testing/selftests/sysctl/run_numerictests [deleted file]
tools/testing/selftests/sysctl/run_stringtests [deleted file]
tools/testing/selftests/sysctl/sysctl.sh [new file with mode: 0644]
tools/testing/selftests/timers/Makefile
tools/testing/selftests/timers/rtctest.c
tools/testing/selftests/timers/rtctest_setdate.c [new file with mode: 0644]
virt/kvm/eventfd.c
virt/kvm/irqchip.c
virt/kvm/kvm_main.c
virt/kvm/vfio.c

index 3b5c3bc..f34e592 100644 (file)
@@ -229,6 +229,6 @@ KernelVersion:      4.1
 Contact:       linux-mtd@lists.infradead.org
 Description:
                For a partition, the offset of that partition from the start
-               of the master device in bytes. This attribute is absent on
-               main devices, so it can be used to distinguish between
-               partitions and devices that aren't partitions.
+               of the parent (another partition or a flash device) in bytes.
+               This attribute is absent on flash devices, so it can be used
+               to distinguish them from partitions.
index 4ed3883..f0cc3f7 100644 (file)
@@ -1,22 +1,24 @@
-                    Dynamic DMA mapping Guide
-                    =========================
+=========================
+Dynamic DMA mapping Guide
+=========================
 
-                David S. Miller <davem@redhat.com>
-                Richard Henderson <rth@cygnus.com>
-                 Jakub Jelinek <jakub@redhat.com>
+:Author: David S. Miller <davem@redhat.com>
+:Author: Richard Henderson <rth@cygnus.com>
+:Author: Jakub Jelinek <jakub@redhat.com>
 
 This is a guide to device driver writers on how to use the DMA API
 with example pseudo-code.  For a concise description of the API, see
 DMA-API.txt.
 
-                       CPU and DMA addresses
+CPU and DMA addresses
+=====================
 
 There are several kinds of addresses involved in the DMA API, and it's
 important to understand the differences.
 
 The kernel normally uses virtual addresses.  Any address returned by
 kmalloc(), vmalloc(), and similar interfaces is a virtual address and can
-be stored in a "void *".
+be stored in a ``void *``.
 
 The virtual memory system (TLB, page tables, etc.) translates virtual
 addresses to CPU physical addresses, which are stored as "phys_addr_t" or
@@ -37,7 +39,7 @@ be restricted to a subset of that space.  For example, even if a system
 supports 64-bit addresses for main memory and PCI BARs, it may use an IOMMU
 so devices only need to use 32-bit DMA addresses.
 
-Here's a picture and some examples:
+Here's a picture and some examples::
 
                CPU                  CPU                  Bus
              Virtual              Physical             Address
@@ -98,15 +100,16 @@ microprocessor architecture. You should use the DMA API rather than the
 bus-specific DMA API, i.e., use the dma_map_*() interfaces rather than the
 pci_map_*() interfaces.
 
-First of all, you should make sure
+First of all, you should make sure::
 
-#include <linux/dma-mapping.h>
+       #include <linux/dma-mapping.h>
 
 is in your driver, which provides the definition of dma_addr_t.  This type
 can hold any valid DMA address for the platform and should be used
 everywhere you hold a DMA address returned from the DMA mapping functions.
 
-                        What memory is DMA'able?
+What memory is DMA'able?
+========================
 
 The first piece of information you must know is what kernel memory can
 be used with the DMA mapping facilities.  There has been an unwritten
@@ -143,7 +146,8 @@ What about block I/O and networking buffers?  The block I/O and
 networking subsystems make sure that the buffers they use are valid
 for you to DMA from/to.
 
-                       DMA addressing limitations
+DMA addressing limitations
+==========================
 
 Does your device have any DMA addressing limitations?  For example, is
 your device only capable of driving the low order 24-bits of address?
@@ -166,7 +170,7 @@ style to do this even if your device holds the default setting,
 because this shows that you did think about these issues wrt. your
 device.
 
-The query is performed via a call to dma_set_mask_and_coherent():
+The query is performed via a call to dma_set_mask_and_coherent()::
 
        int dma_set_mask_and_coherent(struct device *dev, u64 mask);
 
@@ -175,12 +179,12 @@ If you have some special requirements, then the following two separate
 queries can be used instead:
 
        The query for streaming mappings is performed via a call to
-       dma_set_mask():
+       dma_set_mask()::
 
                int dma_set_mask(struct device *dev, u64 mask);
 
        The query for consistent allocations is performed via a call
-       to dma_set_coherent_mask():
+       to dma_set_coherent_mask()::
 
                int dma_set_coherent_mask(struct device *dev, u64 mask);
 
@@ -209,7 +213,7 @@ of your driver reports that performance is bad or that the device is not
 even detected, you can ask them for the kernel messages to find out
 exactly why.
 
-The standard 32-bit addressing device would do something like this:
+The standard 32-bit addressing device would do something like this::
 
        if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
                dev_warn(dev, "mydev: No suitable DMA available\n");
@@ -225,7 +229,7 @@ than 64-bit addressing.  For example, Sparc64 PCI SAC addressing is
 more efficient than DAC addressing.
 
 Here is how you would handle a 64-bit capable device which can drive
-all 64-bits when accessing streaming DMA:
+all 64-bits when accessing streaming DMA::
 
        int using_dac;
 
@@ -239,7 +243,7 @@ all 64-bits when accessing streaming DMA:
        }
 
 If a card is capable of using 64-bit consistent allocations as well,
-the case would look like this:
+the case would look like this::
 
        int using_dac, consistent_using_dac;
 
@@ -260,7 +264,7 @@ uses consistent allocations, one would have to check the return value from
 dma_set_coherent_mask().
 
 Finally, if your device can only drive the low 24-bits of
-address you might do something like:
+address you might do something like::
 
        if (dma_set_mask(dev, DMA_BIT_MASK(24))) {
                dev_warn(dev, "mydev: 24-bit DMA addressing not available\n");
@@ -280,7 +284,7 @@ only provide the functionality which the machine can handle.  It
 is important that the last call to dma_set_mask() be for the
 most specific mask.
 
-Here is pseudo-code showing how this might be done:
+Here is pseudo-code showing how this might be done::
 
        #define PLAYBACK_ADDRESS_BITS   DMA_BIT_MASK(32)
        #define RECORD_ADDRESS_BITS     DMA_BIT_MASK(24)
@@ -308,7 +312,8 @@ A sound card was used as an example here because this genre of PCI
 devices seems to be littered with ISA chips given a PCI front end,
 and thus retaining the 16MB DMA addressing limitations of ISA.
 
-                       Types of DMA mappings
+Types of DMA mappings
+=====================
 
 There are two types of DMA mappings:
 
@@ -336,12 +341,14 @@ There are two types of DMA mappings:
   to memory is immediately visible to the device, and vice
   versa.  Consistent mappings guarantee this.
 
-  IMPORTANT: Consistent DMA memory does not preclude the usage of
-             proper memory barriers.  The CPU may reorder stores to
+  .. important::
+
+            Consistent DMA memory does not preclude the usage of
+            proper memory barriers.  The CPU may reorder stores to
             consistent memory just as it may normal memory.  Example:
             if it is important for the device to see the first word
             of a descriptor updated before the second, you must do
-            something like:
+            something like::
 
                desc->word0 = address;
                wmb();
@@ -377,16 +384,17 @@ Also, systems with caches that aren't DMA-coherent will work better
 when the underlying buffers don't share cache lines with other data.
 
 
-                Using Consistent DMA mappings.
+Using Consistent DMA mappings
+=============================
 
 To allocate and map large (PAGE_SIZE or so) consistent DMA regions,
-you should do:
+you should do::
 
        dma_addr_t dma_handle;
 
        cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, gfp);
 
-where device is a struct device *. This may be called in interrupt
+where device is a ``struct device *``. This may be called in interrupt
 context with the GFP_ATOMIC flag.
 
 Size is the length of the region you want to allocate, in bytes.
@@ -415,7 +423,7 @@ exists (for example) to guarantee that if you allocate a chunk
 which is smaller than or equal to 64 kilobytes, the extent of the
 buffer you receive will not cross a 64K boundary.
 
-To unmap and free such a DMA region, you call:
+To unmap and free such a DMA region, you call::
 
        dma_free_coherent(dev, size, cpu_addr, dma_handle);
 
@@ -430,7 +438,7 @@ a kmem_cache, but it uses dma_alloc_coherent(), not __get_free_pages().
 Also, it understands common hardware constraints for alignment,
 like queue heads needing to be aligned on N byte boundaries.
 
-Create a dma_pool like this:
+Create a dma_pool like this::
 
        struct dma_pool *pool;
 
@@ -444,7 +452,7 @@ pass 0 for boundary; passing 4096 says memory allocated from this pool
 must not cross 4KByte boundaries (but at that time it may be better to
 use dma_alloc_coherent() directly instead).
 
-Allocate memory from a DMA pool like this:
+Allocate memory from a DMA pool like this::
 
        cpu_addr = dma_pool_alloc(pool, flags, &dma_handle);
 
@@ -452,7 +460,7 @@ flags are GFP_KERNEL if blocking is permitted (not in_interrupt nor
 holding SMP locks), GFP_ATOMIC otherwise.  Like dma_alloc_coherent(),
 this returns two values, cpu_addr and dma_handle.
 
-Free memory that was allocated from a dma_pool like this:
+Free memory that was allocated from a dma_pool like this::
 
        dma_pool_free(pool, cpu_addr, dma_handle);
 
@@ -460,7 +468,7 @@ where pool is what you passed to dma_pool_alloc(), and cpu_addr and
 dma_handle are the values dma_pool_alloc() returned. This function
 may be called in interrupt context.
 
-Destroy a dma_pool by calling:
+Destroy a dma_pool by calling::
 
        dma_pool_destroy(pool);
 
@@ -468,11 +476,12 @@ Make sure you've called dma_pool_free() for all memory allocated
 from a pool before you destroy the pool. This function may not
 be called in interrupt context.
 
-                       DMA Direction
+DMA Direction
+=============
 
 The interfaces described in subsequent portions of this document
 take a DMA direction argument, which is an integer and takes on
-one of the following values:
+one of the following values::
 
  DMA_BIDIRECTIONAL
  DMA_TO_DEVICE
@@ -521,14 +530,15 @@ packets, map/unmap them with the DMA_TO_DEVICE direction
 specifier.  For receive packets, just the opposite, map/unmap them
 with the DMA_FROM_DEVICE direction specifier.
 
-                 Using Streaming DMA mappings
+Using Streaming DMA mappings
+============================
 
 The streaming DMA mapping routines can be called from interrupt
 context.  There are two versions of each map/unmap, one which will
 map/unmap a single memory region, and one which will map/unmap a
 scatterlist.
 
-To map a single region, you do:
+To map a single region, you do::
 
        struct device *dev = &my_dev->dev;
        dma_addr_t dma_handle;
@@ -545,7 +555,7 @@ To map a single region, you do:
                goto map_error_handling;
        }
 
-and to unmap it:
+and to unmap it::
 
        dma_unmap_single(dev, dma_handle, size, direction);
 
@@ -563,7 +573,7 @@ Using CPU pointers like this for single mappings has a disadvantage:
 you cannot reference HIGHMEM memory in this way.  Thus, there is a
 map/unmap interface pair akin to dma_{map,unmap}_single().  These
 interfaces deal with page/offset pairs instead of CPU pointers.
-Specifically:
+Specifically::
 
        struct device *dev = &my_dev->dev;
        dma_addr_t dma_handle;
@@ -593,7 +603,7 @@ error as outlined under the dma_map_single() discussion.
 You should call dma_unmap_page() when the DMA activity is finished, e.g.,
 from the interrupt which told you that the DMA transfer is done.
 
-With scatterlists, you map a region gathered from several regions by:
+With scatterlists, you map a region gathered from several regions by::
 
        int i, count = dma_map_sg(dev, sglist, nents, direction);
        struct scatterlist *sg;
@@ -617,16 +627,18 @@ Then you should loop count times (note: this can be less than nents times)
 and use sg_dma_address() and sg_dma_len() macros where you previously
 accessed sg->address and sg->length as shown above.
 
-To unmap a scatterlist, just call:
+To unmap a scatterlist, just call::
 
        dma_unmap_sg(dev, sglist, nents, direction);
 
 Again, make sure DMA activity has already finished.
 
-PLEASE NOTE:  The 'nents' argument to the dma_unmap_sg call must be
-              the _same_ one you passed into the dma_map_sg call,
-             it should _NOT_ be the 'count' value _returned_ from the
-              dma_map_sg call.
+.. note::
+
+       The 'nents' argument to the dma_unmap_sg call must be
+       the _same_ one you passed into the dma_map_sg call,
+       it should _NOT_ be the 'count' value _returned_ from the
+       dma_map_sg call.
 
 Every dma_map_{single,sg}() call should have its dma_unmap_{single,sg}()
 counterpart, because the DMA address space is a shared resource and
@@ -638,11 +650,11 @@ properly in order for the CPU and device to see the most up-to-date and
 correct copy of the DMA buffer.
 
 So, firstly, just map it with dma_map_{single,sg}(), and after each DMA
-transfer call either:
+transfer call either::
 
        dma_sync_single_for_cpu(dev, dma_handle, size, direction);
 
-or:
+or::
 
        dma_sync_sg_for_cpu(dev, sglist, nents, direction);
 
@@ -650,17 +662,19 @@ as appropriate.
 
 Then, if you wish to let the device get at the DMA area again,
 finish accessing the data with the CPU, and then before actually
-giving the buffer to the hardware call either:
+giving the buffer to the hardware call either::
 
        dma_sync_single_for_device(dev, dma_handle, size, direction);
 
-or:
+or::
 
        dma_sync_sg_for_device(dev, sglist, nents, direction);
 
 as appropriate.
 
-PLEASE NOTE:  The 'nents' argument to dma_sync_sg_for_cpu() and
+.. note::
+
+             The 'nents' argument to dma_sync_sg_for_cpu() and
              dma_sync_sg_for_device() must be the same passed to
              dma_map_sg(). It is _NOT_ the count returned by
              dma_map_sg().
@@ -671,7 +685,7 @@ dma_map_*() call till dma_unmap_*(), then you don't have to call the
 dma_sync_*() routines at all.
 
 Here is pseudo code which shows a situation in which you would need
-to use the dma_sync_*() interfaces.
+to use the dma_sync_*() interfaces::
 
        my_card_setup_receive_buffer(struct my_card *cp, char *buffer, int len)
        {
@@ -747,7 +761,8 @@ is planned to completely remove virt_to_bus() and bus_to_virt() as
 they are entirely deprecated.  Some ports already do not provide these
 as it is impossible to correctly support them.
 
-                       Handling Errors
+Handling Errors
+===============
 
 DMA address space is limited on some architectures and an allocation
 failure can be determined by:
@@ -755,7 +770,7 @@ failure can be determined by:
 - checking if dma_alloc_coherent() returns NULL or dma_map_sg returns 0
 
 - checking the dma_addr_t returned from dma_map_single() and dma_map_page()
-  by using dma_mapping_error():
+  by using dma_mapping_error()::
 
        dma_addr_t dma_handle;
 
@@ -773,7 +788,8 @@ failure can be determined by:
   of a multiple page mapping attempt. These example are applicable to
   dma_map_page() as well.
 
-Example 1:
+Example 1::
+
        dma_addr_t dma_handle1;
        dma_addr_t dma_handle2;
 
@@ -802,8 +818,12 @@ Example 1:
                dma_unmap_single(dma_handle1);
        map_error_handling1:
 
-Example 2: (if buffers are allocated in a loop, unmap all mapped buffers when
-           mapping error is detected in the middle)
+Example 2::
+
+       /*
+        * if buffers are allocated in a loop, unmap all mapped buffers when
+        * mapping error is detected in the middle
+        */
 
        dma_addr_t dma_addr;
        dma_addr_t array[DMA_BUFFERS];
@@ -846,7 +866,8 @@ SCSI drivers must return SCSI_MLQUEUE_HOST_BUSY if the DMA mapping
 fails in the queuecommand hook. This means that the SCSI subsystem
 passes the command to the driver again later.
 
-               Optimizing Unmap State Space Consumption
+Optimizing Unmap State Space Consumption
+========================================
 
 On many platforms, dma_unmap_{single,page}() is simply a nop.
 Therefore, keeping track of the mapping address and length is a waste
@@ -858,7 +879,7 @@ Actually, instead of describing the macros one by one, we'll
 transform some example code.
 
 1) Use DEFINE_DMA_UNMAP_{ADDR,LEN} in state saving structures.
-   Example, before:
+   Example, before::
 
        struct ring_state {
                struct sk_buff *skb;
@@ -866,7 +887,7 @@ transform some example code.
                __u32 len;
        };
 
-   after:
+   after::
 
        struct ring_state {
                struct sk_buff *skb;
@@ -875,23 +896,23 @@ transform some example code.
        };
 
 2) Use dma_unmap_{addr,len}_set() to set these values.
-   Example, before:
+   Example, before::
 
        ringp->mapping = FOO;
        ringp->len = BAR;
 
-   after:
+   after::
 
        dma_unmap_addr_set(ringp, mapping, FOO);
        dma_unmap_len_set(ringp, len, BAR);
 
 3) Use dma_unmap_{addr,len}() to access these values.
-   Example, before:
+   Example, before::
 
        dma_unmap_single(dev, ringp->mapping, ringp->len,
                         DMA_FROM_DEVICE);
 
-   after:
+   after::
 
        dma_unmap_single(dev,
                         dma_unmap_addr(ringp, mapping),
@@ -902,7 +923,8 @@ It really should be self-explanatory.  We treat the ADDR and LEN
 separately, because it is possible for an implementation to only
 need the address in order to perform the unmap operation.
 
-                       Platform Issues
+Platform Issues
+===============
 
 If you are just writing drivers for Linux and do not maintain
 an architecture port for the kernel, you can safely skip down
@@ -928,12 +950,13 @@ to "Closing".
    alignment constraints (e.g. the alignment constraints about 64-bit
    objects).
 
-                          Closing
+Closing
+=======
 
 This document, and the API itself, would not be in its current
 form without the feedback and suggestions from numerous individuals.
 We would like to specifically mention, in no particular order, the
-following people:
+following people::
 
        Russell King <rmk@arm.linux.org.uk>
        Leo Dagum <dagum@barrel.engr.sgi.com>
index 71200df..45b2932 100644 (file)
@@ -1,7 +1,8 @@
-               Dynamic DMA mapping using the generic device
-               ============================================
+============================================
+Dynamic DMA mapping using the generic device
+============================================
 
-        James E.J. Bottomley <James.Bottomley@HansenPartnership.com>
+:Author: James E.J. Bottomley <James.Bottomley@HansenPartnership.com>
 
 This document describes the DMA API.  For a more gentle introduction
 of the API (and actual examples), see Documentation/DMA-API-HOWTO.txt.
@@ -12,10 +13,10 @@ machines.  Unless you know that your driver absolutely has to support
 non-consistent platforms (this is usually only legacy platforms) you
 should only use the API described in part I.
 
-Part I - dma_ API
--------------------------------------
+Part I - dma_API
+----------------
 
-To get the dma_ API, you must #include <linux/dma-mapping.h>.  This
+To get the dma_API, you must #include <linux/dma-mapping.h>.  This
 provides dma_addr_t and the interfaces described below.
 
 A dma_addr_t can hold any valid DMA address for the platform.  It can be
@@ -26,9 +27,11 @@ address space and the DMA address space.
 Part Ia - Using large DMA-coherent buffers
 ------------------------------------------
 
-void *
-dma_alloc_coherent(struct device *dev, size_t size,
-                            dma_addr_t *dma_handle, gfp_t flag)
+::
+
+       void *
+       dma_alloc_coherent(struct device *dev, size_t size,
+                          dma_addr_t *dma_handle, gfp_t flag)
 
 Consistent memory is memory for which a write by either the device or
 the processor can immediately be read by the processor or device
@@ -51,20 +54,24 @@ consolidate your requests for consistent memory as much as possible.
 The simplest way to do that is to use the dma_pool calls (see below).
 
 The flag parameter (dma_alloc_coherent() only) allows the caller to
-specify the GFP_ flags (see kmalloc()) for the allocation (the
+specify the ``GFP_`` flags (see kmalloc()) for the allocation (the
 implementation may choose to ignore flags that affect the location of
 the returned memory, like GFP_DMA).
 
-void *
-dma_zalloc_coherent(struct device *dev, size_t size,
-                            dma_addr_t *dma_handle, gfp_t flag)
+::
+
+       void *
+       dma_zalloc_coherent(struct device *dev, size_t size,
+                           dma_addr_t *dma_handle, gfp_t flag)
 
 Wraps dma_alloc_coherent() and also zeroes the returned memory if the
 allocation attempt succeeded.
 
-void
-dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-                          dma_addr_t dma_handle)
+::
+
+       void
+       dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+                         dma_addr_t dma_handle)
 
 Free a region of consistent memory you previously allocated.  dev,
 size and dma_handle must all be the same as those passed into
@@ -78,7 +85,7 @@ may only be called with IRQs enabled.
 Part Ib - Using small DMA-coherent buffers
 ------------------------------------------
 
-To get this part of the dma_ API, you must #include <linux/dmapool.h>
+To get this part of the dma_API, you must #include <linux/dmapool.h>
 
 Many drivers need lots of small DMA-coherent memory regions for DMA
 descriptors or I/O buffers.  Rather than allocating in units of a page
@@ -88,6 +95,8 @@ not __get_free_pages().  Also, they understand common hardware constraints
 for alignment, like queue heads needing to be aligned on N-byte boundaries.
 
 
+::
+
        struct dma_pool *
        dma_pool_create(const char *name, struct device *dev,
                        size_t size, size_t align, size_t alloc);
@@ -103,16 +112,21 @@ in bytes, and must be a power of two).  If your device has no boundary
 crossing restrictions, pass 0 for alloc; passing 4096 says memory allocated
 from this pool must not cross 4KByte boundaries.
 
+::
 
-       void *dma_pool_zalloc(struct dma_pool *pool, gfp_t mem_flags,
-                             dma_addr_t *handle)
+       void *
+       dma_pool_zalloc(struct dma_pool *pool, gfp_t mem_flags,
+                       dma_addr_t *handle)
 
 Wraps dma_pool_alloc() and also zeroes the returned memory if the
 allocation attempt succeeded.
 
 
-       void *dma_pool_alloc(struct dma_pool *pool, gfp_t gfp_flags,
-                       dma_addr_t *dma_handle);
+::
+
+       void *
+       dma_pool_alloc(struct dma_pool *pool, gfp_t gfp_flags,
+                      dma_addr_t *dma_handle);
 
 This allocates memory from the pool; the returned memory will meet the
 size and alignment requirements specified at creation time.  Pass
@@ -122,16 +136,20 @@ blocking.  Like dma_alloc_coherent(), this returns two values:  an
 address usable by the CPU, and the DMA address usable by the pool's
 device.
 
+::
 
-       void dma_pool_free(struct dma_pool *pool, void *vaddr,
-                       dma_addr_t addr);
+       void
+       dma_pool_free(struct dma_pool *pool, void *vaddr,
+                     dma_addr_t addr);
 
 This puts memory back into the pool.  The pool is what was passed to
 dma_pool_alloc(); the CPU (vaddr) and DMA addresses are what
 were returned when that routine allocated the memory being freed.
 
+::
 
-       void dma_pool_destroy(struct dma_pool *pool);
+       void
+       dma_pool_destroy(struct dma_pool *pool);
 
 dma_pool_destroy() frees the resources of the pool.  It must be
 called in a context which can sleep.  Make sure you've freed all allocated
@@ -141,32 +159,40 @@ memory back to the pool before you destroy it.
 Part Ic - DMA addressing limitations
 ------------------------------------
 
-int
-dma_set_mask_and_coherent(struct device *dev, u64 mask)
+::
+
+       int
+       dma_set_mask_and_coherent(struct device *dev, u64 mask)
 
 Checks to see if the mask is possible and updates the device
 streaming and coherent DMA mask parameters if it is.
 
 Returns: 0 if successful and a negative error if not.
 
-int
-dma_set_mask(struct device *dev, u64 mask)
+::
+
+       int
+       dma_set_mask(struct device *dev, u64 mask)
 
 Checks to see if the mask is possible and updates the device
 parameters if it is.
 
 Returns: 0 if successful and a negative error if not.
 
-int
-dma_set_coherent_mask(struct device *dev, u64 mask)
+::
+
+       int
+       dma_set_coherent_mask(struct device *dev, u64 mask)
 
 Checks to see if the mask is possible and updates the device
 parameters if it is.
 
 Returns: 0 if successful and a negative error if not.
 
-u64
-dma_get_required_mask(struct device *dev)
+::
+
+       u64
+       dma_get_required_mask(struct device *dev)
 
 This API returns the mask that the platform requires to
 operate efficiently.  Usually this means the returned mask
@@ -182,94 +208,107 @@ call to set the mask to the value returned.
 Part Id - Streaming DMA mappings
 --------------------------------
 
-dma_addr_t
-dma_map_single(struct device *dev, void *cpu_addr, size_t size,
-                     enum dma_data_direction direction)
+::
+
+       dma_addr_t
+       dma_map_single(struct device *dev, void *cpu_addr, size_t size,
+                      enum dma_data_direction direction)
 
 Maps a piece of processor virtual memory so it can be accessed by the
 device and returns the DMA address of the memory.
 
 The direction for both APIs may be converted freely by casting.
-However the dma_ API uses a strongly typed enumerator for its
+However the dma_API uses a strongly typed enumerator for its
 direction:
 
+======================= =============================================
 DMA_NONE               no direction (used for debugging)
 DMA_TO_DEVICE          data is going from the memory to the device
 DMA_FROM_DEVICE                data is coming from the device to the memory
 DMA_BIDIRECTIONAL      direction isn't known
+======================= =============================================
+
+.. note::
+
+       Not all memory regions in a machine can be mapped by this API.
+       Further, contiguous kernel virtual space may not be contiguous as
+       physical memory.  Since this API does not provide any scatter/gather
+       capability, it will fail if the user tries to map a non-physically
+       contiguous piece of memory.  For this reason, memory to be mapped by
+       this API should be obtained from sources which guarantee it to be
+       physically contiguous (like kmalloc).
+
+       Further, the DMA address of the memory must be within the
+       dma_mask of the device (the dma_mask is a bit mask of the
+       addressable region for the device, i.e., if the DMA address of
+       the memory ANDed with the dma_mask is still equal to the DMA
+       address, then the device can perform DMA to the memory).  To
+       ensure that the memory allocated by kmalloc is within the dma_mask,
+       the driver may specify various platform-dependent flags to restrict
+       the DMA address range of the allocation (e.g., on x86, GFP_DMA
+       guarantees to be within the first 16MB of available DMA addresses,
+       as required by ISA devices).
+
+       Note also that the above constraints on physical contiguity and
+       dma_mask may not apply if the platform has an IOMMU (a device which
+       maps an I/O DMA address to a physical memory address).  However, to be
+       portable, device driver writers may *not* assume that such an IOMMU
+       exists.
+
+.. warning::
+
+       Memory coherency operates at a granularity called the cache
+       line width.  In order for memory mapped by this API to operate
+       correctly, the mapped region must begin exactly on a cache line
+       boundary and end exactly on one (to prevent two separately mapped
+       regions from sharing a single cache line).  Since the cache line size
+       may not be known at compile time, the API will not enforce this
+       requirement.  Therefore, it is recommended that driver writers who
+       don't take special care to determine the cache line size at run time
+       only map virtual regions that begin and end on page boundaries (which
+       are guaranteed also to be cache line boundaries).
+
+       DMA_TO_DEVICE synchronisation must be done after the last modification
+       of the memory region by the software and before it is handed off to
+       the device.  Once this primitive is used, memory covered by this
+       primitive should be treated as read-only by the device.  If the device
+       may write to it at any point, it should be DMA_BIDIRECTIONAL (see
+       below).
+
+       DMA_FROM_DEVICE synchronisation must be done before the driver
+       accesses data that may be changed by the device.  This memory should
+       be treated as read-only by the driver.  If the driver needs to write
+       to it at any point, it should be DMA_BIDIRECTIONAL (see below).
+
+       DMA_BIDIRECTIONAL requires special handling: it means that the driver
+       isn't sure if the memory was modified before being handed off to the
+       device and also isn't sure if the device will also modify it.  Thus,
+       you must always sync bidirectional memory twice: once before the
+       memory is handed off to the device (to make sure all memory changes
+       are flushed from the processor) and once before the data may be
+       accessed after being used by the device (to make sure any processor
+       cache lines are updated with data that the device may have changed).
+
+::
 
-Notes:  Not all memory regions in a machine can be mapped by this API.
-Further, contiguous kernel virtual space may not be contiguous as
-physical memory.  Since this API does not provide any scatter/gather
-capability, it will fail if the user tries to map a non-physically
-contiguous piece of memory.  For this reason, memory to be mapped by
-this API should be obtained from sources which guarantee it to be
-physically contiguous (like kmalloc).
-
-Further, the DMA address of the memory must be within the
-dma_mask of the device (the dma_mask is a bit mask of the
-addressable region for the device, i.e., if the DMA address of
-the memory ANDed with the dma_mask is still equal to the DMA
-address, then the device can perform DMA to the memory).  To
-ensure that the memory allocated by kmalloc is within the dma_mask,
-the driver may specify various platform-dependent flags to restrict
-the DMA address range of the allocation (e.g., on x86, GFP_DMA
-guarantees to be within the first 16MB of available DMA addresses,
-as required by ISA devices).
-
-Note also that the above constraints on physical contiguity and
-dma_mask may not apply if the platform has an IOMMU (a device which
-maps an I/O DMA address to a physical memory address).  However, to be
-portable, device driver writers may *not* assume that such an IOMMU
-exists.
-
-Warnings:  Memory coherency operates at a granularity called the cache
-line width.  In order for memory mapped by this API to operate
-correctly, the mapped region must begin exactly on a cache line
-boundary and end exactly on one (to prevent two separately mapped
-regions from sharing a single cache line).  Since the cache line size
-may not be known at compile time, the API will not enforce this
-requirement.  Therefore, it is recommended that driver writers who
-don't take special care to determine the cache line size at run time
-only map virtual regions that begin and end on page boundaries (which
-are guaranteed also to be cache line boundaries).
-
-DMA_TO_DEVICE synchronisation must be done after the last modification
-of the memory region by the software and before it is handed off to
-the device.  Once this primitive is used, memory covered by this
-primitive should be treated as read-only by the device.  If the device
-may write to it at any point, it should be DMA_BIDIRECTIONAL (see
-below).
-
-DMA_FROM_DEVICE synchronisation must be done before the driver
-accesses data that may be changed by the device.  This memory should
-be treated as read-only by the driver.  If the driver needs to write
-to it at any point, it should be DMA_BIDIRECTIONAL (see below).
-
-DMA_BIDIRECTIONAL requires special handling: it means that the driver
-isn't sure if the memory was modified before being handed off to the
-device and also isn't sure if the device will also modify it.  Thus,
-you must always sync bidirectional memory twice: once before the
-memory is handed off to the device (to make sure all memory changes
-are flushed from the processor) and once before the data may be
-accessed after being used by the device (to make sure any processor
-cache lines are updated with data that the device may have changed).
-
-void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-                enum dma_data_direction direction)
+       void
+       dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+                        enum dma_data_direction direction)
 
 Unmaps the region previously mapped.  All the parameters passed in
 must be identical to those passed in (and returned) by the mapping
 API.
 
-dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
-                   unsigned long offset, size_t size,
-                   enum dma_data_direction direction)
-void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-              enum dma_data_direction direction)
+::
+
+       dma_addr_t
+       dma_map_page(struct device *dev, struct page *page,
+                    unsigned long offset, size_t size,
+                    enum dma_data_direction direction)
+
+       void
+       dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+                      enum dma_data_direction direction)
 
 API for mapping and unmapping for pages.  All the notes and warnings
 for the other mapping APIs apply here.  Also, although the <offset>
@@ -277,20 +316,24 @@ and <size> parameters are provided to do partial page mapping, it is
 recommended that you never use these unless you really know what the
 cache width is.
 
-dma_addr_t
-dma_map_resource(struct device *dev, phys_addr_t phys_addr, size_t size,
-                enum dma_data_direction dir, unsigned long attrs)
+::
 
-void
-dma_unmap_resource(struct device *dev, dma_addr_t addr, size_t size,
-                  enum dma_data_direction dir, unsigned long attrs)
+       dma_addr_t
+       dma_map_resource(struct device *dev, phys_addr_t phys_addr, size_t size,
+                        enum dma_data_direction dir, unsigned long attrs)
+
+       void
+       dma_unmap_resource(struct device *dev, dma_addr_t addr, size_t size,
+                          enum dma_data_direction dir, unsigned long attrs)
 
 API for mapping and unmapping for MMIO resources. All the notes and
 warnings for the other mapping APIs apply here. The API should only be
 used to map device MMIO resources, mapping of RAM is not permitted.
 
-int
-dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+::
+
+       int
+       dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 
 In some circumstances dma_map_single(), dma_map_page() and dma_map_resource()
 will fail to create a mapping. A driver can check for these errors by testing
@@ -298,9 +341,11 @@ the returned DMA address with dma_mapping_error(). A non-zero return value
 means the mapping could not be created and the driver should take appropriate
 action (e.g. reduce current DMA mapping usage or delay and try again later).
 
+::
+
        int
        dma_map_sg(struct device *dev, struct scatterlist *sg,
-               int nents, enum dma_data_direction direction)
+                  int nents, enum dma_data_direction direction)
 
 Returns: the number of DMA address segments mapped (this may be shorter
 than <nents> passed in if some elements of the scatter/gather list are
@@ -316,7 +361,7 @@ critical that the driver do something, in the case of a block driver
 aborting the request or even oopsing is better than doing nothing and
 corrupting the filesystem.
 
-With scatterlists, you use the resulting mapping like this:
+With scatterlists, you use the resulting mapping like this::
 
        int i, count = dma_map_sg(dev, sglist, nents, direction);
        struct scatterlist *sg;
@@ -337,9 +382,11 @@ Then you should loop count times (note: this can be less than nents times)
 and use sg_dma_address() and sg_dma_len() macros where you previously
 accessed sg->address and sg->length as shown above.
 
+::
+
        void
        dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-               int nents, enum dma_data_direction direction)
+                    int nents, enum dma_data_direction direction)
 
 Unmap the previously mapped scatter/gather list.  All the parameters
 must be the same as those and passed in to the scatter/gather mapping
@@ -348,18 +395,27 @@ API.
 Note: <nents> must be the number you passed in, *not* the number of
 DMA address entries returned.
 
-void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-                       enum dma_data_direction direction)
-void
-dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
-                          enum dma_data_direction direction)
-void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
-                   enum dma_data_direction direction)
-void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
-                      enum dma_data_direction direction)
+::
+
+       void
+       dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                               size_t size,
+                               enum dma_data_direction direction)
+
+       void
+       dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+                                  size_t size,
+                                  enum dma_data_direction direction)
+
+       void
+       dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                           int nents,
+                           enum dma_data_direction direction)
+
+       void
+       dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+                              int nents,
+                              enum dma_data_direction direction)
 
 Synchronise a single contiguous or scatter/gather mapping for the CPU
 and device. With the sync_sg API, all the parameters must be the same
@@ -367,36 +423,41 @@ as those passed into the single mapping API. With the sync_single API,
 you can use dma_handle and size parameters that aren't identical to
 those passed into the single mapping API to do a partial sync.
 
-Notes:  You must do this:
 
-- Before reading values that have been written by DMA from the device
-  (use the DMA_FROM_DEVICE direction)
-- After writing values that will be written to the device using DMA
-  (use the DMA_TO_DEVICE) direction
-- before *and* after handing memory to the device if the memory is
-  DMA_BIDIRECTIONAL
+.. note::
+
+   You must do this:
+
+   - Before reading values that have been written by DMA from the device
+     (use the DMA_FROM_DEVICE direction)
+   - After writing values that will be written to the device using DMA
+     (use the DMA_TO_DEVICE) direction
+   - before *and* after handing memory to the device if the memory is
+     DMA_BIDIRECTIONAL
 
 See also dma_map_single().
 
-dma_addr_t
-dma_map_single_attrs(struct device *dev, void *cpu_addr, size_t size,
-                    enum dma_data_direction dir,
-                    unsigned long attrs)
+::
+
+       dma_addr_t
+       dma_map_single_attrs(struct device *dev, void *cpu_addr, size_t size,
+                            enum dma_data_direction dir,
+                            unsigned long attrs)
 
-void
-dma_unmap_single_attrs(struct device *dev, dma_addr_t dma_addr,
-                      size_t size, enum dma_data_direction dir,
-                      unsigned long attrs)
+       void
+       dma_unmap_single_attrs(struct device *dev, dma_addr_t dma_addr,
+                              size_t size, enum dma_data_direction dir,
+                              unsigned long attrs)
 
-int
-dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
-                int nents, enum dma_data_direction dir,
-                unsigned long attrs)
+       int
+       dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
+                        int nents, enum dma_data_direction dir,
+                        unsigned long attrs)
 
-void
-dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sgl,
-                  int nents, enum dma_data_direction dir,
-                  unsigned long attrs)
+       void
+       dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sgl,
+                          int nents, enum dma_data_direction dir,
+                          unsigned long attrs)
 
 The four functions above are just like the counterpart functions
 without the _attrs suffixes, except that they pass an optional
@@ -410,37 +471,38 @@ is identical to those of the corresponding function
 without the _attrs suffix. As a result dma_map_single_attrs()
 can generally replace dma_map_single(), etc.
 
-As an example of the use of the *_attrs functions, here's how
+As an example of the use of the ``*_attrs`` functions, here's how
 you could pass an attribute DMA_ATTR_FOO when mapping memory
-for DMA:
+for DMA::
 
-#include <linux/dma-mapping.h>
-/* DMA_ATTR_FOO should be defined in linux/dma-mapping.h and
- * documented in Documentation/DMA-attributes.txt */
-...
+       #include <linux/dma-mapping.h>
+       /* DMA_ATTR_FOO should be defined in linux/dma-mapping.h and
      * documented in Documentation/DMA-attributes.txt */
+       ...
 
-       unsigned long attr;
-       attr |= DMA_ATTR_FOO;
-       ....
-       n = dma_map_sg_attrs(dev, sg, nents, DMA_TO_DEVICE, attr);
-       ....
+               unsigned long attr;
+               attr |= DMA_ATTR_FOO;
+               ....
+               n = dma_map_sg_attrs(dev, sg, nents, DMA_TO_DEVICE, attr);
+               ....
 
 Architectures that care about DMA_ATTR_FOO would check for its
 presence in their implementations of the mapping and unmapping
-routines, e.g.:
-
-void whizco_dma_map_sg_attrs(struct device *dev, dma_addr_t dma_addr,
-                            size_t size, enum dma_data_direction dir,
-                            unsigned long attrs)
-{
-       ....
-       if (attrs & DMA_ATTR_FOO)
-               /* twizzle the frobnozzle */
-       ....
+routines, e.g.:::
+
+       void whizco_dma_map_sg_attrs(struct device *dev, dma_addr_t dma_addr,
+                                    size_t size, enum dma_data_direction dir,
+                                    unsigned long attrs)
+       {
+               ....
+               if (attrs & DMA_ATTR_FOO)
+                       /* twizzle the frobnozzle */
+               ....
+       }
 
 
-Part II - Advanced dma_ usage
------------------------------
+Part II - Advanced dma usage
+----------------------------
 
 Warning: These pieces of the DMA API should not be used in the
 majority of cases, since they cater for unlikely corner cases that
@@ -450,9 +512,11 @@ If you don't understand how cache line coherency works between a
 processor and an I/O device, you should not be using this part of the
 API at all.
 
-void *
-dma_alloc_noncoherent(struct device *dev, size_t size,
-                              dma_addr_t *dma_handle, gfp_t flag)
+::
+
+       void *
+       dma_alloc_noncoherent(struct device *dev, size_t size,
+                             dma_addr_t *dma_handle, gfp_t flag)
 
 Identical to dma_alloc_coherent() except that the platform will
 choose to return either consistent or non-consistent memory as it sees
@@ -468,39 +532,49 @@ only use this API if you positively know your driver will be
 required to work on one of the rare (usually non-PCI) architectures
 that simply cannot make consistent memory.
 
-void
-dma_free_noncoherent(struct device *dev, size_t size, void *cpu_addr,
-                             dma_addr_t dma_handle)
+::
+
+       void
+       dma_free_noncoherent(struct device *dev, size_t size, void *cpu_addr,
+                            dma_addr_t dma_handle)
 
 Free memory allocated by the nonconsistent API.  All parameters must
 be identical to those passed in (and returned by
 dma_alloc_noncoherent()).
 
-int
-dma_get_cache_alignment(void)
+::
+
+       int
+       dma_get_cache_alignment(void)
 
 Returns the processor cache alignment.  This is the absolute minimum
 alignment *and* width that you must observe when either mapping
 memory or doing partial flushes.
 
-Notes: This API may return a number *larger* than the actual cache
-line, but it will guarantee that one or more cache lines fit exactly
-into the width returned by this call.  It will also always be a power
-of two for easy alignment.
+.. note::
 
-void
-dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-              enum dma_data_direction direction)
+       This API may return a number *larger* than the actual cache
+       line, but it will guarantee that one or more cache lines fit exactly
+       into the width returned by this call.  It will also always be a power
+       of two for easy alignment.
+
+::
+
+       void
+       dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+                      enum dma_data_direction direction)
 
 Do a partial sync of memory that was allocated by
 dma_alloc_noncoherent(), starting at virtual address vaddr and
 continuing on for size.  Again, you *must* observe the cache line
 boundaries when doing this.
 
-int
-dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
-                           dma_addr_t device_addr, size_t size, int
-                           flags)
+::
+
+       int
+       dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
+                                   dma_addr_t device_addr, size_t size, int
+                                   flags)
 
 Declare region of memory to be handed out by dma_alloc_coherent() when
 it's asked for coherent memory for this device.
@@ -516,21 +590,21 @@ size is the size of the area (must be multiples of PAGE_SIZE).
 
 flags can be ORed together and are:
 
-DMA_MEMORY_MAP - request that the memory returned from
-dma_alloc_coherent() be directly writable.
+DMA_MEMORY_MAP - request that the memory returned from
+  dma_alloc_coherent() be directly writable.
 
-DMA_MEMORY_IO - request that the memory returned from
-dma_alloc_coherent() be addressable using read()/write()/memcpy_toio() etc.
+DMA_MEMORY_IO - request that the memory returned from
+  dma_alloc_coherent() be addressable using read()/write()/memcpy_toio() etc.
 
 One or both of these flags must be present.
 
-DMA_MEMORY_INCLUDES_CHILDREN - make the declared memory be allocated by
-dma_alloc_coherent of any child devices of this one (for memory residing
-on a bridge).
+DMA_MEMORY_INCLUDES_CHILDREN - make the declared memory be allocated by
+  dma_alloc_coherent of any child devices of this one (for memory residing
+  on a bridge).
 
-DMA_MEMORY_EXCLUSIVE - only allocate memory from the declared regions. 
-Do not allow dma_alloc_coherent() to fall back to system memory when
-it's out of memory in the declared region.
+- DMA_MEMORY_EXCLUSIVE - only allocate memory from the declared regions.
+  Do not allow dma_alloc_coherent() to fall back to system memory when
+  it's out of memory in the declared region.
 
 The return value will be either DMA_MEMORY_MAP or DMA_MEMORY_IO and
 must correspond to a passed in flag (i.e. no returning DMA_MEMORY_IO
@@ -543,15 +617,17 @@ must be accessed using the correct bus functions.  If your driver
 isn't prepared to handle this contingency, it should not specify
 DMA_MEMORY_IO in the input flags.
 
-As a simplification for the platforms, only *one* such region of
+As a simplification for the platforms, only **one** such region of
 memory may be declared per device.
 
 For reasons of efficiency, most platforms choose to track the declared
 region only at the granularity of a page.  For smaller allocations,
 you should use the dma_pool() API.
 
-void
-dma_release_declared_memory(struct device *dev)
+::
+
+       void
+       dma_release_declared_memory(struct device *dev)
 
 Remove the memory region previously declared from the system.  This
 API performs *no* in-use checking for this region and will return
@@ -559,9 +635,11 @@ unconditionally having removed all the required structures.  It is the
 driver's job to ensure that no parts of this memory region are
 currently in use.
 
-void *
-dma_mark_declared_memory_occupied(struct device *dev,
-                                 dma_addr_t device_addr, size_t size)
+::
+
+       void *
+       dma_mark_declared_memory_occupied(struct device *dev,
+                                         dma_addr_t device_addr, size_t size)
 
 This is used to occupy specific regions of the declared space
 (dma_alloc_coherent() will hand out the first free region it finds).
@@ -592,38 +670,37 @@ option has a performance impact. Do not enable it in production kernels.
 If you boot the resulting kernel will contain code which does some bookkeeping
 about what DMA memory was allocated for which device. If this code detects an
 error it prints a warning message with some details into your kernel log. An
-example warning message may look like this:
-
-------------[ cut here ]------------
-WARNING: at /data2/repos/linux-2.6-iommu/lib/dma-debug.c:448
-       check_unmap+0x203/0x490()
-Hardware name:
-forcedeth 0000:00:08.0: DMA-API: device driver frees DMA memory with wrong
-       function [device address=0x00000000640444be] [size=66 bytes] [mapped as
-single] [unmapped as page]
-Modules linked in: nfsd exportfs bridge stp llc r8169
-Pid: 0, comm: swapper Tainted: G        W  2.6.28-dmatest-09289-g8bb99c0 #1
-Call Trace:
- <IRQ>  [<ffffffff80240b22>] warn_slowpath+0xf2/0x130
- [<ffffffff80647b70>] _spin_unlock+0x10/0x30
- [<ffffffff80537e75>] usb_hcd_link_urb_to_ep+0x75/0xc0
- [<ffffffff80647c22>] _spin_unlock_irqrestore+0x12/0x40
- [<ffffffff8055347f>] ohci_urb_enqueue+0x19f/0x7c0
- [<ffffffff80252f96>] queue_work+0x56/0x60
- [<ffffffff80237e10>] enqueue_task_fair+0x20/0x50
- [<ffffffff80539279>] usb_hcd_submit_urb+0x379/0xbc0
- [<ffffffff803b78c3>] cpumask_next_and+0x23/0x40
- [<ffffffff80235177>] find_busiest_group+0x207/0x8a0
- [<ffffffff8064784f>] _spin_lock_irqsave+0x1f/0x50
- [<ffffffff803c7ea3>] check_unmap+0x203/0x490
- [<ffffffff803c8259>] debug_dma_unmap_page+0x49/0x50
- [<ffffffff80485f26>] nv_tx_done_optimized+0xc6/0x2c0
- [<ffffffff80486c13>] nv_nic_irq_optimized+0x73/0x2b0
- [<ffffffff8026df84>] handle_IRQ_event+0x34/0x70
- [<ffffffff8026ffe9>] handle_edge_irq+0xc9/0x150
- [<ffffffff8020e3ab>] do_IRQ+0xcb/0x1c0
- [<ffffffff8020c093>] ret_from_intr+0x0/0xa
- <EOI> <4>---[ end trace f6435a98e2a38c0e ]---
+example warning message may look like this::
+
+       WARNING: at /data2/repos/linux-2.6-iommu/lib/dma-debug.c:448
+               check_unmap+0x203/0x490()
+       Hardware name:
+       forcedeth 0000:00:08.0: DMA-API: device driver frees DMA memory with wrong
+               function [device address=0x00000000640444be] [size=66 bytes] [mapped as
+       single] [unmapped as page]
+       Modules linked in: nfsd exportfs bridge stp llc r8169
+       Pid: 0, comm: swapper Tainted: G        W  2.6.28-dmatest-09289-g8bb99c0 #1
+       Call Trace:
+       <IRQ>  [<ffffffff80240b22>] warn_slowpath+0xf2/0x130
+       [<ffffffff80647b70>] _spin_unlock+0x10/0x30
+       [<ffffffff80537e75>] usb_hcd_link_urb_to_ep+0x75/0xc0
+       [<ffffffff80647c22>] _spin_unlock_irqrestore+0x12/0x40
+       [<ffffffff8055347f>] ohci_urb_enqueue+0x19f/0x7c0
+       [<ffffffff80252f96>] queue_work+0x56/0x60
+       [<ffffffff80237e10>] enqueue_task_fair+0x20/0x50
+       [<ffffffff80539279>] usb_hcd_submit_urb+0x379/0xbc0
+       [<ffffffff803b78c3>] cpumask_next_and+0x23/0x40
+       [<ffffffff80235177>] find_busiest_group+0x207/0x8a0
+       [<ffffffff8064784f>] _spin_lock_irqsave+0x1f/0x50
+       [<ffffffff803c7ea3>] check_unmap+0x203/0x490
+       [<ffffffff803c8259>] debug_dma_unmap_page+0x49/0x50
+       [<ffffffff80485f26>] nv_tx_done_optimized+0xc6/0x2c0
+       [<ffffffff80486c13>] nv_nic_irq_optimized+0x73/0x2b0
+       [<ffffffff8026df84>] handle_IRQ_event+0x34/0x70
+       [<ffffffff8026ffe9>] handle_edge_irq+0xc9/0x150
+       [<ffffffff8020e3ab>] do_IRQ+0xcb/0x1c0
+       [<ffffffff8020c093>] ret_from_intr+0x0/0xa
+       <EOI> <4>---[ end trace f6435a98e2a38c0e ]---
 
 The driver developer can find the driver and the device including a stacktrace
 of the DMA-API call which caused this warning.
@@ -637,43 +714,42 @@ details.
 The debugfs directory for the DMA-API debugging code is called dma-api/. In
 this directory the following files can currently be found:
 
-       dma-api/all_errors      This file contains a numeric value. If this
+=============================== ===============================================
+dma-api/all_errors             This file contains a numeric value. If this
                                value is not equal to zero the debugging code
                                will print a warning for every error it finds
                                into the kernel log. Be careful with this
                                option, as it can easily flood your logs.
 
-       dma-api/disabled        This read-only file contains the character 'Y'
+dma-api/disabled               This read-only file contains the character 'Y'
                                if the debugging code is disabled. This can
                                happen when it runs out of memory or if it was
                                disabled at boot time
 
-       dma-api/error_count     This file is read-only and shows the total
+dma-api/error_count            This file is read-only and shows the total
                                numbers of errors found.
 
-       dma-api/num_errors      The number in this file shows how many
+dma-api/num_errors             The number in this file shows how many
                                warnings will be printed to the kernel log
                                before it stops. This number is initialized to
                                one at system boot and be set by writing into
                                this file
 
-       dma-api/min_free_entries
-                               This read-only file can be read to get the
+dma-api/min_free_entries       This read-only file can be read to get the
                                minimum number of free dma_debug_entries the
                                allocator has ever seen. If this value goes
                                down to zero the code will disable itself
                                because it is not longer reliable.
 
-       dma-api/num_free_entries
-                               The current number of free dma_debug_entries
+dma-api/num_free_entries       The current number of free dma_debug_entries
                                in the allocator.
 
-       dma-api/driver-filter
-                               You can write a name of a driver into this file
+dma-api/driver-filter          You can write a name of a driver into this file
                                to limit the debug output to requests from that
                                particular driver. Write an empty string to
                                that file to disable the filter and see
                                all errors again.
+=============================== ===============================================
 
 If you have this code compiled into your kernel it will be enabled by default.
 If you want to boot without the bookkeeping anyway you can provide
@@ -692,7 +768,10 @@ of preallocated entries is defined per architecture. If it is too low for you
 boot with 'dma_debug_entries=<your_desired_number>' to overwrite the
 architectural default.
 
-void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
+::
+
+       void
+       debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
 
 dma-debug interface debug_dma_mapping_error() to debug drivers that fail
 to check DMA mapping errors on addresses returned by dma_map_single() and
@@ -702,4 +781,3 @@ the driver. When driver does unmap, debug_dma_unmap() checks the flag and if
 this flag is still set, prints warning message that includes call trace that
 leads up to the unmap. This interface can be called from dma_mapping_error()
 routines to enable DMA mapping error check debugging.
-
index c413313..8c2b8be 100644 (file)
@@ -1,19 +1,20 @@
-                        DMA with ISA and LPC devices
-                        ============================
+============================
+DMA with ISA and LPC devices
+============================
 
-                      Pierre Ossman <drzeus@drzeus.cx>
+:Author: Pierre Ossman <drzeus@drzeus.cx>
 
 This document describes how to do DMA transfers using the old ISA DMA
 controller. Even though ISA is more or less dead today the LPC bus
 uses the same DMA system so it will be around for quite some time.
 
-Part I - Headers and dependencies
----------------------------------
+Headers and dependencies
+------------------------
 
-To do ISA style DMA you need to include two headers:
+To do ISA style DMA you need to include two headers::
 
-#include <linux/dma-mapping.h>
-#include <asm/dma.h>
+       #include <linux/dma-mapping.h>
+       #include <asm/dma.h>
 
 The first is the generic DMA API used to convert virtual addresses to
 bus addresses (see Documentation/DMA-API.txt for details).
@@ -23,8 +24,8 @@ this is not present on all platforms make sure you construct your
 Kconfig to be dependent on ISA_DMA_API (not ISA) so that nobody tries
 to build your driver on unsupported platforms.
 
-Part II - Buffer allocation
----------------------------
+Buffer allocation
+-----------------
 
 The ISA DMA controller has some very strict requirements on which
 memory it can access so extra care must be taken when allocating
@@ -42,13 +43,13 @@ requirements you pass the flag GFP_DMA to kmalloc.
 
 Unfortunately the memory available for ISA DMA is scarce so unless you
 allocate the memory during boot-up it's a good idea to also pass
-__GFP_REPEAT and __GFP_NOWARN to make the allocator try a bit harder.
+__GFP_RETRY_MAYFAIL and __GFP_NOWARN to make the allocator try a bit harder.
 
 (This scarcity also means that you should allocate the buffer as
 early as possible and not release it until the driver is unloaded.)
 
-Part III - Address translation
-------------------------------
+Address translation
+-------------------
 
 To translate the virtual address to a bus address, use the normal DMA
 API. Do _not_ use isa_virt_to_phys() even though it does the same
@@ -61,8 +62,8 @@ Note: x86_64 had a broken DMA API when it came to ISA but has since
 been fixed. If your arch has problems then fix the DMA API instead of
 reverting to the ISA functions.
 
-Part IV - Channels
-------------------
+Channels
+--------
 
 A normal ISA DMA controller has 8 channels. The lower four are for
 8-bit transfers and the upper four are for 16-bit transfers.
@@ -80,8 +81,8 @@ The ability to use 16-bit or 8-bit transfers is _not_ up to you as a
 driver author but depends on what the hardware supports. Check your
 specs or test different channels.
 
-Part V - Transfer data
-----------------------
+Transfer data
+-------------
 
 Now for the good stuff, the actual DMA transfer. :)
 
@@ -112,37 +113,37 @@ Once the DMA transfer is finished (or timed out) you should disable
 the channel again. You should also check get_dma_residue() to make
 sure that all data has been transferred.
 
-Example:
+Example::
 
-int flags, residue;
+       int flags, residue;
 
-flags = claim_dma_lock();
+       flags = claim_dma_lock();
 
-clear_dma_ff();
+       clear_dma_ff();
 
-set_dma_mode(channel, DMA_MODE_WRITE);
-set_dma_addr(channel, phys_addr);
-set_dma_count(channel, num_bytes);
+       set_dma_mode(channel, DMA_MODE_WRITE);
+       set_dma_addr(channel, phys_addr);
+       set_dma_count(channel, num_bytes);
 
-dma_enable(channel);
+       dma_enable(channel);
 
-release_dma_lock(flags);
+       release_dma_lock(flags);
 
-while (!device_done());
+       while (!device_done());
 
-flags = claim_dma_lock();
+       flags = claim_dma_lock();
 
-dma_disable(channel);
+       dma_disable(channel);
 
-residue = dma_get_residue(channel);
-if (residue != 0)
-       printk(KERN_ERR "driver: Incomplete DMA transfer!"
-               " %d bytes left!\n", residue);
+       residue = dma_get_residue(channel);
+       if (residue != 0)
+               printk(KERN_ERR "driver: Incomplete DMA transfer!"
+                       " %d bytes left!\n", residue);
 
-release_dma_lock(flags);
+       release_dma_lock(flags);
 
-Part VI - Suspend/resume
-------------------------
+Suspend/resume
+--------------
 
 It is the driver's responsibility to make sure that the machine isn't
 suspended while a DMA transfer is in progress. Also, all DMA settings
index 44c6bc4..8f8d97f 100644 (file)
@@ -1,5 +1,6 @@
-                       DMA attributes
-                       ==============
+==============
+DMA attributes
+==============
 
 This document describes the semantics of the DMA attributes that are
 defined in linux/dma-mapping.h.
@@ -108,6 +109,7 @@ This is a hint to the DMA-mapping subsystem that it's probably not worth
 the time to try to allocate memory to in a way that gives better TLB
 efficiency (AKA it's not worth trying to build the mapping out of larger
 pages).  You might want to specify this if:
+
 - You know that the accesses to this memory won't thrash the TLB.
   You might know that the accesses are likely to be sequential or
   that they aren't sequential but it's unlikely you'll ping-pong
@@ -121,11 +123,12 @@ pages).  You might want to specify this if:
   the mapping to have a short lifetime then it may be worth it to
   optimize allocation (avoid coming up with large pages) instead of
   getting the slight performance win of larger pages.
+
 Setting this hint doesn't guarantee that you won't get huge pages, but it
 means that we won't try quite as hard to get them.
 
-NOTE: At the moment DMA_ATTR_ALLOC_SINGLE_PAGES is only implemented on ARM,
-though ARM64 patches will likely be posted soon.
+.. note:: At the moment DMA_ATTR_ALLOC_SINGLE_PAGES is only implemented on ARM,
+         though ARM64 patches will likely be posted soon.
 
 DMA_ATTR_NO_WARN
 ----------------
@@ -142,10 +145,10 @@ problem at all, depending on the implementation of the retry mechanism.
 So, this provides a way for drivers to avoid those error messages on calls
 where allocation failures are not a problem, and shouldn't bother the logs.
 
-NOTE: At the moment DMA_ATTR_NO_WARN is only implemented on PowerPC.
+.. note:: At the moment DMA_ATTR_NO_WARN is only implemented on PowerPC.
 
 DMA_ATTR_PRIVILEGED
-------------------------------
+-------------------
 
 Some advanced peripherals such as remote processors and GPUs perform
 accesses to DMA buffers in both privileged "supervisor" and unprivileged
index 6962cab..aa77a25 100644 (file)
@@ -1,9 +1,8 @@
+=====================
+The Linux IPMI Driver
+=====================
 
-                          The Linux IPMI Driver
-                         ---------------------
-                             Corey Minyard
-                         <minyard@mvista.com>
-                           <minyard@acm.org>
+:Author: Corey Minyard <minyard@mvista.com> / <minyard@acm.org>
 
 The Intelligent Platform Management Interface, or IPMI, is a
 standard for controlling intelligent devices that monitor a system.
@@ -141,7 +140,7 @@ Addressing
 ----------
 
 The IPMI addressing works much like IP addresses, you have an overlay
-to handle the different address types.  The overlay is:
+to handle the different address types.  The overlay is::
 
   struct ipmi_addr
   {
@@ -153,7 +152,7 @@ to handle the different address types.  The overlay is:
 The addr_type determines what the address really is.  The driver
 currently understands two different types of addresses.
 
-"System Interface" addresses are defined as:
+"System Interface" addresses are defined as::
 
   struct ipmi_system_interface_addr
   {
@@ -166,7 +165,7 @@ straight to the BMC on the current card.  The channel must be
 IPMI_BMC_CHANNEL.
 
 Messages that are destined to go out on the IPMB bus use the
-IPMI_IPMB_ADDR_TYPE address type.  The format is
+IPMI_IPMB_ADDR_TYPE address type.  The format is::
 
   struct ipmi_ipmb_addr
   {
@@ -184,16 +183,16 @@ spec.
 Messages
 --------
 
-Messages are defined as:
+Messages are defined as::
 
-struct ipmi_msg
-{
+  struct ipmi_msg
+  {
        unsigned char netfn;
        unsigned char lun;
        unsigned char cmd;
        unsigned char *data;
        int           data_len;
-};
+  };
 
 The driver takes care of adding/stripping the header information.  The
 data portion is just the data to be send (do NOT put addressing info
@@ -208,7 +207,7 @@ block of data, even when receiving messages.  Otherwise the driver
 will have no place to put the message.
 
 Messages coming up from the message handler in kernelland will come in
-as:
+as::
 
   struct ipmi_recv_msg
   {
@@ -246,6 +245,7 @@ and the user should not have to care what type of SMI is below them.
 
 
 Watching For Interfaces
+^^^^^^^^^^^^^^^^^^^^^^^
 
 When your code comes up, the IPMI driver may or may not have detected
 if IPMI devices exist.  So you might have to defer your setup until
@@ -256,6 +256,7 @@ and tell you when they come and go.
 
 
 Creating the User
+^^^^^^^^^^^^^^^^^
 
 To use the message handler, you must first create a user using
 ipmi_create_user.  The interface number specifies which SMI you want
@@ -272,6 +273,7 @@ closing the device automatically destroys the user.
 
 
 Messaging
+^^^^^^^^^
 
 To send a message from kernel-land, the ipmi_request_settime() call does
 pretty much all message handling.  Most of the parameter are
@@ -321,6 +323,7 @@ though, since it is tricky to manage your own buffers.
 
 
 Events and Incoming Commands
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 The driver takes care of polling for IPMI events and receiving
 commands (commands are messages that are not responses, they are
@@ -367,7 +370,7 @@ in the system.  It discovers interfaces through a host of different
 methods, depending on the system.
 
 You can specify up to four interfaces on the module load line and
-control some module parameters:
+control some module parameters::
 
   modprobe ipmi_si.o type=<type1>,<type2>....
        ports=<port1>,<port2>... addrs=<addr1>,<addr2>...
@@ -437,7 +440,7 @@ default is one.  Setting to 0 is useful with the hotmod, but is
 obviously only useful for modules.
 
 When compiled into the kernel, the parameters can be specified on the
-kernel command line as:
+kernel command line as::
 
   ipmi_si.type=<type1>,<type2>...
        ipmi_si.ports=<port1>,<port2>... ipmi_si.addrs=<addr1>,<addr2>...
@@ -474,16 +477,22 @@ The driver supports a hot add and remove of interfaces.  This way,
 interfaces can be added or removed after the kernel is up and running.
 This is done using /sys/modules/ipmi_si/parameters/hotmod, which is a
 write-only parameter.  You write a string to this interface.  The string
-has the format:
+has the format::
+
    <op1>[:op2[:op3...]]
-The "op"s are:
+
+The "op"s are::
+
    add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]]
-You can specify more than one interface on the line.  The "opt"s are:
+
+You can specify more than one interface on the line.  The "opt"s are::
+
    rsp=<regspacing>
    rsi=<regsize>
    rsh=<regshift>
    irq=<irq>
    ipmb=<ipmb slave addr>
+
 and these have the same meanings as discussed above.  Note that you
 can also use this on the kernel command line for a more compact format
 for specifying an interface.  Note that when removing an interface,
@@ -496,7 +505,7 @@ The SMBus Driver (SSIF)
 The SMBus driver allows up to 4 SMBus devices to be configured in the
 system.  By default, the driver will only register with something it
 finds in DMI or ACPI tables.  You can change this
-at module load time (for a module) with:
+at module load time (for a module) with::
 
   modprobe ipmi_ssif.o
        addr=<i2caddr1>[,<i2caddr2>[,...]]
@@ -535,7 +544,7 @@ the smb_addr parameter unless you have DMI or ACPI data to tell the
 driver what to use.
 
 When compiled into the kernel, the addresses can be specified on the
-kernel command line as:
+kernel command line as::
 
   ipmb_ssif.addr=<i2caddr1>[,<i2caddr2>[...]]
        ipmi_ssif.adapter=<adapter1>[,<adapter2>[...]]
@@ -565,9 +574,9 @@ Some users need more detailed information about a device, like where
 the address came from or the raw base device for the IPMI interface.
 You can use the IPMI smi_watcher to catch the IPMI interfaces as they
 come or go, and to grab the information, you can use the function
-ipmi_get_smi_info(), which returns the following structure:
+ipmi_get_smi_info(), which returns the following structure::
 
-struct ipmi_smi_info {
+  struct ipmi_smi_info {
        enum ipmi_addr_src addr_src;
        struct device *dev;
        union {
@@ -575,7 +584,7 @@ struct ipmi_smi_info {
                        void *acpi_handle;
                } acpi_info;
        } addr_info;
-};
+  };
 
 Currently special info for only for SI_ACPI address sources is
 returned.  Others may be added as necessary.
@@ -590,7 +599,7 @@ Watchdog
 
 A watchdog timer is provided that implements the Linux-standard
 watchdog timer interface.  It has three module parameters that can be
-used to control it:
+used to control it::
 
   modprobe ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type>
       preaction=<preaction type> preop=<preop type> start_now=x
@@ -635,7 +644,7 @@ watchdog device is closed.  The default value of nowayout is true
 if the CONFIG_WATCHDOG_NOWAYOUT option is enabled, or false if not.
 
 When compiled into the kernel, the kernel command line is available
-for configuring the watchdog:
+for configuring the watchdog::
 
   ipmi_watchdog.timeout=<t> ipmi_watchdog.pretimeout=<t>
        ipmi_watchdog.action=<action type>
@@ -675,6 +684,7 @@ also get a bunch of OEM events holding the panic string.
 
 
 The field settings of the events are:
+
 * Generator ID: 0x21 (kernel)
 * EvM Rev: 0x03 (this event is formatting in IPMI 1.0 format)
 * Sensor Type: 0x20 (OS critical stop sensor)
@@ -683,18 +693,20 @@ The field settings of the events are:
 * Event Data 1: 0xa1 (Runtime stop in OEM bytes 2 and 3)
 * Event data 2: second byte of panic string
 * Event data 3: third byte of panic string
+
 See the IPMI spec for the details of the event layout.  This event is
 always sent to the local management controller.  It will handle routing
 the message to the right place
 
 Other OEM events have the following format:
-Record ID (bytes 0-1): Set by the SEL.
-Record type (byte 2): 0xf0 (OEM non-timestamped)
-byte 3: The slave address of the card saving the panic
-byte 4: A sequence number (starting at zero)
-The rest of the bytes (11 bytes) are the panic string.  If the panic string
-is longer than 11 bytes, multiple messages will be sent with increasing
-sequence numbers.
+
+* Record ID (bytes 0-1): Set by the SEL.
+* Record type (byte 2): 0xf0 (OEM non-timestamped)
+* byte 3: The slave address of the card saving the panic
+* byte 4: A sequence number (starting at zero)
+  The rest of the bytes (11 bytes) are the panic string.  If the panic string
+  is longer than 11 bytes, multiple messages will be sent with increasing
+  sequence numbers.
 
 Because you cannot send OEM events using the standard interface, this
 function will attempt to find an SEL and add the events there.  It
index 01a6751..29da500 100644 (file)
@@ -1,8 +1,11 @@
+================
+SMP IRQ affinity
+================
+
 ChangeLog:
-       Started by Ingo Molnar <mingo@redhat.com>
-       Update by Max Krasnyansky <maxk@qualcomm.com>
+       Started by Ingo Molnar <mingo@redhat.com>
+       Update by Max Krasnyansky <maxk@qualcomm.com>
 
-SMP IRQ affinity
 
 /proc/irq/IRQ#/smp_affinity and /proc/irq/IRQ#/smp_affinity_list specify
 which target CPUs are permitted for a given IRQ source.  It's a bitmask
@@ -16,50 +19,52 @@ will be set to the default mask. It can then be changed as described above.
 Default mask is 0xffffffff.
 
 Here is an example of restricting IRQ44 (eth1) to CPU0-3 then restricting
-it to CPU4-7 (this is an 8-CPU SMP box):
+it to CPU4-7 (this is an 8-CPU SMP box)::
 
-[root@moon 44]# cd /proc/irq/44
-[root@moon 44]# cat smp_affinity
-ffffffff
+       [root@moon 44]# cd /proc/irq/44
+       [root@moon 44]# cat smp_affinity
+       ffffffff
 
-[root@moon 44]# echo 0f > smp_affinity
-[root@moon 44]# cat smp_affinity
-0000000f
-[root@moon 44]# ping -f h
-PING hell (195.4.7.3): 56 data bytes
-...
---- hell ping statistics ---
-6029 packets transmitted, 6027 packets received, 0% packet loss
-round-trip min/avg/max = 0.1/0.1/0.4 ms
-[root@moon 44]# cat /proc/interrupts | grep 'CPU\|44:'
-           CPU0       CPU1       CPU2       CPU3      CPU4       CPU5        CPU6       CPU7
- 44:       1068       1785       1785       1783         0          0           0         0    IO-APIC-level  eth1
+       [root@moon 44]# echo 0f > smp_affinity
+       [root@moon 44]# cat smp_affinity
+       0000000f
+       [root@moon 44]# ping -f h
+       PING hell (195.4.7.3): 56 data bytes
+       ...
+       --- hell ping statistics ---
+       6029 packets transmitted, 6027 packets received, 0% packet loss
+       round-trip min/avg/max = 0.1/0.1/0.4 ms
+       [root@moon 44]# cat /proc/interrupts | grep 'CPU\|44:'
+               CPU0       CPU1       CPU2       CPU3      CPU4       CPU5        CPU6       CPU7
      44:       1068       1785       1785       1783         0          0           0         0    IO-APIC-level  eth1
 
 As can be seen from the line above IRQ44 was delivered only to the first four
 processors (0-3).
 Now lets restrict that IRQ to CPU(4-7).
 
-[root@moon 44]# echo f0 > smp_affinity
-[root@moon 44]# cat smp_affinity
-000000f0
-[root@moon 44]# ping -f h
-PING hell (195.4.7.3): 56 data bytes
-..
---- hell ping statistics ---
-2779 packets transmitted, 2777 packets received, 0% packet loss
-round-trip min/avg/max = 0.1/0.5/585.4 ms
-[root@moon 44]# cat /proc/interrupts |  'CPU\|44:'
-           CPU0       CPU1       CPU2       CPU3      CPU4       CPU5        CPU6       CPU7
- 44:       1068       1785       1785       1783      1784       1069        1070       1069   IO-APIC-level  eth1
+::
+
+       [root@moon 44]# echo f0 > smp_affinity
+       [root@moon 44]# cat smp_affinity
+       000000f0
+       [root@moon 44]# ping -f h
+       PING hell (195.4.7.3): 56 data bytes
+       ..
+       --- hell ping statistics ---
+       2779 packets transmitted, 2777 packets received, 0% packet loss
+       round-trip min/avg/max = 0.1/0.5/585.4 ms
+       [root@moon 44]# cat /proc/interrupts |  'CPU\|44:'
+               CPU0       CPU1       CPU2       CPU3      CPU4       CPU5        CPU6       CPU7
+       44:       1068       1785       1785       1783      1784       1069        1070       1069   IO-APIC-level  eth1
 
 This time around IRQ44 was delivered only to the last four processors.
 i.e counters for the CPU0-3 did not change.
 
-Here is an example of limiting that same irq (44) to cpus 1024 to 1031:
+Here is an example of limiting that same irq (44) to cpus 1024 to 1031::
 
-[root@moon 44]# echo 1024-1031 > smp_affinity_list
-[root@moon 44]# cat smp_affinity_list
-1024-1031
+       [root@moon 44]# echo 1024-1031 > smp_affinity_list
+       [root@moon 44]# cat smp_affinity_list
+       1024-1031
 
 Note that to do this with a bitmask would require 32 bitmasks of zero
 to follow the pertinent one.
index 1f246eb..4a1cd76 100644 (file)
@@ -1,4 +1,6 @@
-irq_domain interrupt number mapping library
+===============================================
+The irq_domain interrupt number mapping library
+===============================================
 
 The current design of the Linux kernel uses a single large number
 space where each separate IRQ source is assigned a different number.
@@ -36,7 +38,9 @@ irq_domain also implements translation from an abstract irq_fwspec
 structure to hwirq numbers (Device Tree and ACPI GSI so far), and can
 be easily extended to support other IRQ topology data sources.
 
-=== irq_domain usage ===
+irq_domain usage
+================
+
 An interrupt controller driver creates and registers an irq_domain by
 calling one of the irq_domain_add_*() functions (each mapping method
 has a different allocator function, more on that later).  The function
@@ -62,15 +66,21 @@ If the driver has the Linux IRQ number or the irq_data pointer, and
 needs to know the associated hwirq number (such as in the irq_chip
 callbacks) then it can be directly obtained from irq_data->hwirq.
 
-=== Types of irq_domain mappings ===
+Types of irq_domain mappings
+============================
+
 There are several mechanisms available for reverse mapping from hwirq
 to Linux irq, and each mechanism uses a different allocation function.
 Which reverse map type should be used depends on the use case.  Each
 of the reverse map types are described below:
 
-==== Linear ====
-irq_domain_add_linear()
-irq_domain_create_linear()
+Linear
+------
+
+::
+
+       irq_domain_add_linear()
+       irq_domain_create_linear()
 
 The linear reverse map maintains a fixed size table indexed by the
 hwirq number.  When a hwirq is mapped, an irq_desc is allocated for
@@ -89,9 +99,13 @@ accepts a more general abstraction 'struct fwnode_handle'.
 
 The majority of drivers should use the linear map.
 
-==== Tree ====
-irq_domain_add_tree()
-irq_domain_create_tree()
+Tree
+----
+
+::
+
+       irq_domain_add_tree()
+       irq_domain_create_tree()
 
 The irq_domain maintains a radix tree map from hwirq numbers to Linux
 IRQs.  When an hwirq is mapped, an irq_desc is allocated and the
@@ -109,8 +123,12 @@ accepts a more general abstraction 'struct fwnode_handle'.
 
 Very few drivers should need this mapping.
 
-==== No Map ===-
-irq_domain_add_nomap()
+No Map
+------
+
+::
+
+       irq_domain_add_nomap()
 
 The No Map mapping is to be used when the hwirq number is
 programmable in the hardware.  In this case it is best to program the
@@ -121,10 +139,14 @@ Linux IRQ number into the hardware.
 
 Most drivers cannot use this mapping.
 
-==== Legacy ====
-irq_domain_add_simple()
-irq_domain_add_legacy()
-irq_domain_add_legacy_isa()
+Legacy
+------
+
+::
+
+       irq_domain_add_simple()
+       irq_domain_add_legacy()
+       irq_domain_add_legacy_isa()
 
 The Legacy mapping is a special case for drivers that already have a
 range of irq_descs allocated for the hwirqs.  It is used when the
@@ -163,14 +185,17 @@ that the driver using the simple domain call irq_create_mapping()
 before any irq_find_mapping() since the latter will actually work
 for the static IRQ assignment case.
 
-==== Hierarchy IRQ domain ====
+Hierarchy IRQ domain
+--------------------
+
 On some architectures, there may be multiple interrupt controllers
 involved in delivering an interrupt from the device to the target CPU.
-Let's look at a typical interrupt delivering path on x86 platforms:
+Let's look at a typical interrupt delivering path on x86 platforms::
 
-Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU
+  Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU
 
 There are three interrupt controllers involved:
+
 1) IOAPIC controller
 2) Interrupt remapping controller
 3) Local APIC controller
@@ -180,7 +205,8 @@ hardware architecture, an irq_domain data structure is built for each
 interrupt controller and those irq_domains are organized into hierarchy.
 When building irq_domain hierarchy, the irq_domain near to the device is
 child and the irq_domain near to CPU is parent. So a hierarchy structure
-as below will be built for the example above.
+as below will be built for the example above::
+
        CPU Vector irq_domain (root irq_domain to manage CPU vectors)
                ^
                |
@@ -190,6 +216,7 @@ as below will be built for the example above.
        IOAPIC irq_domain (manage IOAPIC delivery entries/pins)
 
 There are four major interfaces to use hierarchy irq_domain:
+
 1) irq_domain_alloc_irqs(): allocate IRQ descriptors and interrupt
    controller related resources to deliver these interrupts.
 2) irq_domain_free_irqs(): free IRQ descriptors and interrupt controller
@@ -199,7 +226,8 @@ There are four major interfaces to use hierarchy irq_domain:
 4) irq_domain_deactivate_irq(): deactivate interrupt controller hardware
    to stop delivering the interrupt.
 
-Following changes are needed to support hierarchy irq_domain.
+Following changes are needed to support hierarchy irq_domain:
+
 1) a new field 'parent' is added to struct irq_domain; it's used to
    maintain irq_domain hierarchy information.
 2) a new field 'parent_data' is added to struct irq_data; it's used to
@@ -223,6 +251,7 @@ software architecture.
 
 For an interrupt controller driver to support hierarchy irq_domain, it
 needs to:
+
 1) Implement irq_domain_ops.alloc and irq_domain_ops.free
 2) Optionally implement irq_domain_ops.activate and
    irq_domain_ops.deactivate.
index 1011e71..4273806 100644 (file)
@@ -1,4 +1,6 @@
+===============
 What is an IRQ?
+===============
 
 An IRQ is an interrupt request from a device.
 Currently they can come in over a pin, or over a packet.
index 49585b6..9dae6b4 100644 (file)
@@ -1,3 +1,4 @@
+===================
 Linux IOMMU Support
 ===================
 
@@ -9,11 +10,11 @@ This guide gives a quick cheat sheet for some basic understanding.
 
 Some Keywords
 
-DMAR - DMA remapping
-DRHD - DMA Remapping Hardware Unit Definition
-RMRR - Reserved memory Region Reporting Structure
-ZLR  - Zero length reads from PCI devices
-IOVA - IO Virtual address.
+DMAR - DMA remapping
+DRHD - DMA Remapping Hardware Unit Definition
+RMRR - Reserved memory Region Reporting Structure
+ZLR  - Zero length reads from PCI devices
+IOVA - IO Virtual address.
 
 Basic stuff
 -----------
@@ -33,7 +34,7 @@ devices that need to access these regions. OS is expected to setup
 unity mappings for these regions for these devices to access these regions.
 
 How is IOVA generated?
----------------------
+----------------------
 
 Well behaved drivers call pci_map_*() calls before sending command to device
 that needs to perform DMA. Once DMA is completed and mapping is no longer
@@ -82,14 +83,14 @@ in ACPI.
 ACPI: DMAR (v001 A M I  OEMDMAR  0x00000001 MSFT 0x00000097) @ 0x000000007f5b5ef0
 
 When DMAR is being processed and initialized by ACPI, prints DMAR locations
-and any RMRR's processed.
+and any RMRR's processed::
 
-ACPI DMAR:Host address width 36
-ACPI DMAR:DRHD (flags: 0x00000000)base: 0x00000000fed90000
-ACPI DMAR:DRHD (flags: 0x00000000)base: 0x00000000fed91000
-ACPI DMAR:DRHD (flags: 0x00000001)base: 0x00000000fed93000
-ACPI DMAR:RMRR base: 0x00000000000ed000 end: 0x00000000000effff
-ACPI DMAR:RMRR base: 0x000000007f600000 end: 0x000000007fffffff
+       ACPI DMAR:Host address width 36
+       ACPI DMAR:DRHD (flags: 0x00000000)base: 0x00000000fed90000
+       ACPI DMAR:DRHD (flags: 0x00000000)base: 0x00000000fed91000
+       ACPI DMAR:DRHD (flags: 0x00000001)base: 0x00000000fed93000
+       ACPI DMAR:RMRR base: 0x00000000000ed000 end: 0x00000000000effff
+       ACPI DMAR:RMRR base: 0x000000007f600000 end: 0x000000007fffffff
 
 When DMAR is enabled for use, you will notice..
 
@@ -98,10 +99,12 @@ PCI-DMA: Using DMAR IOMMU
 Fault reporting
 ---------------
 
-DMAR:[DMA Write] Request device [00:02.0] fault addr 6df084000
-DMAR:[fault reason 05] PTE Write access is not set
-DMAR:[DMA Write] Request device [00:02.0] fault addr 6df084000
-DMAR:[fault reason 05] PTE Write access is not set
+::
+
+       DMAR:[DMA Write] Request device [00:02.0] fault addr 6df084000
+       DMAR:[fault reason 05] PTE Write access is not set
+       DMAR:[DMA Write] Request device [00:02.0] fault addr 6df084000
+       DMAR:[fault reason 05] PTE Write access is not set
 
 TBD
 ----
index 74be146..260e1d3 100644 (file)
@@ -1,5 +1,9 @@
-Linux 2.4.2 Secure Attention Key (SAK) handling
-18 March 2001, Andrew Morton
+=========================================
+Linux Secure Attention Key (SAK) handling
+=========================================
+
+:Date: 18 March 2001
+:Author: Andrew Morton
 
 An operating system's Secure Attention Key is a security tool which is
 provided as protection against trojan password capturing programs.  It
@@ -13,7 +17,7 @@ this sequence.  It is only available if the kernel was compiled with
 sysrq support.
 
 The proper way of generating a SAK is to define the key sequence using
-`loadkeys'.  This will work whether or not sysrq support is compiled
+``loadkeys``.  This will work whether or not sysrq support is compiled
 into the kernel.
 
 SAK works correctly when the keyboard is in raw mode.  This means that
@@ -25,64 +29,63 @@ What key sequence should you use? Well, CTRL-ALT-DEL is used to reboot
 the machine.  CTRL-ALT-BACKSPACE is magical to the X server.  We'll
 choose CTRL-ALT-PAUSE.
 
-In your rc.sysinit (or rc.local) file, add the command
+In your rc.sysinit (or rc.local) file, add the command::
 
        echo "control alt keycode 101 = SAK" | /bin/loadkeys
 
 And that's it!  Only the superuser may reprogram the SAK key.
 
 
-NOTES
-=====
+.. note::
 
-1: Linux SAK is said to be not a "true SAK" as is required by
-   systems which implement C2 level security.  This author does not
-   know why.
+  1. Linux SAK is said to be not a "true SAK" as is required by
+     systems which implement C2 level security.  This author does not
+     know why.
 
 
-2: On the PC keyboard, SAK kills all applications which have
-   /dev/console opened.
+  2. On the PC keyboard, SAK kills all applications which have
+     /dev/console opened.
 
-   Unfortunately this includes a number of things which you don't
-   actually want killed.  This is because these applications are
-   incorrectly holding /dev/console open.  Be sure to complain to your
-   Linux distributor about this!
+     Unfortunately this includes a number of things which you don't
+     actually want killed.  This is because these applications are
+     incorrectly holding /dev/console open.  Be sure to complain to your
+     Linux distributor about this!
 
-   You can identify processes which will be killed by SAK with the
-   command
+     You can identify processes which will be killed by SAK with the
+     command::
 
        # ls -l /proc/[0-9]*/fd/* | grep console
        l-wx------    1 root     root           64 Mar 18 00:46 /proc/579/fd/0 -> /dev/console
 
-   Then:
+     Then::
 
        # ps aux|grep 579
        root       579  0.0  0.1  1088  436 ?        S    00:43   0:00 gpm -t ps/2
 
-   So `gpm' will be killed by SAK.  This is a bug in gpm.  It should
-   be closing standard input.  You can work around this by finding the
-   initscript which launches gpm and changing it thusly:
+     So ``gpm`` will be killed by SAK.  This is a bug in gpm.  It should
+     be closing standard input.  You can work around this by finding the
+     initscript which launches gpm and changing it thusly:
 
-   Old:
+     Old::
 
        daemon gpm
 
-   New:
+     New::
 
        daemon gpm < /dev/null
 
-   Vixie cron also seems to have this problem, and needs the same treatment.
+     Vixie cron also seems to have this problem, and needs the same treatment.
 
-   Also, one prominent Linux distribution has the following three
-   lines in its rc.sysinit and rc scripts:
+     Also, one prominent Linux distribution has the following three
+     lines in its rc.sysinit and rc scripts::
 
        exec 3<&0
        exec 4>&1
        exec 5>&2
 
-   These commands cause *all* daemons which are launched by the
-   initscripts to have file descriptors 3, 4 and 5 attached to
-   /dev/console.  So SAK kills them all.  A workaround is to simply
-   delete these lines, but this may cause system management
-   applications to malfunction - test everything well.
+     These commands cause **all** daemons which are launched by the
+     initscripts to have file descriptors 3, 4 and 5 attached to
+     /dev/console.  So SAK kills them all.  A workaround is to simply
+     delete these lines, but this may cause system management
+     applications to malfunction - test everything well.
 
index 561826f..8825074 100644 (file)
@@ -1,7 +1,10 @@
-                       SM501 Driver
-                       ============
+.. include:: <isonum.txt>
 
-Copyright 2006, 2007 Simtec Electronics
+============
+SM501 Driver
+============
+
+:Copyright: |copy| 2006, 2007 Simtec Electronics
 
 The Silicon Motion SM501 multimedia companion chip is a multifunction device
 which may provide numerous interfaces including USB host controller USB gadget,
index a9259b5..c0ce64d 100644 (file)
@@ -1,10 +1,15 @@
+============================
+A block layer cache (bcache)
+============================
+
 Say you've got a big slow raid 6, and an ssd or three. Wouldn't it be
 nice if you could use them as cache... Hence bcache.
 
 Wiki and git repositories are at:
-  http://bcache.evilpiepirate.org
-  http://evilpiepirate.org/git/linux-bcache.git
-  http://evilpiepirate.org/git/bcache-tools.git
+
+  - http://bcache.evilpiepirate.org
+  - http://evilpiepirate.org/git/linux-bcache.git
+  - http://evilpiepirate.org/git/bcache-tools.git
 
 It's designed around the performance characteristics of SSDs - it only allocates
 in erase block sized buckets, and it uses a hybrid btree/log to track cached
@@ -37,17 +42,19 @@ to be flushed.
 
 Getting started:
 You'll need make-bcache from the bcache-tools repository. Both the cache device
-and backing device must be formatted before use.
+and backing device must be formatted before use::
+
   make-bcache -B /dev/sdb
   make-bcache -C /dev/sdc
 
 make-bcache has the ability to format multiple devices at the same time - if
 you format your backing devices and cache device at the same time, you won't
-have to manually attach:
+have to manually attach::
+
   make-bcache -B /dev/sda /dev/sdb -C /dev/sdc
 
 bcache-tools now ships udev rules, and bcache devices are known to the kernel
-immediately.  Without udev, you can manually register devices like this:
+immediately.  Without udev, you can manually register devices like this::
 
   echo /dev/sdb > /sys/fs/bcache/register
   echo /dev/sdc > /sys/fs/bcache/register
@@ -60,16 +67,16 @@ slow devices as bcache backing devices without a cache, and you can choose to ad
 a caching device later.
 See 'ATTACHING' section below.
 
-The devices show up as:
+The devices show up as::
 
   /dev/bcache<N>
 
-As well as (with udev):
+As well as (with udev)::
 
   /dev/bcache/by-uuid/<uuid>
   /dev/bcache/by-label/<label>
 
-To get started:
+To get started::
 
   mkfs.ext4 /dev/bcache0
   mount /dev/bcache0 /mnt
@@ -81,13 +88,13 @@ Cache devices are managed as sets; multiple caches per set isn't supported yet
 but will allow for mirroring of metadata and dirty data in the future. Your new
 cache set shows up as /sys/fs/bcache/<UUID>
 
-ATTACHING
+Attaching
 ---------
 
 After your cache device and backing device are registered, the backing device
 must be attached to your cache set to enable caching. Attaching a backing
 device to a cache set is done thusly, with the UUID of the cache set in
-/sys/fs/bcache:
+/sys/fs/bcache::
 
   echo <CSET-UUID> > /sys/block/bcache0/bcache/attach
 
@@ -97,7 +104,7 @@ your bcache devices. If a backing device has data in a cache somewhere, the
 important if you have writeback caching turned on.
 
 If you're booting up and your cache device is gone and never coming back, you
-can force run the backing device:
+can force run the backing device::
 
   echo 1 > /sys/block/sdb/bcache/running
 
@@ -110,7 +117,7 @@ but all the cached data will be invalidated. If there was dirty data in the
 cache, don't expect the filesystem to be recoverable - you will have massive
 filesystem corruption, though ext4's fsck does work miracles.
 
-ERROR HANDLING
+Error Handling
 --------------
 
 Bcache tries to transparently handle IO errors to/from the cache device without
@@ -134,25 +141,27 @@ the backing devices to passthrough mode.
    read some of the dirty data, though.
 
 
-HOWTO/COOKBOOK
+Howto/cookbook
 --------------
 
 A) Starting a bcache with a missing caching device
 
 If registering the backing device doesn't help, it's already there, you just need
-to force it to run without the cache:
+to force it to run without the cache::
+
        host:~# echo /dev/sdb1 > /sys/fs/bcache/register
        [  119.844831] bcache: register_bcache() error opening /dev/sdb1: device already registered
 
 Next, you try to register your caching device if it's present. However
 if it's absent, or registration fails for some reason, you can still
-start your bcache without its cache, like so:
+start your bcache without its cache, like so::
+
        host:/sys/block/sdb/sdb1/bcache# echo 1 > running
 
 Note that this may cause data loss if you were running in writeback mode.
 
 
-B) Bcache does not find its cache
+B) Bcache does not find its cache::
 
        host:/sys/block/md5/bcache# echo 0226553a-37cf-41d5-b3ce-8b1e944543a8 > attach
        [ 1933.455082] bcache: bch_cached_dev_attach() Couldn't find uuid for md5 in set
@@ -160,7 +169,8 @@ B) Bcache does not find its cache
        [ 1933.478179] : cache set not found
 
 In this case, the caching device was simply not registered at boot
-or disappeared and came back, and needs to be (re-)registered:
+or disappeared and came back, and needs to be (re-)registered::
+
        host:/sys/block/md5/bcache# echo /dev/sdh2 > /sys/fs/bcache/register
 
 
@@ -180,7 +190,8 @@ device is still available at an 8KiB offset. So either via a loopdev
 of the backing device created with --offset 8K, or any value defined by
 --data-offset when you originally formatted bcache with `make-bcache`.
 
-For example:
+For example::
+
        losetup -o 8192 /dev/loop0 /dev/your_bcache_backing_dev
 
 This should present your unmodified backing device data in /dev/loop0
@@ -191,33 +202,38 @@ cache device without loosing data.
 
 E) Wiping a cache device
 
-host:~# wipefs -a /dev/sdh2
-16 bytes were erased at offset 0x1018 (bcache)
-they were: c6 85 73 f6 4e 1a 45 ca 82 65 f5 7f 48 ba 6d 81
+::
+
+       host:~# wipefs -a /dev/sdh2
+       16 bytes were erased at offset 0x1018 (bcache)
+       they were: c6 85 73 f6 4e 1a 45 ca 82 65 f5 7f 48 ba 6d 81
+
+After you boot back with bcache enabled, you recreate the cache and attach it::
 
-After you boot back with bcache enabled, you recreate the cache and attach it:
-host:~# make-bcache -C /dev/sdh2
-UUID:                   7be7e175-8f4c-4f99-94b2-9c904d227045
-Set UUID:               5bc072a8-ab17-446d-9744-e247949913c1
-version:                0
-nbuckets:               106874
-block_size:             1
-bucket_size:            1024
-nr_in_set:              1
-nr_this_dev:            0
-first_bucket:           1
-[  650.511912] bcache: run_cache_set() invalidating existing data
-[  650.549228] bcache: register_cache() registered cache device sdh2
+       host:~# make-bcache -C /dev/sdh2
+       UUID:                   7be7e175-8f4c-4f99-94b2-9c904d227045
+       Set UUID:               5bc072a8-ab17-446d-9744-e247949913c1
+       version:                0
+       nbuckets:               106874
+       block_size:             1
+       bucket_size:            1024
+       nr_in_set:              1
+       nr_this_dev:            0
+       first_bucket:           1
+       [  650.511912] bcache: run_cache_set() invalidating existing data
+       [  650.549228] bcache: register_cache() registered cache device sdh2
 
-start backing device with missing cache:
-host:/sys/block/md5/bcache# echo 1 > running
+start backing device with missing cache::
 
-attach new cache:
-host:/sys/block/md5/bcache# echo 5bc072a8-ab17-446d-9744-e247949913c1 > attach
-[  865.276616] bcache: bch_cached_dev_attach() Caching md5 as bcache0 on set 5bc072a8-ab17-446d-9744-e247949913c1
+       host:/sys/block/md5/bcache# echo 1 > running
 
+attach new cache::
 
-F) Remove or replace a caching device
+       host:/sys/block/md5/bcache# echo 5bc072a8-ab17-446d-9744-e247949913c1 > attach
+       [  865.276616] bcache: bch_cached_dev_attach() Caching md5 as bcache0 on set 5bc072a8-ab17-446d-9744-e247949913c1
+
+
+F) Remove or replace a caching device::
 
        host:/sys/block/sda/sda7/bcache# echo 1 > detach
        [  695.872542] bcache: cached_dev_detach_finish() Caching disabled for sda7
@@ -226,13 +242,15 @@ F) Remove or replace a caching device
        wipefs: error: /dev/nvme0n1p4: probing initialization failed: Device or resource busy
        Ooops, it's disabled, but not unregistered, so it's still protected
 
-We need to go and unregister it:
+We need to go and unregister it::
+
        host:/sys/fs/bcache/b7ba27a1-2398-4649-8ae3-0959f57ba128# ls -l cache0
        lrwxrwxrwx 1 root root 0 Feb 25 18:33 cache0 -> ../../../devices/pci0000:00/0000:00:1d.0/0000:70:00.0/nvme/nvme0/nvme0n1/nvme0n1p4/bcache/
        host:/sys/fs/bcache/b7ba27a1-2398-4649-8ae3-0959f57ba128# echo 1 > stop
        kernel: [  917.041908] bcache: cache_set_free() Cache set b7ba27a1-2398-4649-8ae3-0959f57ba128 unregistered
 
-Now we can wipe it:
+Now we can wipe it::
+
        host:~# wipefs -a /dev/nvme0n1p4
        /dev/nvme0n1p4: 16 bytes were erased at offset 0x00001018 (bcache): c6 85 73 f6 4e 1a 45 ca 82 65 f5 7f 48 ba 6d 81
 
@@ -252,40 +270,44 @@ if there are any active backing or caching devices left on it:
 
 1) Is it present in /dev/bcache* ? (there are times where it won't be)
 
-If so, it's easy:
+   If so, it's easy::
+
        host:/sys/block/bcache0/bcache# echo 1 > stop
 
-2) But if your backing device is gone, this won't work:
+2) But if your backing device is gone, this won't work::
+
        host:/sys/block/bcache0# cd bcache
        bash: cd: bcache: No such file or directory
 
-In this case, you may have to unregister the dmcrypt block device that
-references this bcache to free it up:
+   In this case, you may have to unregister the dmcrypt block device that
+   references this bcache to free it up::
+
        host:~# dmsetup remove oldds1
        bcache: bcache_device_free() bcache0 stopped
        bcache: cache_set_free() Cache set 5bc072a8-ab17-446d-9744-e247949913c1 unregistered
 
-This causes the backing bcache to be removed from /sys/fs/bcache and
-then it can be reused.  This would be true of any block device stacking
-where bcache is a lower device.
+   This causes the backing bcache to be removed from /sys/fs/bcache and
+   then it can be reused.  This would be true of any block device stacking
+   where bcache is a lower device.
+
+3) In other cases, you can also look in /sys/fs/bcache/::
 
-3) In other cases, you can also look in /sys/fs/bcache/:
+       host:/sys/fs/bcache# ls -l */{cache?,bdev?}
+       lrwxrwxrwx 1 root root 0 Mar  5 09:39 0226553a-37cf-41d5-b3ce-8b1e944543a8/bdev1 -> ../../../devices/virtual/block/dm-1/bcache/
+       lrwxrwxrwx 1 root root 0 Mar  5 09:39 0226553a-37cf-41d5-b3ce-8b1e944543a8/cache0 -> ../../../devices/virtual/block/dm-4/bcache/
+       lrwxrwxrwx 1 root root 0 Mar  5 09:39 5bc072a8-ab17-446d-9744-e247949913c1/cache0 -> ../../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/ata10/host9/target9:0:0/9:0:0:0/block/sdl/sdl2/bcache/
 
-host:/sys/fs/bcache# ls -l */{cache?,bdev?}
-lrwxrwxrwx 1 root root 0 Mar  5 09:39 0226553a-37cf-41d5-b3ce-8b1e944543a8/bdev1 -> ../../../devices/virtual/block/dm-1/bcache/
-lrwxrwxrwx 1 root root 0 Mar  5 09:39 0226553a-37cf-41d5-b3ce-8b1e944543a8/cache0 -> ../../../devices/virtual/block/dm-4/bcache/
-lrwxrwxrwx 1 root root 0 Mar  5 09:39 5bc072a8-ab17-446d-9744-e247949913c1/cache0 -> ../../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/ata10/host9/target9:0:0/9:0:0:0/block/sdl/sdl2/bcache/
+   The device names will show which UUID is relevant, cd in that directory
+   and stop the cache::
 
-The device names will show which UUID is relevant, cd in that directory
-and stop the cache:
        host:/sys/fs/bcache/5bc072a8-ab17-446d-9744-e247949913c1# echo 1 > stop
 
-This will free up bcache references and let you reuse the partition for
-other purposes.
+   This will free up bcache references and let you reuse the partition for
+   other purposes.
 
 
 
-TROUBLESHOOTING PERFORMANCE
+Troubleshooting performance
 ---------------------------
 
 Bcache has a bunch of config options and tunables. The defaults are intended to
@@ -301,11 +323,13 @@ want for getting the best possible numbers when benchmarking.
    raid stripe size to get the disk multiples that you would like.
 
    For example:  If you have a 64k stripe size, then the following offset
-   would provide alignment for many common RAID5 data spindle counts:
+   would provide alignment for many common RAID5 data spindle counts::
+
        64k * 2*2*2*3*3*5*7 bytes = 161280k
 
    That space is wasted, but for only 157.5MB you can grow your RAID 5
-   volume to the following data-spindle counts without re-aligning:
+   volume to the following data-spindle counts without re-aligning::
+
        3,4,5,6,7,8,9,10,12,14,15,18,20,21 ...
 
  - Bad write performance
@@ -313,9 +337,9 @@ want for getting the best possible numbers when benchmarking.
    If write performance is not what you expected, you probably wanted to be
    running in writeback mode, which isn't the default (not due to a lack of
    maturity, but simply because in writeback mode you'll lose data if something
-   happens to your SSD)
+   happens to your SSD)::
 
-   # echo writeback > /sys/block/bcache0/bcache/cache_mode
+       # echo writeback > /sys/block/bcache0/bcache/cache_mode
 
  - Bad performance, or traffic not going to the SSD that you'd expect
 
@@ -325,13 +349,13 @@ want for getting the best possible numbers when benchmarking.
    accessed data out of your cache.
 
    But if you want to benchmark reads from cache, and you start out with fio
-   writing an 8 gigabyte test file - so you want to disable that.
+   writing an 8 gigabyte test file - so you want to disable that::
 
-   # echo 0 > /sys/block/bcache0/bcache/sequential_cutoff
+       # echo 0 > /sys/block/bcache0/bcache/sequential_cutoff
 
-   To set it back to the default (4 mb), do
+   To set it back to the default (4 mb), do::
 
-   # echo 4M > /sys/block/bcache0/bcache/sequential_cutoff
+       # echo 4M > /sys/block/bcache0/bcache/sequential_cutoff
 
  - Traffic's still going to the spindle/still getting cache misses
 
@@ -344,10 +368,10 @@ want for getting the best possible numbers when benchmarking.
    throttles traffic if the latency exceeds a threshold (it does this by
    cranking down the sequential bypass).
 
-   You can disable this if you need to by setting the thresholds to 0:
+   You can disable this if you need to by setting the thresholds to 0::
 
-   # echo 0 > /sys/fs/bcache/<cache set>/congested_read_threshold_us
-   # echo 0 > /sys/fs/bcache/<cache set>/congested_write_threshold_us
+       # echo 0 > /sys/fs/bcache/<cache set>/congested_read_threshold_us
+       # echo 0 > /sys/fs/bcache/<cache set>/congested_write_threshold_us
 
    The default is 2000 us (2 milliseconds) for reads, and 20000 for writes.
 
@@ -369,7 +393,7 @@ want for getting the best possible numbers when benchmarking.
    a fix for the issue there).
 
 
-SYSFS - BACKING DEVICE
+Sysfs - backing device
 ----------------------
 
 Available at /sys/block/<bdev>/bcache, /sys/block/bcache*/bcache and
@@ -454,7 +478,8 @@ writeback_running
   still be added to the cache until it is mostly full; only meant for
   benchmarking. Defaults to on.
 
-SYSFS - BACKING DEVICE STATS:
+Sysfs - backing device stats
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 There are directories with these numbers for a running total, as well as
 versions that decay over the past day, hour and 5 minutes; they're also
@@ -463,14 +488,11 @@ aggregated in the cache set directory as well.
 bypassed
   Amount of IO (both reads and writes) that has bypassed the cache
 
-cache_hits
-cache_misses
-cache_hit_ratio
+cache_hits, cache_misses, cache_hit_ratio
   Hits and misses are counted per individual IO as bcache sees them; a
   partial hit is counted as a miss.
 
-cache_bypass_hits
-cache_bypass_misses
+cache_bypass_hits, cache_bypass_misses
   Hits and misses for IO that is intended to skip the cache are still counted,
   but broken out here.
 
@@ -482,7 +504,8 @@ cache_miss_collisions
 cache_readaheads
   Count of times readahead occurred.
 
-SYSFS - CACHE SET:
+Sysfs - cache set
+~~~~~~~~~~~~~~~~~
 
 Available at /sys/fs/bcache/<cset-uuid>
 
@@ -520,8 +543,7 @@ flash_vol_create
   Echoing a size to this file (in human readable units, k/M/G) creates a thinly
   provisioned volume backed by the cache set.
 
-io_error_halflife
-io_error_limit
+io_error_halflife, io_error_limit
   These determines how many errors we accept before disabling the cache.
   Each error is decayed by the half life (in # ios).  If the decaying count
   reaches io_error_limit dirty data is written out and the cache is disabled.
@@ -545,7 +567,8 @@ unregister
   Detaches all backing devices and closes the cache devices; if dirty data is
   present it will disable writeback caching and wait for it to be flushed.
 
-SYSFS - CACHE SET INTERNAL:
+Sysfs - cache set internal
+~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 This directory also exposes timings for a number of internal operations, with
 separate files for average duration, average frequency, last occurrence and max
@@ -574,7 +597,8 @@ cache_read_races
 trigger_gc
   Writing to this file forces garbage collection to run.
 
-SYSFS - CACHE DEVICE:
+Sysfs - Cache device
+~~~~~~~~~~~~~~~~~~~~
 
 Available at /sys/block/<cdev>/bcache
 
index d8297e4..a845feb 100644 (file)
@@ -1,12 +1,8 @@
-===============================================================
-==  BT8XXGPIO driver                                         ==
-==                                                           ==
-==  A driver for a selfmade cheap BT8xx based PCI GPIO-card  ==
-==                                                           ==
-==  For advanced documentation, see                          ==
-==  http://www.bu3sch.de/btgpio.php                          ==
-===============================================================
+===================================================================
+A driver for a selfmade cheap BT8xx based PCI GPIO-card (bt8xxgpio)
+===================================================================
 
+For advanced documentation, see http://www.bu3sch.de/btgpio.php
 
 A generic digital 24-port PCI GPIO card can be built out of an ordinary
 Brooktree bt848, bt849, bt878 or bt879 based analog TV tuner card. The
@@ -17,9 +13,8 @@ The bt8xx chip does have 24 digital GPIO ports.
 These ports are accessible via 24 pins on the SMD chip package.
 
 
-==============================================
-==  How to physically access the GPIO pins  ==
-==============================================
+How to physically access the GPIO pins
+======================================
 
 The are several ways to access these pins. One might unsolder the whole chip
 and put it on a custom PCI board, or one might only unsolder each individual
@@ -27,7 +22,7 @@ GPIO pin and solder that to some tiny wire. As the chip package really is tiny
 there are some advanced soldering skills needed in any case.
 
 The physical pinouts are drawn in the following ASCII art.
-The GPIO pins are marked with G00-G23
+The GPIO pins are marked with G00-G23::
 
                                            G G G G G G G G G G G G     G G G G G G
                                            0 0 0 0 0 0 0 0 0 0 1 1     1 1 1 1 1 1
index 34916a4..ec57740 100644 (file)
@@ -1,18 +1,16 @@
-=======================================================================
-               README for btmrvl driver
-=======================================================================
-
+=============
+btmrvl driver
+=============
 
 All commands are used via debugfs interface.
 
-=====================
-Set/get driver configurations:
+Set/get driver configurations
+=============================
 
 Path:  /debug/btmrvl/config/
 
-gpiogap=[n]
-hscfgcmd
-       These commands are used to configure the host sleep parameters.
+gpiogap=[n], hscfgcmd
+       These commands are used to configure the host sleep parameters::
        bit 8:0  -- Gap
        bit 16:8 -- GPIO
 
@@ -23,7 +21,8 @@ hscfgcmd
        where Gap is the gap in milli seconds between wakeup signal and
        wakeup event, or 0xff for special host sleep setting.
 
-       Usage:
+       Usage::
+
                # Use SDIO interface to wake up the host and set GAP to 0x80:
                echo 0xff80 > /debug/btmrvl/config/gpiogap
                echo 1 > /debug/btmrvl/config/hscfgcmd
@@ -32,15 +31,16 @@ hscfgcmd
                echo 0x03ff >  /debug/btmrvl/config/gpiogap
                echo 1 > /debug/btmrvl/config/hscfgcmd
 
-psmode=[n]
-pscmd
+psmode=[n], pscmd
        These commands are used to enable/disable auto sleep mode
 
-       where the option is:
+       where the option is::
+
                        1       -- Enable auto sleep mode
                        0       -- Disable auto sleep mode
 
-       Usage:
+       Usage::
+
                # Enable auto sleep mode
                echo 1 > /debug/btmrvl/config/psmode
                echo 1 > /debug/btmrvl/config/pscmd
@@ -50,15 +50,16 @@ pscmd
                echo 1 > /debug/btmrvl/config/pscmd
 
 
-hsmode=[n]
-hscmd
+hsmode=[n], hscmd
        These commands are used to enable host sleep or wake up firmware
 
-       where the option is:
+       where the option is::
+
                        1       -- Enable host sleep
                        0       -- Wake up firmware
 
-       Usage:
+       Usage::
+
                # Enable host sleep
                echo 1 > /debug/btmrvl/config/hsmode
                echo 1 > /debug/btmrvl/config/hscmd
@@ -68,12 +69,13 @@ hscmd
                echo 1 > /debug/btmrvl/config/hscmd
 
 
-======================
-Get driver status:
+Get driver status
+=================
 
 Path:  /debug/btmrvl/status/
 
-Usage:
+Usage::
+
        cat /debug/btmrvl/status/<args>
 
 where the args are:
@@ -90,14 +92,17 @@ hsstate
 txdnldrdy
        This command displays the value of Tx download ready flag.
 
-
-=====================
+Issuing a raw hci command
+=========================
 
 Use hcitool to issue raw hci command, refer to hcitool manual
 
-       Usage: Hcitool cmd <ogf> <ocf> [Parameters]
+Usage::
+
+       Hcitool cmd <ogf> <ocf> [Parameters]
+
+Interface Control Command::
 
-       Interface Control Command
        hcitool cmd 0x3f 0x5b 0xf5 0x01 0x00    --Enable All interface
        hcitool cmd 0x3f 0x5b 0xf5 0x01 0x01    --Enable Wlan interface
        hcitool cmd 0x3f 0x5b 0xf5 0x01 0x02    --Enable BT interface
@@ -105,13 +110,13 @@ Use hcitool to issue raw hci command, refer to hcitool manual
        hcitool cmd 0x3f 0x5b 0xf5 0x00 0x01    --Disable Wlan interface
        hcitool cmd 0x3f 0x5b 0xf5 0x00 0x02    --Disable BT interface
 
-=======================================================================
-
+SD8688 firmware
+===============
 
-SD8688 firmware:
+Images:
 
-/lib/firmware/sd8688_helper.bin
-/lib/firmware/sd8688.bin
+/lib/firmware/sd8688_helper.bin
+/lib/firmware/sd8688.bin
 
 
 The images can be downloaded from:
index 2bc55ff..4bb07c2 100644 (file)
@@ -1,17 +1,27 @@
-[ NOTE: The virt_to_bus() and bus_to_virt() functions have been
+==========================================================
+How to access I/O mapped memory from within device drivers
+==========================================================
+
+:Author: Linus
+
+.. warning::
+
+       The virt_to_bus() and bus_to_virt() functions have been
        superseded by the functionality provided by the PCI DMA interface
        (see Documentation/DMA-API-HOWTO.txt).  They continue
        to be documented below for historical purposes, but new code
-       must not use them. --davidm 00/12/12 ]
+       must not use them. --davidm 00/12/12
 
-[ This is a mail message in response to a query on IO mapping, thus the
-  strange format for a "document" ]
+::
+
+  [ This is a mail message in response to a query on IO mapping, thus the
+    strange format for a "document" ]
 
 The AHA-1542 is a bus-master device, and your patch makes the driver give the
 controller the physical address of the buffers, which is correct on x86
 (because all bus master devices see the physical memory mappings directly). 
 
-However, on many setups, there are actually _three_ different ways of looking
+However, on many setups, there are actually **three** different ways of looking
 at memory addresses, and in this case we actually want the third, the
 so-called "bus address". 
 
@@ -38,7 +48,7 @@ because the memory and the devices share the same address space, and that is
 not generally necessarily true on other PCI/ISA setups. 
 
 Now, just as an example, on the PReP (PowerPC Reference Platform), the 
-CPU sees a memory map something like this (this is from memory):
+CPU sees a memory map something like this (this is from memory)::
 
        0-2 GB          "real memory"
        2 GB-3 GB       "system IO" (inb/out and similar accesses on x86)
@@ -52,7 +62,7 @@ So when the CPU wants any bus master to write to physical memory 0, it
 has to give the master address 0x80000000 as the memory address.
 
 So, for example, depending on how the kernel is actually mapped on the 
-PPC, you can end up with a setup like this:
+PPC, you can end up with a setup like this::
 
  physical address:     0
  virtual address:      0xC0000000
@@ -61,7 +71,7 @@ PPC, you can end up with a setup like this:
 where all the addresses actually point to the same thing.  It's just seen 
 through different translations..
 
-Similarly, on the Alpha, the normal translation is
+Similarly, on the Alpha, the normal translation is::
 
  physical address:     0
  virtual address:      0xfffffc0000000000
@@ -70,7 +80,7 @@ Similarly, on the Alpha, the normal translation is
 (but there are also Alphas where the physical address and the bus address
 are the same). 
 
-Anyway, the way to look up all these translations, you do
+Anyway, the way to look up all these translations, you do::
 
        #include <asm/io.h>
 
@@ -81,8 +91,8 @@ Anyway, the way to look up all these translations, you do
 
 Now, when do you need these?
 
-You want the _virtual_ address when you are actually going to access that 
-pointer from the kernel. So you can have something like this:
+You want the **virtual** address when you are actually going to access that
+pointer from the kernel. So you can have something like this::
 
        /*
         * this is the hardware "mailbox" we use to communicate with
@@ -104,7 +114,7 @@ pointer from the kernel. So you can have something like this:
                                ...
 
 on the other hand, you want the bus address when you have a buffer that 
-you want to give to the controller:
+you want to give to the controller::
 
        /* ask the controller to read the sense status into "sense_buffer" */
        mbox.bufstart = virt_to_bus(&sense_buffer);
@@ -112,7 +122,7 @@ you want to give to the controller:
        mbox.status = 0;
        notify_controller(&mbox);
 
-And you generally _never_ want to use the physical address, because you can't
+And you generally **never** want to use the physical address, because you can't
 use that from the CPU (the CPU only uses translated virtual addresses), and
 you can't use it from the bus master. 
 
@@ -124,8 +134,10 @@ be remapped as measured in units of pages, a.k.a. the pfn (the memory
 management layer doesn't know about devices outside the CPU, so it
 shouldn't need to know about "bus addresses" etc).
 
-NOTE NOTE NOTE! The above is only one part of the whole equation. The above
-only talks about "real memory", that is, CPU memory (RAM). 
+.. note::
+
+       The above is only one part of the whole equation. The above
+       only talks about "real memory", that is, CPU memory (RAM).
 
 There is a completely different type of memory too, and that's the "shared
 memory" on the PCI or ISA bus. That's generally not RAM (although in the case
@@ -137,20 +149,22 @@ whatever, and there is only one way to access it: the readb/writeb and
 related functions. You should never take the address of such memory, because
 there is really nothing you can do with such an address: it's not
 conceptually in the same memory space as "real memory" at all, so you cannot
-just dereference a pointer. (Sadly, on x86 it _is_ in the same memory space,
+just dereference a pointer. (Sadly, on x86 it **is** in the same memory space,
 so on x86 it actually works to just deference a pointer, but it's not
 portable). 
 
-For such memory, you can do things like
+For such memory, you can do things like:
+
+ - reading::
 
- - reading:
        /*
         * read first 32 bits from ISA memory at 0xC0000, aka
         * C000:0000 in DOS terms
         */
        unsigned int signature = isa_readl(0xC0000);
 
- - remapping and writing:
+ - remapping and writing::
+
        /*
         * remap framebuffer PCI memory area at 0xFC000000,
         * size 1MB, so that we can access it: We can directly
@@ -165,7 +179,8 @@ For such memory, you can do things like
        /* unmap when we unload the driver */
        iounmap(baseptr);
 
- - copying and clearing:
+ - copying and clearing::
+
        /* get the 6-byte Ethernet address at ISA address E000:0040 */
        memcpy_fromio(kernel_buffer, 0xE0040, 6);
        /* write a packet to the driver */
@@ -181,10 +196,10 @@ happy that your driver works ;)
 Note that kernel versions 2.0.x (and earlier) mistakenly called the
 ioremap() function "vremap()".  ioremap() is the proper name, but I
 didn't think straight when I wrote it originally.  People who have to
-support both can do something like:
+support both can do something like::
  
        /* support old naming silliness */
-       #if LINUX_VERSION_CODE < 0x020100                                     
+       #if LINUX_VERSION_CODE < 0x020100
        #define ioremap vremap
        #define iounmap vfree                                                     
        #endif
@@ -196,13 +211,10 @@ And the above sounds worse than it really is.  Most real drivers really
 don't do all that complex things (or rather: the complexity is not so
 much in the actual IO accesses as in error handling and timeouts etc). 
 It's generally not hard to fix drivers, and in many cases the code
-actually looks better afterwards:
+actually looks better afterwards::
 
        unsigned long signature = *(unsigned int *) 0xC0000;
                vs
        unsigned long signature = readl(0xC0000);
 
 I think the second version actually is more readable, no?
-
-               Linus
-
index 3f9f808..6eb9d3f 100644 (file)
@@ -1,7 +1,8 @@
-               Cache and TLB Flushing
-                    Under Linux
+==================================
+Cache and TLB Flushing Under Linux
+==================================
 
-           David S. Miller <davem@redhat.com>
+:Author: David S. Miller <davem@redhat.com>
 
 This document describes the cache/tlb flushing interfaces called
 by the Linux VM subsystem.  It enumerates over each interface,
@@ -28,7 +29,7 @@ Therefore when software page table changes occur, the kernel will
 invoke one of the following flush methods _after_ the page table
 changes occur:
 
-1) void flush_tlb_all(void)
+1) ``void flush_tlb_all(void)``
 
        The most severe flush of all.  After this interface runs,
        any previous page table modification whatsoever will be
@@ -37,7 +38,7 @@ changes occur:
        This is usually invoked when the kernel page tables are
        changed, since such translations are "global" in nature.
 
-2) void flush_tlb_mm(struct mm_struct *mm)
+2) ``void flush_tlb_mm(struct mm_struct *mm)``
 
        This interface flushes an entire user address space from
        the TLB.  After running, this interface must make sure that
@@ -49,8 +50,8 @@ changes occur:
        page table operations such as what happens during
        fork, and exec.
 
-3) void flush_tlb_range(struct vm_area_struct *vma,
-                       unsigned long start, unsigned long end)
+3) ``void flush_tlb_range(struct vm_area_struct *vma,
+   unsigned long start, unsigned long end)``
 
        Here we are flushing a specific range of (user) virtual
        address translations from the TLB.  After running, this
@@ -69,7 +70,7 @@ changes occur:
        call flush_tlb_page (see below) for each entry which may be
        modified.
 
-4) void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
+4) ``void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)``
 
        This time we need to remove the PAGE_SIZE sized translation
        from the TLB.  The 'vma' is the backing structure used by
@@ -87,8 +88,8 @@ changes occur:
 
        This is used primarily during fault processing.
 
-5) void update_mmu_cache(struct vm_area_struct *vma,
-                        unsigned long address, pte_t *ptep)
+5) ``void update_mmu_cache(struct vm_area_struct *vma,
+   unsigned long address, pte_t *ptep)``
 
        At the end of every page fault, this routine is invoked to
        tell the architecture specific code that a translation
@@ -100,7 +101,7 @@ changes occur:
        translations for software managed TLB configurations.
        The sparc64 port currently does this.
 
-6) void tlb_migrate_finish(struct mm_struct *mm)
+6) ``void tlb_migrate_finish(struct mm_struct *mm)``
 
        This interface is called at the end of an explicit
        process migration. This interface provides a hook
@@ -112,7 +113,7 @@ changes occur:
 
 Next, we have the cache flushing interfaces.  In general, when Linux
 is changing an existing virtual-->physical mapping to a new value,
-the sequence will be in one of the following forms:
+the sequence will be in one of the following forms::
 
        1) flush_cache_mm(mm);
           change_all_page_tables_of(mm);
@@ -143,7 +144,7 @@ and have no dependency on translation information.
 
 Here are the routines, one by one:
 
-1) void flush_cache_mm(struct mm_struct *mm)
+1) ``void flush_cache_mm(struct mm_struct *mm)``
 
        This interface flushes an entire user address space from
        the caches.  That is, after running, there will be no cache
@@ -152,7 +153,7 @@ Here are the routines, one by one:
        This interface is used to handle whole address space
        page table operations such as what happens during exit and exec.
 
-2) void flush_cache_dup_mm(struct mm_struct *mm)
+2) ``void flush_cache_dup_mm(struct mm_struct *mm)``
 
        This interface flushes an entire user address space from
        the caches.  That is, after running, there will be no cache
@@ -164,8 +165,8 @@ Here are the routines, one by one:
        This option is separate from flush_cache_mm to allow some
        optimizations for VIPT caches.
 
-3) void flush_cache_range(struct vm_area_struct *vma,
-                         unsigned long start, unsigned long end)
+3) ``void flush_cache_range(struct vm_area_struct *vma,
+   unsigned long start, unsigned long end)``
 
        Here we are flushing a specific range of (user) virtual
        addresses from the cache.  After running, there will be no
@@ -181,7 +182,7 @@ Here are the routines, one by one:
        call flush_cache_page (see below) for each entry which may be
        modified.
 
-4) void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)
+4) ``void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)``
 
        This time we need to remove a PAGE_SIZE sized range
        from the cache.  The 'vma' is the backing structure used by
@@ -202,7 +203,7 @@ Here are the routines, one by one:
 
        This is used primarily during fault processing.
 
-5) void flush_cache_kmaps(void)
+5) ``void flush_cache_kmaps(void)``
 
        This routine need only be implemented if the platform utilizes
        highmem.  It will be called right before all of the kmaps
@@ -214,8 +215,8 @@ Here are the routines, one by one:
 
        This routing should be implemented in asm/highmem.h
 
-6) void flush_cache_vmap(unsigned long start, unsigned long end)
-   void flush_cache_vunmap(unsigned long start, unsigned long end)
+6) ``void flush_cache_vmap(unsigned long start, unsigned long end)``
+   ``void flush_cache_vunmap(unsigned long start, unsigned long end)``
 
        Here in these two interfaces we are flushing a specific range
        of (kernel) virtual addresses from the cache.  After running,
@@ -243,8 +244,10 @@ size).  This setting will force the SYSv IPC layer to only allow user
 processes to mmap shared memory at address which are a multiple of
 this value.
 
-NOTE: This does not fix shared mmaps, check out the sparc64 port for
-one way to solve this (in particular SPARC_FLAG_MMAPSHARED).
+.. note::
+
+  This does not fix shared mmaps, check out the sparc64 port for
+  one way to solve this (in particular SPARC_FLAG_MMAPSHARED).
 
 Next, you have to solve the D-cache aliasing issue for all
 other cases.  Please keep in mind that fact that, for a given page
@@ -255,8 +258,8 @@ physical page into its address space, by implication the D-cache
 aliasing problem has the potential to exist since the kernel already
 maps this page at its virtual address.
 
-  void copy_user_page(void *to, void *from, unsigned long addr, struct page *page)
-  void clear_user_page(void *to, unsigned long addr, struct page *page)
+  ``void copy_user_page(void *to, void *from, unsigned long addr, struct page *page)``
+  ``void clear_user_page(void *to, unsigned long addr, struct page *page)``
 
        These two routines store data in user anonymous or COW
        pages.  It allows a port to efficiently avoid D-cache alias
@@ -276,14 +279,16 @@ maps this page at its virtual address.
        If D-cache aliasing is not an issue, these two routines may
        simply call memcpy/memset directly and do nothing more.
 
-  void flush_dcache_page(struct page *page)
+  ``void flush_dcache_page(struct page *page)``
 
        Any time the kernel writes to a page cache page, _OR_
        the kernel is about to read from a page cache page and
        user space shared/writable mappings of this page potentially
        exist, this routine is called.
 
-       NOTE: This routine need only be called for page cache pages
+       .. note::
+
+             This routine need only be called for page cache pages
              which can potentially ever be mapped into the address
              space of a user process.  So for example, VFS layer code
              handling vfs symlinks in the page cache need not call
@@ -322,18 +327,19 @@ maps this page at its virtual address.
        made of this flag bit, and if set the flush is done and the flag
        bit is cleared.
 
-       IMPORTANT NOTE: It is often important, if you defer the flush,
+       .. important::
+
+                       It is often important, if you defer the flush,
                        that the actual flush occurs on the same CPU
                        as did the cpu stores into the page to make it
                        dirty.  Again, see sparc64 for examples of how
                        to deal with this.
 
-  void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
-                         unsigned long user_vaddr,
-                         void *dst, void *src, int len)
-  void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
-                           unsigned long user_vaddr,
-                           void *dst, void *src, int len)
+  ``void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+  unsigned long user_vaddr, void *dst, void *src, int len)``
+  ``void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+  unsigned long user_vaddr, void *dst, void *src, int len)``
+
        When the kernel needs to copy arbitrary data in and out
        of arbitrary user pages (f.e. for ptrace()) it will use
        these two routines.
@@ -344,8 +350,9 @@ maps this page at its virtual address.
        likely that you will need to flush the instruction cache
        for copy_to_user_page().
 
-  void flush_anon_page(struct vm_area_struct *vma, struct page *page,
-                       unsigned long vmaddr)
+  ``void flush_anon_page(struct vm_area_struct *vma, struct page *page,
+  unsigned long vmaddr)``
+
        When the kernel needs to access the contents of an anonymous
        page, it calls this function (currently only
        get_user_pages()).  Note: flush_dcache_page() deliberately
@@ -354,7 +361,8 @@ maps this page at its virtual address.
        architectures).  For incoherent architectures, it should flush
        the cache of the page at vmaddr.
 
-  void flush_kernel_dcache_page(struct page *page)
+  ``void flush_kernel_dcache_page(struct page *page)``
+
        When the kernel needs to modify a user page is has obtained
        with kmap, it calls this function after all modifications are
        complete (but before kunmapping it) to bring the underlying
@@ -366,14 +374,16 @@ maps this page at its virtual address.
        the kernel cache for page (using page_address(page)).
 
 
-  void flush_icache_range(unsigned long start, unsigned long end)
+  ``void flush_icache_range(unsigned long start, unsigned long end)``
+
        When the kernel stores into addresses that it will execute
        out of (eg when loading modules), this function is called.
 
        If the icache does not snoop stores then this routine will need
        to flush it.
 
-  void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+  ``void flush_icache_page(struct vm_area_struct *vma, struct page *page)``
+
        All the functionality of flush_icache_page can be implemented in
        flush_dcache_page and update_mmu_cache. In the future, the hope
        is to remove this interface completely.
@@ -387,7 +397,8 @@ the kernel trying to do I/O to vmap areas must manually manage
 coherency.  It must do this by flushing the vmap range before doing
 I/O and invalidating it after the I/O returns.
 
-  void flush_kernel_vmap_range(void *vaddr, int size)
+  ``void flush_kernel_vmap_range(void *vaddr, int size)``
+
        flushes the kernel cache for a given virtual address range in
        the vmap area.  This is to make sure that any data the kernel
        modified in the vmap range is made visible to the physical
@@ -395,7 +406,8 @@ I/O and invalidating it after the I/O returns.
        Note that this API does *not* also flush the offset map alias
        of the area.
 
-  void invalidate_kernel_vmap_range(void *vaddr, int size) invalidates
+  ``void invalidate_kernel_vmap_range(void *vaddr, int size) invalidates``
+
        the cache for a given virtual address range in the vmap area
        which prevents the processor from making the cache stale by
        speculatively reading data while the I/O was occurring to the
index e610197..bde1771 100644 (file)
@@ -1,7 +1,9 @@
-
+================
 Control Group v2
+================
 
-October, 2015          Tejun Heo <tj@kernel.org>
+:Date: October, 2015
+:Author: Tejun Heo <tj@kernel.org>
 
 This is the authoritative documentation on the design, interface and
 conventions of cgroup v2.  It describes all userland-visible aspects
@@ -9,70 +11,72 @@ of cgroup including core and specific controller behaviors.  All
 future changes must be reflected in this document.  Documentation for
 v1 is available under Documentation/cgroup-v1/.
 
-CONTENTS
-
-1. Introduction
-  1-1. Terminology
-  1-2. What is cgroup?
-2. Basic Operations
-  2-1. Mounting
-  2-2. Organizing Processes
-  2-3. [Un]populated Notification
-  2-4. Controlling Controllers
-    2-4-1. Enabling and Disabling
-    2-4-2. Top-down Constraint
-    2-4-3. No Internal Process Constraint
-  2-5. Delegation
-    2-5-1. Model of Delegation
-    2-5-2. Delegation Containment
-  2-6. Guidelines
-    2-6-1. Organize Once and Control
-    2-6-2. Avoid Name Collisions
-3. Resource Distribution Models
-  3-1. Weights
-  3-2. Limits
-  3-3. Protections
-  3-4. Allocations
-4. Interface Files
-  4-1. Format
-  4-2. Conventions
-  4-3. Core Interface Files
-5. Controllers
-  5-1. CPU
-    5-1-1. CPU Interface Files
-  5-2. Memory
-    5-2-1. Memory Interface Files
-    5-2-2. Usage Guidelines
-    5-2-3. Memory Ownership
-  5-3. IO
-    5-3-1. IO Interface Files
-    5-3-2. Writeback
-  5-4. PID
-    5-4-1. PID Interface Files
-  5-5. RDMA
-    5-5-1. RDMA Interface Files
-  5-6. Misc
-    5-6-1. perf_event
-6. Namespace
-  6-1. Basics
-  6-2. The Root and Views
-  6-3. Migration and setns(2)
-  6-4. Interaction with Other Namespaces
-P. Information on Kernel Programming
-  P-1. Filesystem Support for Writeback
-D. Deprecated v1 Core Features
-R. Issues with v1 and Rationales for v2
-  R-1. Multiple Hierarchies
-  R-2. Thread Granularity
-  R-3. Competition Between Inner Nodes and Threads
-  R-4. Other Interface Issues
-  R-5. Controller Issues and Remedies
-    R-5-1. Memory
-
-
-1. Introduction
-
-1-1. Terminology
+.. CONTENTS
+
+   1. Introduction
+     1-1. Terminology
+     1-2. What is cgroup?
+   2. Basic Operations
+     2-1. Mounting
+     2-2. Organizing Processes
+     2-3. [Un]populated Notification
+     2-4. Controlling Controllers
+       2-4-1. Enabling and Disabling
+       2-4-2. Top-down Constraint
+       2-4-3. No Internal Process Constraint
+     2-5. Delegation
+       2-5-1. Model of Delegation
+       2-5-2. Delegation Containment
+     2-6. Guidelines
+       2-6-1. Organize Once and Control
+       2-6-2. Avoid Name Collisions
+   3. Resource Distribution Models
+     3-1. Weights
+     3-2. Limits
+     3-3. Protections
+     3-4. Allocations
+   4. Interface Files
+     4-1. Format
+     4-2. Conventions
+     4-3. Core Interface Files
+   5. Controllers
+     5-1. CPU
+       5-1-1. CPU Interface Files
+     5-2. Memory
+       5-2-1. Memory Interface Files
+       5-2-2. Usage Guidelines
+       5-2-3. Memory Ownership
+     5-3. IO
+       5-3-1. IO Interface Files
+       5-3-2. Writeback
+     5-4. PID
+       5-4-1. PID Interface Files
+     5-5. RDMA
+       5-5-1. RDMA Interface Files
+     5-6. Misc
+       5-6-1. perf_event
+   6. Namespace
+     6-1. Basics
+     6-2. The Root and Views
+     6-3. Migration and setns(2)
+     6-4. Interaction with Other Namespaces
+   P. Information on Kernel Programming
+     P-1. Filesystem Support for Writeback
+   D. Deprecated v1 Core Features
+   R. Issues with v1 and Rationales for v2
+     R-1. Multiple Hierarchies
+     R-2. Thread Granularity
+     R-3. Competition Between Inner Nodes and Threads
+     R-4. Other Interface Issues
+     R-5. Controller Issues and Remedies
+       R-5-1. Memory
+
+
+Introduction
+============
+
+Terminology
+-----------
 
 "cgroup" stands for "control group" and is never capitalized.  The
 singular form is used to designate the whole feature and also as a
@@ -80,7 +84,8 @@ qualifier as in "cgroup controllers".  When explicitly referring to
 multiple individual control groups, the plural form "cgroups" is used.
 
 
-1-2. What is cgroup?
+What is cgroup?
+---------------
 
 cgroup is a mechanism to organize processes hierarchically and
 distribute system resources along the hierarchy in a controlled and
@@ -110,12 +115,14 @@ restrictions set closer to the root in the hierarchy can not be
 overridden from further away.
 
 
-2. Basic Operations
+Basic Operations
+================
 
-2-1. Mounting
+Mounting
+--------
 
 Unlike v1, cgroup v2 has only single hierarchy.  The cgroup v2
-hierarchy can be mounted with the following mount command.
+hierarchy can be mounted with the following mount command::
 
   # mount -t cgroup2 none $MOUNT_POINT
 
@@ -160,10 +167,11 @@ cgroup v2 currently supports the following mount options.
        Delegation section for details.
 
 
-2-2. Organizing Processes
+Organizing Processes
+--------------------
 
 Initially, only the root cgroup exists to which all processes belong.
-A child cgroup can be created by creating a sub-directory.
+A child cgroup can be created by creating a sub-directory::
 
   # mkdir $CGROUP_NAME
 
@@ -190,28 +198,29 @@ moved to another cgroup.
 A cgroup which doesn't have any children or live processes can be
 destroyed by removing the directory.  Note that a cgroup which doesn't
 have any children and is associated only with zombie processes is
-considered empty and can be removed.
+considered empty and can be removed::
 
   # rmdir $CGROUP_NAME
 
 "/proc/$PID/cgroup" lists a process's cgroup membership.  If legacy
 cgroup is in use in the system, this file may contain multiple lines,
 one for each hierarchy.  The entry for cgroup v2 is always in the
-format "0::$PATH".
+format "0::$PATH"::
 
   # cat /proc/842/cgroup
   ...
   0::/test-cgroup/test-cgroup-nested
 
 If the process becomes a zombie and the cgroup it was associated with
-is removed subsequently, " (deleted)" is appended to the path.
+is removed subsequently, " (deleted)" is appended to the path::
 
   # cat /proc/842/cgroup
   ...
   0::/test-cgroup/test-cgroup-nested (deleted)
 
 
-2-3. [Un]populated Notification
+[Un]populated Notification
+--------------------------
 
 Each non-root cgroup has a "cgroup.events" file which contains
 "populated" field indicating whether the cgroup's sub-hierarchy has
@@ -222,7 +231,7 @@ example, to start a clean-up operation after all processes of a given
 sub-hierarchy have exited.  The populated state updates and
 notifications are recursive.  Consider the following sub-hierarchy
 where the numbers in the parentheses represent the numbers of processes
-in each cgroup.
+in each cgroup::
 
   A(4) - B(0) - C(1)
               \ D(0)
@@ -233,18 +242,20 @@ file modified events will be generated on the "cgroup.events" files of
 both cgroups.
 
 
-2-4. Controlling Controllers
+Controlling Controllers
+-----------------------
 
-2-4-1. Enabling and Disabling
+Enabling and Disabling
+~~~~~~~~~~~~~~~~~~~~~~
 
 Each cgroup has a "cgroup.controllers" file which lists all
-controllers available for the cgroup to enable.
+controllers available for the cgroup to enable::
 
   # cat cgroup.controllers
   cpu io memory
 
 No controller is enabled by default.  Controllers can be enabled and
-disabled by writing to the "cgroup.subtree_control" file.
+disabled by writing to the "cgroup.subtree_control" file::
 
   # echo "+cpu +memory -io" > cgroup.subtree_control
 
@@ -256,7 +267,7 @@ are specified, the last one is effective.
 Enabling a controller in a cgroup indicates that the distribution of
 the target resource across its immediate children will be controlled.
 Consider the following sub-hierarchy.  The enabled controllers are
-listed in parentheses.
+listed in parentheses::
 
   A(cpu,memory) - B(memory) - C()
                             \ D()
@@ -276,7 +287,8 @@ controller interface files - anything which doesn't start with
 "cgroup." are owned by the parent rather than the cgroup itself.
 
 
-2-4-2. Top-down Constraint
+Top-down Constraint
+~~~~~~~~~~~~~~~~~~~
 
 Resources are distributed top-down and a cgroup can further distribute
 a resource only if the resource has been distributed to it from the
@@ -287,7 +299,8 @@ the parent has the controller enabled and a controller can't be
 disabled if one or more children have it enabled.
 
 
-2-4-3. No Internal Process Constraint
+No Internal Process Constraint
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Non-root cgroups can only distribute resources to their children when
 they don't have any processes of their own.  In other words, only
@@ -314,9 +327,11 @@ children before enabling controllers in its "cgroup.subtree_control"
 file.
 
 
-2-5. Delegation
+Delegation
+----------
 
-2-5-1. Model of Delegation
+Model of Delegation
+~~~~~~~~~~~~~~~~~~~
 
 A cgroup can be delegated in two ways.  First, to a less privileged
 user by granting write access of the directory and its "cgroup.procs"
@@ -345,7 +360,8 @@ cgroups in or nesting depth of a delegated sub-hierarchy; however,
 this may be limited explicitly in the future.
 
 
-2-5-2. Delegation Containment
+Delegation Containment
+~~~~~~~~~~~~~~~~~~~~~~
 
 A delegated sub-hierarchy is contained in the sense that processes
 can't be moved into or out of the sub-hierarchy by the delegatee.
@@ -366,7 +382,7 @@ in from or push out to outside the sub-hierarchy.
 
 For an example, let's assume cgroups C0 and C1 have been delegated to
 user U0 who created C00, C01 under C0 and C10 under C1 as follows and
-all processes under C0 and C1 belong to U0.
+all processes under C0 and C1 belong to U0::
 
   ~~~~~~~~~~~~~ - C0 - C00
   ~ cgroup    ~      \ C01
@@ -386,9 +402,11 @@ namespace of the process which is attempting the migration.  If either
 is not reachable, the migration is rejected with -ENOENT.
 
 
-2-6. Guidelines
+Guidelines
+----------
 
-2-6-1. Organize Once and Control
+Organize Once and Control
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Migrating a process across cgroups is a relatively expensive operation
 and stateful resources such as memory are not moved together with the
@@ -404,7 +422,8 @@ distribution can be made by changing controller configuration through
 the interface files.
 
 
-2-6-2. Avoid Name Collisions
+Avoid Name Collisions
+~~~~~~~~~~~~~~~~~~~~~
 
 Interface files for a cgroup and its children cgroups occupy the same
 directory and it is possible to create children cgroups which collide
@@ -422,14 +441,16 @@ cgroup doesn't do anything to prevent name collisions and it's the
 user's responsibility to avoid them.
 
 
-3. Resource Distribution Models
+Resource Distribution Models
+============================
 
 cgroup controllers implement several resource distribution schemes
 depending on the resource type and expected use cases.  This section
 describes major schemes in use along with their expected behaviors.
 
 
-3-1. Weights
+Weights
+-------
 
 A parent's resource is distributed by adding up the weights of all
 active children and giving each the fraction matching the ratio of its
@@ -450,7 +471,8 @@ process migrations.
 and is an example of this type.
 
 
-3-2. Limits
+Limits
+------
 
 A child can only consume upto the configured amount of the resource.
 Limits can be over-committed - the sum of the limits of children can
@@ -466,7 +488,8 @@ process migrations.
 on an IO device and is an example of this type.
 
 
-3-3. Protections
+Protections
+-----------
 
 A cgroup is protected to be allocated upto the configured amount of
 the resource if the usages of all its ancestors are under their
@@ -486,7 +509,8 @@ process migrations.
 example of this type.
 
 
-3-4. Allocations
+Allocations
+-----------
 
 A cgroup is exclusively allocated a certain amount of a finite
 resource.  Allocations can't be over-committed - the sum of the
@@ -505,12 +529,14 @@ may be rejected.
 type.
 
 
-4. Interface Files
+Interface Files
+===============
 
-4-1. Format
+Format
+------
 
 All interface files should be in one of the following formats whenever
-possible.
+possible::
 
   New-line separated values
   (when only one value can be written at once)
@@ -545,7 +571,8 @@ can be written at a time.  For nested keyed files, the sub key pairs
 may be specified in any order and not all pairs have to be specified.
 
 
-4-2. Conventions
+Conventions
+-----------
 
 - Settings for a single feature should be contained in a single file.
 
@@ -581,25 +608,25 @@ may be specified in any order and not all pairs have to be specified.
   with "default" as the value must not appear when read.
 
   For example, a setting which is keyed by major:minor device numbers
-  with integer values may look like the following.
+  with integer values may look like the following::
 
     # cat cgroup-example-interface-file
     default 150
     8:0 300
 
-  The default value can be updated by
+  The default value can be updated by::
 
     # echo 125 > cgroup-example-interface-file
 
-  or
+  or::
 
     # echo "default 125" > cgroup-example-interface-file
 
-  An override can be set by
+  An override can be set by::
 
     # echo "8:16 170" > cgroup-example-interface-file
 
-  and cleared by
+  and cleared by::
 
     # echo "8:0 default" > cgroup-example-interface-file
     # cat cgroup-example-interface-file
@@ -612,12 +639,12 @@ may be specified in any order and not all pairs have to be specified.
   generated on the file.
 
 
-4-3. Core Interface Files
+Core Interface Files
+--------------------
 
 All cgroup core files are prefixed with "cgroup."
 
   cgroup.procs
-
        A read-write new-line separated values file which exists on
        all cgroups.
 
@@ -643,7 +670,6 @@ All cgroup core files are prefixed with "cgroup."
        should be granted along with the containing directory.
 
   cgroup.controllers
-
        A read-only space separated values file which exists on all
        cgroups.
 
@@ -651,7 +677,6 @@ All cgroup core files are prefixed with "cgroup."
        the cgroup.  The controllers are not ordered.
 
   cgroup.subtree_control
-
        A read-write space separated values file which exists on all
        cgroups.  Starts out empty.
 
@@ -667,23 +692,25 @@ All cgroup core files are prefixed with "cgroup."
        operations are specified, either all succeed or all fail.
 
   cgroup.events
-
        A read-only flat-keyed file which exists on non-root cgroups.
        The following entries are defined.  Unless specified
        otherwise, a value change in this file generates a file
        modified event.
 
          populated
-
                1 if the cgroup or its descendants contains any live
                processes; otherwise, 0.
 
 
-5. Controllers
+Controllers
+===========
 
-5-1. CPU
+CPU
+---
 
-[NOTE: The interface for the cpu controller hasn't been merged yet]
+.. note::
+
+       The interface for the cpu controller hasn't been merged yet
 
 The "cpu" controllers regulates distribution of CPU cycles.  This
 controller implements weight and absolute bandwidth limit models for
@@ -691,36 +718,34 @@ normal scheduling policy and absolute bandwidth allocation model for
 realtime scheduling policy.
 
 
-5-1-1. CPU Interface Files
+CPU Interface Files
+~~~~~~~~~~~~~~~~~~~
 
 All time durations are in microseconds.
 
   cpu.stat
-
        A read-only flat-keyed file which exists on non-root cgroups.
 
-       It reports the following six stats.
+       It reports the following six stats:
 
-         usage_usec
-         user_usec
-         system_usec
-         nr_periods
-         nr_throttled
-         throttled_usec
+       - usage_usec
+       - user_usec
+       - system_usec
+       - nr_periods
+       - nr_throttled
+       - throttled_usec
 
   cpu.weight
-
        A read-write single value file which exists on non-root
        cgroups.  The default is "100".
 
        The weight in the range [1, 10000].
 
   cpu.max
-
        A read-write two value file which exists on non-root cgroups.
        The default is "max 100000".
 
-       The maximum bandwidth limit.  It's in the following format.
+       The maximum bandwidth limit.  It's in the following format::
 
          $MAX $PERIOD
 
@@ -729,9 +754,10 @@ All time durations are in microseconds.
        one number is written, $MAX is updated.
 
   cpu.rt.max
+       .. note::
 
-  [NOTE: The semantics of this file is still under discussion and the
-   interface hasn't been merged yet]
+          The semantics of this file is still under discussion and the
+          interface hasn't been merged yet
 
        A read-write two value file which exists on all cgroups.
        The default is "0 100000".
@@ -739,7 +765,7 @@ All time durations are in microseconds.
        The maximum realtime runtime allocation.  Over-committing
        configurations are disallowed and process migrations are
        rejected if not enough bandwidth is available.  It's in the
-       following format.
+       following format::
 
          $MAX $PERIOD
 
@@ -748,7 +774,8 @@ All time durations are in microseconds.
        updated.
 
 
-5-2. Memory
+Memory
+------
 
 The "memory" controller regulates distribution of memory.  Memory is
 stateful and implements both limit and protection models.  Due to the
@@ -770,14 +797,14 @@ following types of memory usages are tracked.
 The above list may expand in the future for better coverage.
 
 
-5-2-1. Memory Interface Files
+Memory Interface Files
+~~~~~~~~~~~~~~~~~~~~~~
 
 All memory amounts are in bytes.  If a value which is not aligned to
 PAGE_SIZE is written, the value may be rounded up to the closest
 PAGE_SIZE multiple when read back.
 
   memory.current
-
        A read-only single value file which exists on non-root
        cgroups.
 
@@ -785,7 +812,6 @@ PAGE_SIZE multiple when read back.
        and its descendants.
 
   memory.low
-
        A read-write single value file which exists on non-root
        cgroups.  The default is "0".
 
@@ -798,7 +824,6 @@ PAGE_SIZE multiple when read back.
        protection is discouraged.
 
   memory.high
-
        A read-write single value file which exists on non-root
        cgroups.  The default is "max".
 
@@ -811,7 +836,6 @@ PAGE_SIZE multiple when read back.
        under extreme conditions the limit may be breached.
 
   memory.max
-
        A read-write single value file which exists on non-root
        cgroups.  The default is "max".
 
@@ -826,21 +850,18 @@ PAGE_SIZE multiple when read back.
        utility is limited to providing the final safety net.
 
   memory.events
-
        A read-only flat-keyed file which exists on non-root cgroups.
        The following entries are defined.  Unless specified
        otherwise, a value change in this file generates a file
        modified event.
 
          low
-
                The number of times the cgroup is reclaimed due to
                high memory pressure even though its usage is under
                the low boundary.  This usually indicates that the low
                boundary is over-committed.
 
          high
-
                The number of times processes of the cgroup are
                throttled and routed to perform direct memory reclaim
                because the high memory boundary was exceeded.  For a
@@ -849,13 +870,11 @@ PAGE_SIZE multiple when read back.
                occurrences are expected.
 
          max
-
                The number of times the cgroup's memory usage was
                about to go over the max boundary.  If direct reclaim
                fails to bring it down, the cgroup goes to OOM state.
 
          oom
-
                The number of time the cgroup's memory usage was
                reached the limit and allocation was about to fail.
 
@@ -864,16 +883,14 @@ PAGE_SIZE multiple when read back.
 
                Failed allocation in its turn could be returned into
                userspace as -ENOMEM or siletly ignored in cases like
-               disk readahead.  For now OOM in memory cgroup kills
+               disk readahead.  For now OOM in memory cgroup kills
                tasks iff shortage has happened inside page fault.
 
          oom_kill
-
                The number of processes belonging to this cgroup
                killed by any kind of OOM killer.
 
   memory.stat
-
        A read-only flat-keyed file which exists on non-root cgroups.
 
        This breaks down the cgroup's memory footprint into different
@@ -887,73 +904,55 @@ PAGE_SIZE multiple when read back.
        fixed position; use the keys to look up specific values!
 
          anon
-
                Amount of memory used in anonymous mappings such as
                brk(), sbrk(), and mmap(MAP_ANONYMOUS)
 
          file
-
                Amount of memory used to cache filesystem data,
                including tmpfs and shared memory.
 
          kernel_stack
-
                Amount of memory allocated to kernel stacks.
 
          slab
-
                Amount of memory used for storing in-kernel data
                structures.
 
          sock
-
                Amount of memory used in network transmission buffers
 
          shmem
-
                Amount of cached filesystem data that is swap-backed,
                such as tmpfs, shm segments, shared anonymous mmap()s
 
          file_mapped
-
                Amount of cached filesystem data mapped with mmap()
 
          file_dirty
-
                Amount of cached filesystem data that was modified but
                not yet written back to disk
 
          file_writeback
-
                Amount of cached filesystem data that was modified and
                is currently being written back to disk
 
-         inactive_anon
-         active_anon
-         inactive_file
-         active_file
-         unevictable
-
+         inactive_anon, active_anon, inactive_file, active_file, unevictable
                Amount of memory, swap-backed and filesystem-backed,
                on the internal memory management lists used by the
                page reclaim algorithm
 
          slab_reclaimable
-
                Part of "slab" that might be reclaimed, such as
                dentries and inodes.
 
          slab_unreclaimable
-
                Part of "slab" that cannot be reclaimed on memory
                pressure.
 
          pgfault
-
                Total number of page faults incurred
 
          pgmajfault
-
                Number of major page faults incurred
 
          workingset_refault
@@ -997,7 +996,6 @@ PAGE_SIZE multiple when read back.
                Amount of reclaimed lazyfree pages
 
   memory.swap.current
-
        A read-only single value file which exists on non-root
        cgroups.
 
@@ -1005,7 +1003,6 @@ PAGE_SIZE multiple when read back.
        and its descendants.
 
   memory.swap.max
-
        A read-write single value file which exists on non-root
        cgroups.  The default is "max".
 
@@ -1013,7 +1010,8 @@ PAGE_SIZE multiple when read back.
        limit, anonymous meomry of the cgroup will not be swapped out.
 
 
-5-2-2. Usage Guidelines
+Usage Guidelines
+~~~~~~~~~~~~~~~~
 
 "memory.high" is the main mechanism to control memory usage.
 Over-committing on high limit (sum of high limits > available memory)
@@ -1036,7 +1034,8 @@ memory; unfortunately, memory pressure monitoring mechanism isn't
 implemented yet.
 
 
-5-2-3. Memory Ownership
+Memory Ownership
+~~~~~~~~~~~~~~~~
 
 A memory area is charged to the cgroup which instantiated it and stays
 charged to the cgroup until the area is released.  Migrating a process
@@ -1054,7 +1053,8 @@ POSIX_FADV_DONTNEED to relinquish the ownership of memory areas
 belonging to the affected files to ensure correct memory ownership.
 
 
-5-3. IO
+IO
+--
 
 The "io" controller regulates the distribution of IO resources.  This
 controller implements both weight based and absolute bandwidth or IOPS
@@ -1063,28 +1063,29 @@ only if cfq-iosched is in use and neither scheme is available for
 blk-mq devices.
 
 
-5-3-1. IO Interface Files
+IO Interface Files
+~~~~~~~~~~~~~~~~~~
 
   io.stat
-
        A read-only nested-keyed file which exists on non-root
        cgroups.
 
        Lines are keyed by $MAJ:$MIN device numbers and not ordered.
        The following nested keys are defined.
 
+         ======        ===================
          rbytes        Bytes read
          wbytes        Bytes written
          rios          Number of read IOs
          wios          Number of write IOs
+         ======        ===================
 
-       An example read output follows.
+       An example read output follows:
 
          8:16 rbytes=1459200 wbytes=314773504 rios=192 wios=353
          8:0 rbytes=90430464 wbytes=299008000 rios=8950 wios=1252
 
   io.weight
-
        A read-write flat-keyed file which exists on non-root cgroups.
        The default is "default 100".
 
@@ -1098,14 +1099,13 @@ blk-mq devices.
        $WEIGHT" or simply "$WEIGHT".  Overrides can be set by writing
        "$MAJ:$MIN $WEIGHT" and unset by writing "$MAJ:$MIN default".
 
-       An example read output follows.
+       An example read output follows::
 
          default 100
          8:16 200
          8:0 50
 
   io.max
-
        A read-write nested-keyed file which exists on non-root
        cgroups.
 
@@ -1113,10 +1113,12 @@ blk-mq devices.
        device numbers and not ordered.  The following nested keys are
        defined.
 
+         =====         ==================================
          rbps          Max read bytes per second
          wbps          Max write bytes per second
          riops         Max read IO operations per second
          wiops         Max write IO operations per second
+         =====         ==================================
 
        When writing, any number of nested key-value pairs can be
        specified in any order.  "max" can be specified as the value
@@ -1126,24 +1128,25 @@ blk-mq devices.
        BPS and IOPS are measured in each IO direction and IOs are
        delayed if limit is reached.  Temporary bursts are allowed.
 
-       Setting read limit at 2M BPS and write at 120 IOPS for 8:16.
+       Setting read limit at 2M BPS and write at 120 IOPS for 8:16::
 
          echo "8:16 rbps=2097152 wiops=120" > io.max
 
-       Reading returns the following.
+       Reading returns the following::
 
          8:16 rbps=2097152 wbps=max riops=max wiops=120
 
-       Write IOPS limit can be removed by writing the following.
+       Write IOPS limit can be removed by writing the following::
 
          echo "8:16 wiops=max" > io.max
 
-       Reading now returns the following.
+       Reading now returns the following::
 
          8:16 rbps=2097152 wbps=max riops=max wiops=max
 
 
-5-3-2. Writeback
+Writeback
+~~~~~~~~~
 
 Page cache is dirtied through buffered writes and shared mmaps and
 written asynchronously to the backing filesystem by the writeback
@@ -1191,22 +1194,19 @@ patterns.
 The sysctl knobs which affect writeback behavior are applied to cgroup
 writeback as follows.
 
-  vm.dirty_background_ratio
-  vm.dirty_ratio
-
+  vm.dirty_background_ratio, vm.dirty_ratio
        These ratios apply the same to cgroup writeback with the
        amount of available memory capped by limits imposed by the
        memory controller and system-wide clean memory.
 
-  vm.dirty_background_bytes
-  vm.dirty_bytes
-
+  vm.dirty_background_bytes, vm.dirty_bytes
        For cgroup writeback, this is calculated into ratio against
        total available memory and applied the same way as
        vm.dirty[_background]_ratio.
 
 
-5-4. PID
+PID
+---
 
 The process number controller is used to allow a cgroup to stop any
 new tasks from being fork()'d or clone()'d after a specified limit is
@@ -1221,17 +1221,16 @@ Note that PIDs used in this controller refer to TIDs, process IDs as
 used by the kernel.
 
 
-5-4-1. PID Interface Files
+PID Interface Files
+~~~~~~~~~~~~~~~~~~~
 
   pids.max
-
        A read-write single value file which exists on non-root
        cgroups.  The default is "max".
 
        Hard limit of number of processes.
 
   pids.current
-
        A read-only single value file which exists on all cgroups.
 
        The number of processes currently in the cgroup and its
@@ -1246,12 +1245,14 @@ through fork() or clone(). These will return -EAGAIN if the creation
 of a new process would cause a cgroup policy to be violated.
 
 
-5-5. RDMA
+RDMA
+----
 
 The "rdma" controller regulates the distribution and accounting of
 of RDMA resources.
 
-5-5-1. RDMA Interface Files
+RDMA Interface Files
+~~~~~~~~~~~~~~~~~~~~
 
   rdma.max
        A readwrite nested-keyed file that exists for all the cgroups
@@ -1264,10 +1265,12 @@ of RDMA resources.
 
        The following nested keys are defined.
 
+         ==========    =============================
          hca_handle    Maximum number of HCA Handles
          hca_object    Maximum number of HCA Objects
+         ==========    =============================
 
-       An example for mlx4 and ocrdma device follows.
+       An example for mlx4 and ocrdma device follows::
 
          mlx4_0 hca_handle=2 hca_object=2000
          ocrdma1 hca_handle=3 hca_object=max
@@ -1276,15 +1279,17 @@ of RDMA resources.
        A read-only file that describes current resource usage.
        It exists for all the cgroup except root.
 
-       An example for mlx4 and ocrdma device follows.
+       An example for mlx4 and ocrdma device follows::
 
          mlx4_0 hca_handle=1 hca_object=20
          ocrdma1 hca_handle=1 hca_object=23
 
 
-5-6. Misc
+Misc
+----
 
-5-6-1. perf_event
+perf_event
+~~~~~~~~~~
 
 perf_event controller, if not mounted on a legacy hierarchy, is
 automatically enabled on the v2 hierarchy so that perf events can
@@ -1292,9 +1297,11 @@ always be filtered by cgroup v2 path.  The controller can still be
 moved to a legacy hierarchy after v2 hierarchy is populated.
 
 
-6. Namespace
+Namespace
+=========
 
-6-1. Basics
+Basics
+------
 
 cgroup namespace provides a mechanism to virtualize the view of the
 "/proc/$PID/cgroup" file and cgroup mounts.  The CLONE_NEWCGROUP clone
@@ -1308,7 +1315,7 @@ Without cgroup namespace, the "/proc/$PID/cgroup" file shows the
 complete path of the cgroup of a process.  In a container setup where
 a set of cgroups and namespaces are intended to isolate processes the
 "/proc/$PID/cgroup" file may leak potential system level information
-to the isolated processes.  For Example:
+to the isolated processes.  For Example::
 
   # cat /proc/self/cgroup
   0::/batchjobs/container_id1
@@ -1316,14 +1323,14 @@ to the isolated processes.  For Example:
 The path '/batchjobs/container_id1' can be considered as system-data
 and undesirable to expose to the isolated processes.  cgroup namespace
 can be used to restrict visibility of this path.  For example, before
-creating a cgroup namespace, one would see:
+creating a cgroup namespace, one would see::
 
   # ls -l /proc/self/ns/cgroup
   lrwxrwxrwx 1 root root 0 2014-07-15 10:37 /proc/self/ns/cgroup -> cgroup:[4026531835]
   # cat /proc/self/cgroup
   0::/batchjobs/container_id1
 
-After unsharing a new namespace, the view changes.
+After unsharing a new namespace, the view changes::
 
   # ls -l /proc/self/ns/cgroup
   lrwxrwxrwx 1 root root 0 2014-07-15 10:35 /proc/self/ns/cgroup -> cgroup:[4026532183]
@@ -1341,7 +1348,8 @@ namespace is destroyed.  The cgroupns root and the actual cgroups
 remain.
 
 
-6-2. The Root and Views
+The Root and Views
+------------------
 
 The 'cgroupns root' for a cgroup namespace is the cgroup in which the
 process calling unshare(2) is running.  For example, if a process in
@@ -1350,7 +1358,7 @@ process calling unshare(2) is running.  For example, if a process in
 init_cgroup_ns, this is the real root ('/') cgroup.
 
 The cgroupns root cgroup does not change even if the namespace creator
-process later moves to a different cgroup.
+process later moves to a different cgroup::
 
   # ~/unshare -c # unshare cgroupns in some cgroup
   # cat /proc/self/cgroup
@@ -1364,7 +1372,7 @@ Each process gets its namespace-specific view of "/proc/$PID/cgroup"
 
 Processes running inside the cgroup namespace will be able to see
 cgroup paths (in /proc/self/cgroup) only inside their root cgroup.
-From within an unshared cgroupns:
+From within an unshared cgroupns::
 
   # sleep 100000 &
   [1] 7353
@@ -1373,7 +1381,7 @@ From within an unshared cgroupns:
   0::/sub_cgrp_1
 
 From the initial cgroup namespace, the real cgroup path will be
-visible:
+visible::
 
   $ cat /proc/7353/cgroup
   0::/batchjobs/container_id1/sub_cgrp_1
@@ -1381,7 +1389,7 @@ visible:
 From a sibling cgroup namespace (that is, a namespace rooted at a
 different cgroup), the cgroup path relative to its own cgroup
 namespace root will be shown.  For instance, if PID 7353's cgroup
-namespace root is at '/batchjobs/container_id2', then it will see
+namespace root is at '/batchjobs/container_id2', then it will see::
 
   # cat /proc/7353/cgroup
   0::/../container_id2/sub_cgrp_1
@@ -1390,13 +1398,14 @@ Note that the relative path always starts with '/' to indicate that
 its relative to the cgroup namespace root of the caller.
 
 
-6-3. Migration and setns(2)
+Migration and setns(2)
+----------------------
 
 Processes inside a cgroup namespace can move into and out of the
 namespace root if they have proper access to external cgroups.  For
 example, from inside a namespace with cgroupns root at
 /batchjobs/container_id1, and assuming that the global hierarchy is
-still accessible inside cgroupns:
+still accessible inside cgroupns::
 
   # cat /proc/7353/cgroup
   0::/sub_cgrp_1
@@ -1418,10 +1427,11 @@ namespace.  It is expected that the someone moves the attaching
 process under the target cgroup namespace root.
 
 
-6-4. Interaction with Other Namespaces
+Interaction with Other Namespaces
+---------------------------------
 
 Namespace specific cgroup hierarchy can be mounted by a process
-running inside a non-init cgroup namespace.
+running inside a non-init cgroup namespace::
 
   # mount -t cgroup2 none $MOUNT_POINT
 
@@ -1434,27 +1444,27 @@ the view of cgroup hierarchy by namespace-private cgroupfs mount
 provides a properly isolated cgroup view inside the container.
 
 
-P. Information on Kernel Programming
+Information on Kernel Programming
+=================================
 
 This section contains kernel programming information in the areas
 where interacting with cgroup is necessary.  cgroup core and
 controllers are not covered.
 
 
-P-1. Filesystem Support for Writeback
+Filesystem Support for Writeback
+--------------------------------
 
 A filesystem can support cgroup writeback by updating
 address_space_operations->writepage[s]() to annotate bio's using the
 following two functions.
 
   wbc_init_bio(@wbc, @bio)
-
        Should be called for each bio carrying writeback data and
        associates the bio with the inode's owner cgroup.  Can be
        called anytime between bio allocation and submission.
 
   wbc_account_io(@wbc, @page, @bytes)
-
        Should be called for each data segment being written out.
        While this function doesn't care exactly when it's called
        during the writeback session, it's the easiest and most
@@ -1475,7 +1485,8 @@ cases by skipping wbc_init_bio() or using bio_associate_blkcg()
 directly.
 
 
-D. Deprecated v1 Core Features
+Deprecated v1 Core Features
+===========================
 
 - Multiple hierarchies including named ones are not supported.
 
@@ -1489,9 +1500,11 @@ D. Deprecated v1 Core Features
   at the root instead.
 
 
-R. Issues with v1 and Rationales for v2
+Issues with v1 and Rationales for v2
+====================================
 
-R-1. Multiple Hierarchies
+Multiple Hierarchies
+--------------------
 
 cgroup v1 allowed an arbitrary number of hierarchies and each
 hierarchy could host any number of controllers.  While this seemed to
@@ -1543,7 +1556,8 @@ how memory is distributed beyond a certain level while still wanting
 to control how CPU cycles are distributed.
 
 
-R-2. Thread Granularity
+Thread Granularity
+------------------
 
 cgroup v1 allowed threads of a process to belong to different cgroups.
 This didn't make sense for some controllers and those controllers
@@ -1586,7 +1600,8 @@ misbehaving and poorly abstracted interfaces and kernel exposing and
 locked into constructs inadvertently.
 
 
-R-3. Competition Between Inner Nodes and Threads
+Competition Between Inner Nodes and Threads
+-------------------------------------------
 
 cgroup v1 allowed threads to be in any cgroups which created an
 interesting problem where threads belonging to a parent cgroup and its
@@ -1605,7 +1620,7 @@ simply weren't available for threads.
 
 The io controller implicitly created a hidden leaf node for each
 cgroup to host the threads.  The hidden leaf had its own copies of all
-the knobs with "leaf_" prefixed.  While this allowed equivalent
+the knobs with ``leaf_`` prefixed.  While this allowed equivalent
 control over internal threads, it was with serious drawbacks.  It
 always added an extra layer of nesting which wouldn't be necessary
 otherwise, made the interface messy and significantly complicated the
@@ -1626,7 +1641,8 @@ This clearly is a problem which needs to be addressed from cgroup core
 in a uniform way.
 
 
-R-4. Other Interface Issues
+Other Interface Issues
+----------------------
 
 cgroup v1 grew without oversight and developed a large number of
 idiosyncrasies and inconsistencies.  One issue on the cgroup core side
@@ -1654,9 +1670,11 @@ cgroup v2 establishes common conventions where appropriate and updates
 controllers so that they expose minimal and consistent interfaces.
 
 
-R-5. Controller Issues and Remedies
+Controller Issues and Remedies
+------------------------------
 
-R-5-1. Memory
+Memory
+~~~~~~
 
 The original lower boundary, the soft limit, is defined as a limit
 that is per default unset.  As a result, the set of cgroups that
index 4a824d2..d462817 100644 (file)
@@ -1,9 +1,9 @@
-                              ================
-                              CIRCULAR BUFFERS
-                              ================
+================
+Circular Buffers
+================
 
-By: David Howells <dhowells@redhat.com>
-    Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+:Author: David Howells <dhowells@redhat.com>
+:Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
 
 
 Linux provides a number of features that can be used to implement circular
@@ -20,7 +20,7 @@ producer and just one consumer.  It is possible to handle multiple producers by
 serialising them, and to handle multiple consumers by serialising them.
 
 
-Contents:
+.. Contents:
 
  (*) What is a circular buffer?
 
@@ -31,8 +31,8 @@ Contents:
      - The consumer.
 
 
-==========================
-WHAT IS A CIRCULAR BUFFER?
+
+What is a circular buffer?
 ==========================
 
 First of all, what is a circular buffer?  A circular buffer is a buffer of
@@ -60,9 +60,7 @@ buffer, provided that neither index overtakes the other.  The implementer must
 be careful, however, as a region more than one unit in size may wrap the end of
 the buffer and be broken into two segments.
 
-
-============================
-MEASURING POWER-OF-2 BUFFERS
+Measuring power-of-2 buffers
 ============================
 
 Calculation of the occupancy or the remaining capacity of an arbitrarily sized
@@ -71,13 +69,13 @@ modulus (divide) instruction.  However, if the buffer is of a power-of-2 size,
 then a much quicker bitwise-AND instruction can be used instead.
 
 Linux provides a set of macros for handling power-of-2 circular buffers.  These
-can be made use of by:
+can be made use of by::
 
        #include <linux/circ_buf.h>
 
 The macros are:
 
- (*) Measure the remaining capacity of a buffer:
+ (#) Measure the remaining capacity of a buffer::
 
        CIRC_SPACE(head_index, tail_index, buffer_size);
 
@@ -85,7 +83,7 @@ The macros are:
      can be inserted.
 
 
- (*) Measure the maximum consecutive immediate space in a buffer:
+ (#) Measure the maximum consecutive immediate space in a buffer::
 
        CIRC_SPACE_TO_END(head_index, tail_index, buffer_size);
 
@@ -94,14 +92,14 @@ The macros are:
      beginning of the buffer.
 
 
- (*) Measure the occupancy of a buffer:
+ (#) Measure the occupancy of a buffer::
 
        CIRC_CNT(head_index, tail_index, buffer_size);
 
      This returns the number of items currently occupying a buffer[2].
 
 
- (*) Measure the non-wrapping occupancy of a buffer:
+ (#) Measure the non-wrapping occupancy of a buffer::
 
        CIRC_CNT_TO_END(head_index, tail_index, buffer_size);
 
@@ -112,7 +110,7 @@ The macros are:
 Each of these macros will nominally return a value between 0 and buffer_size-1,
 however:
 
[1] CIRC_SPACE*() are intended to be used in the producer.  To the producer
(1) CIRC_SPACE*() are intended to be used in the producer.  To the producer
      they will return a lower bound as the producer controls the head index,
      but the consumer may still be depleting the buffer on another CPU and
      moving the tail index.
@@ -120,7 +118,7 @@ however:
      To the consumer it will show an upper bound as the producer may be busy
      depleting the space.
 
[2] CIRC_CNT*() are intended to be used in the consumer.  To the consumer they
(2) CIRC_CNT*() are intended to be used in the consumer.  To the consumer they
      will return a lower bound as the consumer controls the tail index, but the
      producer may still be filling the buffer on another CPU and moving the
      head index.
@@ -128,14 +126,12 @@ however:
      To the producer it will show an upper bound as the consumer may be busy
      emptying the buffer.
 
[3] To a third party, the order in which the writes to the indices by the
(3) To a third party, the order in which the writes to the indices by the
      producer and consumer become visible cannot be guaranteed as they are
      independent and may be made on different CPUs - so the result in such a
      situation will merely be a guess, and may even be negative.
 
-
-===========================================
-USING MEMORY BARRIERS WITH CIRCULAR BUFFERS
+Using memory barriers with circular buffers
 ===========================================
 
 By using memory barriers in conjunction with circular buffers, you can avoid
@@ -152,10 +148,10 @@ time, and only one thing should be emptying a buffer at any one time, but the
 two sides can operate simultaneously.
 
 
-THE PRODUCER
+The producer
 ------------
 
-The producer will look something like this:
+The producer will look something like this::
 
        spin_lock(&producer_lock);
 
@@ -193,10 +189,10 @@ ordering between the read of the index indicating that the consumer has
 vacated a given element and the write by the producer to that same element.
 
 
-THE CONSUMER
+The Consumer
 ------------
 
-The consumer will look something like this:
+The consumer will look something like this::
 
        spin_lock(&consumer_lock);
 
@@ -235,8 +231,7 @@ prevents the compiler from tearing the store, and enforces ordering
 against previous accesses.
 
 
-===============
-FURTHER READING
+Further reading
 ===============
 
 See also Documentation/memory-barriers.txt for a description of Linux's memory
index 22f026a..be909ed 100644 (file)
@@ -1,12 +1,16 @@
-               The Common Clk Framework
-               Mike Turquette <mturquette@ti.com>
+========================
+The Common Clk Framework
+========================
+
+:Author: Mike Turquette <mturquette@ti.com>
 
 This document endeavours to explain the common clk framework details,
 and how to port a platform over to this framework.  It is not yet a
 detailed explanation of the clock api in include/linux/clk.h, but
 perhaps someday it will include that information.
 
-       Part 1 - introduction and interface split
+Introduction and interface split
+================================
 
 The common clk framework is an interface to control the clock nodes
 available on various devices today.  This may come in the form of clock
@@ -35,10 +39,11 @@ is defined in struct clk_foo and pointed to within struct clk_core.  This
 allows for easy navigation between the two discrete halves of the common
 clock interface.
 
-       Part 2 - common data structures and api
+Common data structures and api
+==============================
 
 Below is the common struct clk_core definition from
-drivers/clk/clk.c, modified for brevity:
+drivers/clk/clk.c, modified for brevity::
 
        struct clk_core {
                const char              *name;
@@ -59,7 +64,7 @@ struct clk.  That api is documented in include/linux/clk.h.
 
 Platforms and devices utilizing the common struct clk_core use the struct
 clk_ops pointer in struct clk_core to perform the hardware-specific parts of
-the operations defined in clk-provider.h:
+the operations defined in clk-provider.h::
 
        struct clk_ops {
                int             (*prepare)(struct clk_hw *hw);
@@ -95,19 +100,20 @@ the operations defined in clk-provider.h:
                                              struct dentry *dentry);
        };
 
-       Part 3 - hardware clk implementations
+Hardware clk implementations
+============================
 
 The strength of the common struct clk_core comes from its .ops and .hw pointers
 which abstract the details of struct clk from the hardware-specific bits, and
 vice versa.  To illustrate consider the simple gateable clk implementation in
-drivers/clk/clk-gate.c:
+drivers/clk/clk-gate.c::
 
-struct clk_gate {
-       struct clk_hw   hw;
-       void __iomem    *reg;
-       u8              bit_idx;
-       ...
-};
+       struct clk_gate {
+               struct clk_hw   hw;
+               void __iomem    *reg;
+               u8              bit_idx;
+               ...
+       };
 
 struct clk_gate contains struct clk_hw hw as well as hardware-specific
 knowledge about which register and bit controls this clk's gating.
@@ -115,7 +121,7 @@ Nothing about clock topology or accounting, such as enable_count or
 notifier_count, is needed here.  That is all handled by the common
 framework code and struct clk_core.
 
-Let's walk through enabling this clk from driver code:
+Let's walk through enabling this clk from driver code::
 
        struct clk *clk;
        clk = clk_get(NULL, "my_gateable_clk");
@@ -123,70 +129,71 @@ Let's walk through enabling this clk from driver code:
        clk_prepare(clk);
        clk_enable(clk);
 
-The call graph for clk_enable is very simple:
+The call graph for clk_enable is very simple::
 
-clk_enable(clk);
-       clk->ops->enable(clk->hw);
-       [resolves to...]
-               clk_gate_enable(hw);
-               [resolves struct clk gate with to_clk_gate(hw)]
-                       clk_gate_set_bit(gate);
+       clk_enable(clk);
+               clk->ops->enable(clk->hw);
+               [resolves to...]
+                       clk_gate_enable(hw);
+                       [resolves struct clk gate with to_clk_gate(hw)]
+                               clk_gate_set_bit(gate);
 
-And the definition of clk_gate_set_bit:
+And the definition of clk_gate_set_bit::
 
-static void clk_gate_set_bit(struct clk_gate *gate)
-{
-       u32 reg;
+       static void clk_gate_set_bit(struct clk_gate *gate)
+       {
+               u32 reg;
 
-       reg = __raw_readl(gate->reg);
-       reg |= BIT(gate->bit_idx);
-       writel(reg, gate->reg);
-}
+               reg = __raw_readl(gate->reg);
+               reg |= BIT(gate->bit_idx);
+               writel(reg, gate->reg);
+       }
 
-Note that to_clk_gate is defined as:
+Note that to_clk_gate is defined as::
 
-#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+       #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
 
 This pattern of abstraction is used for every clock hardware
 representation.
 
-       Part 4 - supporting your own clk hardware
+Supporting your own clk hardware
+================================
 
 When implementing support for a new type of clock it is only necessary to
-include the following header:
+include the following header::
 
-#include <linux/clk-provider.h>
+       #include <linux/clk-provider.h>
 
 To construct a clk hardware structure for your platform you must define
-the following:
+the following::
 
-struct clk_foo {
-       struct clk_hw hw;
-       ... hardware specific data goes here ...
-};
+       struct clk_foo {
+               struct clk_hw hw;
+               ... hardware specific data goes here ...
+       };
 
 To take advantage of your data you'll need to support valid operations
-for your clk:
+for your clk::
 
-struct clk_ops clk_foo_ops {
-       .enable         = &clk_foo_enable;
-       .disable        = &clk_foo_disable;
-};
+       struct clk_ops clk_foo_ops {
+               .enable         = &clk_foo_enable;
+               .disable        = &clk_foo_disable;
+       };
 
-Implement the above functions using container_of:
+Implement the above functions using container_of::
 
-#define to_clk_foo(_hw) container_of(_hw, struct clk_foo, hw)
+       #define to_clk_foo(_hw) container_of(_hw, struct clk_foo, hw)
 
-int clk_foo_enable(struct clk_hw *hw)
-{
-       struct clk_foo *foo;
+       int clk_foo_enable(struct clk_hw *hw)
+       {
+               struct clk_foo *foo;
 
-       foo = to_clk_foo(hw);
+               foo = to_clk_foo(hw);
 
-       ... perform magic on foo ...
+               ... perform magic on foo ...
 
-       return 0;
-};
+               return 0;
+       };
 
 Below is a matrix detailing which clk_ops are mandatory based upon the
 hardware capabilities of that clock.  A cell marked as "y" means
@@ -194,41 +201,56 @@ mandatory, a cell marked as "n" implies that either including that
 callback is invalid or otherwise unnecessary.  Empty cells are either
 optional or must be evaluated on a case-by-case basis.
 
-                              clock hardware characteristics
-                -----------------------------------------------------------
-                | gate | change rate | single parent | multiplexer | root |
-                |------|-------------|---------------|-------------|------|
-.prepare        |      |             |               |             |      |
-.unprepare      |      |             |               |             |      |
-                |      |             |               |             |      |
-.enable         | y    |             |               |             |      |
-.disable        | y    |             |               |             |      |
-.is_enabled     | y    |             |               |             |      |
-                |      |             |               |             |      |
-.recalc_rate    |      | y           |               |             |      |
-.round_rate     |      | y [1]       |               |             |      |
-.determine_rate |      | y [1]       |               |             |      |
-.set_rate       |      | y           |               |             |      |
-                |      |             |               |             |      |
-.set_parent     |      |             | n             | y           | n    |
-.get_parent     |      |             | n             | y           | n    |
-                |      |             |               |             |      |
-.recalc_accuracy|      |             |               |             |      |
-                |      |             |               |             |      |
-.init           |      |             |               |             |      |
-                -----------------------------------------------------------
-[1] either one of round_rate or determine_rate is required.
+.. table:: clock hardware characteristics
+
+   +----------------+------+-------------+---------------+-------------+------+
+   |                | gate | change rate | single parent | multiplexer | root |
+   +================+======+=============+===============+=============+======+
+   |.prepare        |      |             |               |             |      |
+   +----------------+------+-------------+---------------+-------------+------+
+   |.unprepare      |      |             |               |             |      |
+   +----------------+------+-------------+---------------+-------------+------+
+   +----------------+------+-------------+---------------+-------------+------+
+   |.enable         | y    |             |               |             |      |
+   +----------------+------+-------------+---------------+-------------+------+
+   |.disable        | y    |             |               |             |      |
+   +----------------+------+-------------+---------------+-------------+------+
+   |.is_enabled     | y    |             |               |             |      |
+   +----------------+------+-------------+---------------+-------------+------+
+   +----------------+------+-------------+---------------+-------------+------+
+   |.recalc_rate    |      | y           |               |             |      |
+   +----------------+------+-------------+---------------+-------------+------+
+   |.round_rate     |      | y [1]_      |               |             |      |
+   +----------------+------+-------------+---------------+-------------+------+
+   |.determine_rate |      | y [1]_      |               |             |      |
+   +----------------+------+-------------+---------------+-------------+------+
+   |.set_rate       |      | y           |               |             |      |
+   +----------------+------+-------------+---------------+-------------+------+
+   +----------------+------+-------------+---------------+-------------+------+
+   |.set_parent     |      |             | n             | y           | n    |
+   +----------------+------+-------------+---------------+-------------+------+
+   |.get_parent     |      |             | n             | y           | n    |
+   +----------------+------+-------------+---------------+-------------+------+
+   +----------------+------+-------------+---------------+-------------+------+
+   |.recalc_accuracy|      |             |               |             |      |
+   +----------------+------+-------------+---------------+-------------+------+
+   +----------------+------+-------------+---------------+-------------+------+
+   |.init           |      |             |               |             |      |
+   +----------------+------+-------------+---------------+-------------+------+
+
+.. [1] either one of round_rate or determine_rate is required.
 
 Finally, register your clock at run-time with a hardware-specific
 registration function.  This function simply populates struct clk_foo's
 data and then passes the common struct clk parameters to the framework
-with a call to:
+with a call to::
 
-clk_register(...)
+       clk_register(...)
 
-See the basic clock types in drivers/clk/clk-*.c for examples.
+See the basic clock types in ``drivers/clk/clk-*.c`` for examples.
 
-       Part 5 - Disabling clock gating of unused clocks
+Disabling clock gating of unused clocks
+=======================================
 
 Sometimes during development it can be useful to be able to bypass the
 default disabling of unused clocks. For example, if drivers aren't enabling
@@ -239,7 +261,8 @@ are sorted out.
 To bypass this disabling, include "clk_ignore_unused" in the bootargs to the
 kernel.
 
-       Part 6 - Locking
+Locking
+=======
 
 The common clock framework uses two global locks, the prepare lock and the
 enable lock.
index 9ec8488..17b0091 100644 (file)
@@ -114,7 +114,7 @@ The Slab Cache
 User Space Memory Access
 ------------------------
 
-.. kernel-doc:: arch/x86/include/asm/uaccess_32.h
+.. kernel-doc:: arch/x86/include/asm/uaccess.h
    :internal:
 
 .. kernel-doc:: arch/x86/lib/usercopy_32.c
index 287224e..2d01ce4 100644 (file)
@@ -1,9 +1,10 @@
+========
 CPU load
---------
+========
 
-Linux exports various bits of information via `/proc/stat' and
-`/proc/uptime' that userland tools, such as top(1), use to calculate
-the average time system spent in a particular state, for example:
+Linux exports various bits of information via ``/proc/stat`` and
+``/proc/uptime`` that userland tools, such as top(1), use to calculate
+the average time system spent in a particular state, for example::
 
     $ iostat
     Linux 2.6.18.3-exp (linmac)     02/20/2007
@@ -17,7 +18,7 @@ Here the system thinks that over the default sampling period the
 system spent 10.01% of the time doing work in user space, 2.92% in the
 kernel, and was overall 81.63% of the time idle.
 
-In most cases the `/proc/stat' information reflects the reality quite
+In most cases the ``/proc/stat``        information reflects the reality quite
 closely, however due to the nature of how/when the kernel collects
 this data sometimes it can not be trusted at all.
 
@@ -33,78 +34,78 @@ Example
 -------
 
 If we imagine the system with one task that periodically burns cycles
-in the following manner:
+in the following manner::
 
- time line between two timer interrupts
-|--------------------------------------|
- ^                                    ^
- |_ something begins working          |
-                                      |_ something goes to sleep
-                                     (only to be awaken quite soon)
    time line between two timer interrupts
+    |--------------------------------------|
    ^                                    ^
    |_ something begins working          |
+                                          |_ something goes to sleep
+                                         (only to be awaken quite soon)
 
 In the above situation the system will be 0% loaded according to the
-`/proc/stat' (since the timer interrupt will always happen when the
+``/proc/stat`` (since the timer interrupt will always happen when the
 system is executing the idle handler), but in reality the load is
 closer to 99%.
 
 One can imagine many more situations where this behavior of the kernel
-will lead to quite erratic information inside `/proc/stat'.
-
-
-/* gcc -o hog smallhog.c */
-#include <time.h>
-#include <limits.h>
-#include <signal.h>
-#include <sys/time.h>
-#define HIST 10
-
-static volatile sig_atomic_t stop;
-
-static void sighandler (int signr)
-{
-     (void) signr;
-     stop = 1;
-}
-static unsigned long hog (unsigned long niters)
-{
-     stop = 0;
-     while (!stop && --niters);
-     return niters;
-}
-int main (void)
-{
-     int i;
-     struct itimerval it = { .it_interval = { .tv_sec = 0, .tv_usec = 1 },
-                             .it_value = { .tv_sec = 0, .tv_usec = 1 } };
-     sigset_t set;
-     unsigned long v[HIST];
-     double tmp = 0.0;
-     unsigned long n;
-     signal (SIGALRM, &sighandler);
-     setitimer (ITIMER_REAL, &it, NULL);
-
-     hog (ULONG_MAX);
-     for (i = 0; i < HIST; ++i) v[i] = ULONG_MAX - hog (ULONG_MAX);
-     for (i = 0; i < HIST; ++i) tmp += v[i];
-     tmp /= HIST;
-     n = tmp - (tmp / 3.0);
-
-     sigemptyset (&set);
-     sigaddset (&set, SIGALRM);
-
-     for (;;) {
-         hog (n);
-         sigwait (&set, &i);
-     }
-     return 0;
-}
+will lead to quite erratic information inside ``/proc/stat``::
+
+
+       /* gcc -o hog smallhog.c */
+       #include <time.h>
+       #include <limits.h>
+       #include <signal.h>
+       #include <sys/time.h>
+       #define HIST 10
+
+       static volatile sig_atomic_t stop;
+
+       static void sighandler (int signr)
+       {
+       (void) signr;
+       stop = 1;
+       }
+       static unsigned long hog (unsigned long niters)
+       {
+       stop = 0;
+       while (!stop && --niters);
+       return niters;
+       }
+       int main (void)
+       {
+       int i;
+       struct itimerval it = { .it_interval = { .tv_sec = 0, .tv_usec = 1 },
+                               .it_value = { .tv_sec = 0, .tv_usec = 1 } };
+       sigset_t set;
+       unsigned long v[HIST];
+       double tmp = 0.0;
+       unsigned long n;
+       signal (SIGALRM, &sighandler);
+       setitimer (ITIMER_REAL, &it, NULL);
+
+       hog (ULONG_MAX);
+       for (i = 0; i < HIST; ++i) v[i] = ULONG_MAX - hog (ULONG_MAX);
+       for (i = 0; i < HIST; ++i) tmp += v[i];
+       tmp /= HIST;
+       n = tmp - (tmp / 3.0);
+
+       sigemptyset (&set);
+       sigaddset (&set, SIGALRM);
+
+       for (;;) {
+               hog (n);
+               sigwait (&set, &i);
+       }
+       return 0;
+       }
 
 
 References
 ----------
 
-http://lkml.org/lkml/2007/2/12/6
-Documentation/filesystems/proc.txt (1.8)
+http://lkml.org/lkml/2007/2/12/6
+Documentation/filesystems/proc.txt (1.8)
 
 
 Thanks
index 127c9d8..c6e7e91 100644 (file)
@@ -1,3 +1,6 @@
+===========================================
+How CPU topology info is exported via sysfs
+===========================================
 
 Export CPU topology info via sysfs. Items (attributes) are similar
 to /proc/cpuinfo output of some architectures:
@@ -75,24 +78,26 @@ CONFIG_SCHED_BOOK and CONFIG_DRAWER are currently only used on s390, where
 they reflect the cpu and cache hierarchy.
 
 For an architecture to support this feature, it must define some of
-these macros in include/asm-XXX/topology.h:
-#define topology_physical_package_id(cpu)
-#define topology_core_id(cpu)
-#define topology_book_id(cpu)
-#define topology_drawer_id(cpu)
-#define topology_sibling_cpumask(cpu)
-#define topology_core_cpumask(cpu)
-#define topology_book_cpumask(cpu)
-#define topology_drawer_cpumask(cpu)
-
-The type of **_id macros is int.
-The type of **_cpumask macros is (const) struct cpumask *. The latter
-correspond with appropriate **_siblings sysfs attributes (except for
+these macros in include/asm-XXX/topology.h::
+
+       #define topology_physical_package_id(cpu)
+       #define topology_core_id(cpu)
+       #define topology_book_id(cpu)
+       #define topology_drawer_id(cpu)
+       #define topology_sibling_cpumask(cpu)
+       #define topology_core_cpumask(cpu)
+       #define topology_book_cpumask(cpu)
+       #define topology_drawer_cpumask(cpu)
+
+The type of ``**_id macros`` is int.
+The type of ``**_cpumask macros`` is ``(const) struct cpumask *``. The latter
+correspond with appropriate ``**_siblings`` sysfs attributes (except for
 topology_sibling_cpumask() which corresponds with thread_siblings).
 
 To be consistent on all architectures, include/linux/topology.h
 provides default definitions for any of the above macros that are
 not defined by include/asm-XXX/topology.h:
+
 1) physical_package_id: -1
 2) core_id: 0
 3) sibling_cpumask: just the given CPU
@@ -107,6 +112,7 @@ Additionally, CPU topology information is provided under
 /sys/devices/system/cpu and includes these files.  The internal
 source for the output is in brackets ("[]").
 
+    =========== ==========================================================
     kernel_max: the maximum CPU index allowed by the kernel configuration.
                [NR_CPUS-1]
 
@@ -122,6 +128,7 @@ source for the output is in brackets ("[]").
 
     present:   CPUs that have been identified as being present in the
                system. [cpu_present_mask]
+    =========== ==========================================================
 
 The format for the above output is compatible with cpulist_parse()
 [see <linux/cpumask.h>].  Some examples follow.
@@ -129,7 +136,7 @@ The format for the above output is compatible with cpulist_parse()
 In this example, there are 64 CPUs in the system but cpus 32-63 exceed
 the kernel max which is limited to 0..31 by the NR_CPUS config option
 being 32.  Note also that CPUs 2 and 4-31 are not online but could be
-brought online as they are both present and possible.
+brought online as they are both present and possible::
 
      kernel_max: 31
         offline: 2,4-31,32-63
@@ -140,7 +147,7 @@ brought online as they are both present and possible.
 In this example, the NR_CPUS config option is 128, but the kernel was
 started with possible_cpus=144.  There are 4 CPUs in the system and cpu2
 was manually taken offline (and is the only CPU that can be brought
-online.)
+online.)::
 
      kernel_max: 127
         offline: 2,4-127,128-143
index a08a7dd..8a6860f 100644 (file)
@@ -1,4 +1,6 @@
-A brief CRC tutorial.
+=================================
+brief tutorial on CRC computation
+=================================
 
 A CRC is a long-division remainder.  You add the CRC to the message,
 and the whole thing (message+CRC) is a multiple of the given
@@ -8,7 +10,8 @@ remainder computed on the message+CRC is 0.  This latter approach
 is used by a lot of hardware implementations, and is why so many
 protocols put the end-of-frame flag after the CRC.
 
-It's actually the same long division you learned in school, except that
+It's actually the same long division you learned in school, except that:
+
 - We're working in binary, so the digits are only 0 and 1, and
 - When dividing polynomials, there are no carries.  Rather than add and
   subtract, we just xor.  Thus, we tend to get a bit sloppy about
@@ -40,11 +43,12 @@ throw the quotient bit away, but subtract the appropriate multiple of
 the polynomial from the remainder and we're back to where we started,
 ready to process the next bit.
 
-A big-endian CRC written this way would be coded like:
-for (i = 0; i < input_bits; i++) {
-       multiple = remainder & 0x80000000 ? CRCPOLY : 0;
-       remainder = (remainder << 1 | next_input_bit()) ^ multiple;
-}
+A big-endian CRC written this way would be coded like::
+
+       for (i = 0; i < input_bits; i++) {
+               multiple = remainder & 0x80000000 ? CRCPOLY : 0;
+               remainder = (remainder << 1 | next_input_bit()) ^ multiple;
+       }
 
 Notice how, to get at bit 32 of the shifted remainder, we look
 at bit 31 of the remainder *before* shifting it.
@@ -54,25 +58,26 @@ the remainder don't actually affect any decision-making until
 32 bits later.  Thus, the first 32 cycles of this are pretty boring.
 Also, to add the CRC to a message, we need a 32-bit-long hole for it at
 the end, so we have to add 32 extra cycles shifting in zeros at the
-end of every message,
+end of every message.
 
 These details lead to a standard trick: rearrange merging in the
 next_input_bit() until the moment it's needed.  Then the first 32 cycles
 can be precomputed, and merging in the final 32 zero bits to make room
-for the CRC can be skipped entirely.  This changes the code to:
+for the CRC can be skipped entirely.  This changes the code to::
 
-for (i = 0; i < input_bits; i++) {
-       remainder ^= next_input_bit() << 31;
-       multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
-       remainder = (remainder << 1) ^ multiple;
-}
+       for (i = 0; i < input_bits; i++) {
+               remainder ^= next_input_bit() << 31;
+               multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+               remainder = (remainder << 1) ^ multiple;
+       }
 
-With this optimization, the little-endian code is particularly simple:
-for (i = 0; i < input_bits; i++) {
-       remainder ^= next_input_bit();
-       multiple = (remainder & 1) ? CRCPOLY : 0;
-       remainder = (remainder >> 1) ^ multiple;
-}
+With this optimization, the little-endian code is particularly simple::
+
+       for (i = 0; i < input_bits; i++) {
+               remainder ^= next_input_bit();
+               multiple = (remainder & 1) ? CRCPOLY : 0;
+               remainder = (remainder >> 1) ^ multiple;
+       }
 
 The most significant coefficient of the remainder polynomial is stored
 in the least significant bit of the binary "remainder" variable.
@@ -81,23 +86,25 @@ be bit-reversed) and next_input_bit().
 
 As long as next_input_bit is returning the bits in a sensible order, we don't
 *have* to wait until the last possible moment to merge in additional bits.
-We can do it 8 bits at a time rather than 1 bit at a time:
-for (i = 0; i < input_bytes; i++) {
-       remainder ^= next_input_byte() << 24;
-       for (j = 0; j < 8; j++) {
-               multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
-               remainder = (remainder << 1) ^ multiple;
+We can do it 8 bits at a time rather than 1 bit at a time::
+
+       for (i = 0; i < input_bytes; i++) {
+               remainder ^= next_input_byte() << 24;
+               for (j = 0; j < 8; j++) {
+                       multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+                       remainder = (remainder << 1) ^ multiple;
+               }
        }
-}
 
-Or in little-endian:
-for (i = 0; i < input_bytes; i++) {
-       remainder ^= next_input_byte();
-       for (j = 0; j < 8; j++) {
-               multiple = (remainder & 1) ? CRCPOLY : 0;
-               remainder = (remainder >> 1) ^ multiple;
+Or in little-endian::
+
+       for (i = 0; i < input_bytes; i++) {
+               remainder ^= next_input_byte();
+               for (j = 0; j < 8; j++) {
+                       multiple = (remainder & 1) ? CRCPOLY : 0;
+                       remainder = (remainder >> 1) ^ multiple;
+               }
        }
-}
 
 If the input is a multiple of 32 bits, you can even XOR in a 32-bit
 word at a time and increase the inner loop count to 32.
index b82b6ad..5969bf4 100644 (file)
@@ -10,6 +10,7 @@ Contents:
     - Signature verification.
   - Asymmetric key subtypes.
   - Instantiation data parsers.
+  - Keyring link restrictions.
 
 
 ========
@@ -318,7 +319,8 @@ KEYRING LINK RESTRICTIONS
 =========================
 
 Keyrings created from userspace using add_key can be configured to check the
-signature of the key being linked.
+signature of the key being linked.  Keys without a valid signature are not
+allowed to link.
 
 Several restriction methods are available:
 
@@ -327,9 +329,10 @@ Several restriction methods are available:
      - Option string used with KEYCTL_RESTRICT_KEYRING:
        - "builtin_trusted"
 
-     The kernel builtin trusted keyring will be searched for the signing
-     key. The ca_keys kernel parameter also affects which keys are used for
-     signature verification.
+     The kernel builtin trusted keyring will be searched for the signing key.
+     If the builtin trusted keyring is not configured, all links will be
+     rejected.  The ca_keys kernel parameter also affects which keys are used
+     for signature verification.
 
  (2) Restrict using the kernel builtin and secondary trusted keyrings
 
@@ -337,8 +340,10 @@ Several restriction methods are available:
        - "builtin_and_secondary_trusted"
 
      The kernel builtin and secondary trusted keyrings will be searched for the
-     signing key. The ca_keys kernel parameter also affects which keys are used
-     for signature verification.
+     signing key.  If the secondary trusted keyring is not configured, this
+     restriction will behave like the "builtin_trusted" option.  The ca_keys
+     kernel parameter also affects which keys are used for signature
+     verification.
 
  (3) Restrict using a separate key or keyring
 
@@ -346,7 +351,7 @@ Several restriction methods are available:
        - "key_or_keyring:<key or keyring serial number>[:chain]"
 
      Whenever a key link is requested, the link will only succeed if the key
-     being linked is signed by one of the designated keys. This key may be
+     being linked is signed by one of the designated keys.  This key may be
      specified directly by providing a serial number for one asymmetric key, or
      a group of keys may be searched for the signing key by providing the
      serial number for a keyring.
@@ -354,7 +359,51 @@ Several restriction methods are available:
      When the "chain" option is provided at the end of the string, the keys
      within the destination keyring will also be searched for signing keys.
      This allows for verification of certificate chains by adding each
-     cert in order (starting closest to the root) to one keyring.
+     certificate in order (starting closest to the root) to a keyring.  For
+     instance, one keyring can be populated with links to a set of root
+     certificates, with a separate, restricted keyring set up for each
+     certificate chain to be validated:
+
+       # Create and populate a keyring for root certificates
+       root_id=`keyctl add keyring root-certs "" @s`
+       keyctl padd asymmetric "" $root_id < root1.cert
+       keyctl padd asymmetric "" $root_id < root2.cert
+
+       # Create and restrict a keyring for the certificate chain
+       chain_id=`keyctl add keyring chain "" @s`
+       keyctl restrict_keyring $chain_id asymmetric key_or_keyring:$root_id:chain
+
+       # Attempt to add each certificate in the chain, starting with the
+       # certificate closest to the root.
+       keyctl padd asymmetric "" $chain_id < intermediateA.cert
+       keyctl padd asymmetric "" $chain_id < intermediateB.cert
+       keyctl padd asymmetric "" $chain_id < end-entity.cert
+
+     If the final end-entity certificate is successfully added to the "chain"
+     keyring, we can be certain that it has a valid signing chain going back to
+     one of the root certificates.
+
+     A single keyring can be used to verify a chain of signatures by
+     restricting the keyring after linking the root certificate:
+
+       # Create a keyring for the certificate chain and add the root
+       chain2_id=`keyctl add keyring chain2 "" @s`
+       keyctl padd asymmetric "" $chain2_id < root1.cert
+
+       # Restrict the keyring that already has root1.cert linked.  The cert
+       # will remain linked by the keyring.
+       keyctl restrict_keyring $chain2_id asymmetric key_or_keyring:0:chain
+
+       # Attempt to add each certificate in the chain, starting with the
+       # certificate closest to the root.
+       keyctl padd asymmetric "" $chain2_id < intermediateA.cert
+       keyctl padd asymmetric "" $chain2_id < intermediateB.cert
+       keyctl padd asymmetric "" $chain2_id < end-entity.cert
+
+     If the final end-entity certificate is successfully added to the "chain2"
+     keyring, we can be certain that there is a valid signing chain going back
+     to the root certificate that was added before the keyring was restricted.
+
 
 In all of these cases, if the signing key is found the signature of the key to
 be linked will be verified using the signing key.  The requested key is added
index e1c52e2..309cc57 100644 (file)
@@ -1,4 +1,9 @@
+===================================
+Dell Systems Management Base Driver
+===================================
+
 Overview
+========
 
 The Dell Systems Management Base Driver provides a sysfs interface for
 systems management software such as Dell OpenManage to perform system
@@ -17,6 +22,7 @@ more information about the libsmbios project.
 
 
 System Management Interrupt
+===========================
 
 On some Dell systems, systems management software must access certain
 management information via a system management interrupt (SMI).  The SMI data
@@ -24,12 +30,12 @@ buffer must reside in 32-bit address space, and the physical address of the
 buffer is required for the SMI.  The driver maintains the memory required for
 the SMI and provides a way for the application to generate the SMI.
 The driver creates the following sysfs entries for systems management
-software to perform these system management interrupts:
+software to perform these system management interrupts::
 
-/sys/devices/platform/dcdbas/smi_data
-/sys/devices/platform/dcdbas/smi_data_buf_phys_addr
-/sys/devices/platform/dcdbas/smi_data_buf_size
-/sys/devices/platform/dcdbas/smi_request
+       /sys/devices/platform/dcdbas/smi_data
+       /sys/devices/platform/dcdbas/smi_data_buf_phys_addr
+       /sys/devices/platform/dcdbas/smi_data_buf_size
+       /sys/devices/platform/dcdbas/smi_request
 
 Systems management software must perform the following steps to execute
 a SMI using this driver:
@@ -43,6 +49,7 @@ a SMI using this driver:
 
 
 Host Control Action
+===================
 
 Dell OpenManage supports a host control feature that allows the administrator
 to perform a power cycle or power off of the system after the OS has finished
@@ -69,12 +76,14 @@ power off host control action using this driver:
 
 
 Host Control SMI Type
+=====================
 
 The following table shows the value to write to host_control_smi_type to
 perform a power cycle or power off host control action:
 
+=================== =====================
 PowerEdge System    Host Control SMI Type
-----------------    ---------------------
+=================== =====================
       300             HC_SMITYPE_TYPE1
      1300             HC_SMITYPE_TYPE1
      1400             HC_SMITYPE_TYPE2
@@ -87,5 +96,4 @@ PowerEdge System    Host Control SMI Type
      1655MC           HC_SMITYPE_TYPE2
       700             HC_SMITYPE_TYPE3
       750             HC_SMITYPE_TYPE3
-
-
+=================== =====================
index 9ff026d..981ad4f 100644 (file)
@@ -1,6 +1,6 @@
-
-  Using physical DMA provided by OHCI-1394 FireWire controllers for debugging
-  ---------------------------------------------------------------------------
+===========================================================================
+Using physical DMA provided by OHCI-1394 FireWire controllers for debugging
+===========================================================================
 
 Introduction
 ------------
@@ -91,10 +91,10 @@ Step-by-step instructions for using firescope with early OHCI initialization:
 1) Verify that your hardware is supported:
 
    Load the firewire-ohci module and check your kernel logs.
-   You should see a line similar to
+   You should see a line similar to::
 
-   firewire_ohci 0000:15:00.1: added OHCI v1.0 device as card 2, 4 IR + 4 IT
-   ... contexts, quirks 0x11
+     firewire_ohci 0000:15:00.1: added OHCI v1.0 device as card 2, 4 IR + 4 IT
+     ... contexts, quirks 0x11
 
    when loading the driver. If you have no supported controller, many PCI,
    CardBus and even some Express cards which are fully compliant to OHCI-1394
@@ -113,9 +113,9 @@ Step-by-step instructions for using firescope with early OHCI initialization:
    stable connection and has matching connectors (there are small 4-pin and
    large 6-pin FireWire ports) will do.
 
-   If an driver is running on both machines you should see a line like
+   If an driver is running on both machines you should see a line like::
 
-   firewire_core 0000:15:00.1: created device fw1: GUID 00061b0020105917, S400
+     firewire_core 0000:15:00.1: created device fw1: GUID 00061b0020105917, S400
 
    on both machines in the kernel log when the cable is plugged in
    and connects the two machines.
@@ -123,7 +123,7 @@ Step-by-step instructions for using firescope with early OHCI initialization:
 3) Test physical DMA using firescope:
 
    On the debug host, make sure that /dev/fw* is accessible,
-   then start firescope:
+   then start firescope::
 
        $ firescope
        Port 0 (/dev/fw1) opened, 2 nodes detected
@@ -163,7 +163,7 @@ Step-by-step instructions for using firescope with early OHCI initialization:
    host loaded, reboot the debugged machine, booting the kernel which has
    CONFIG_PROVIDE_OHCI1394_DMA_INIT enabled, with the option ohci1394_dma=early.
 
-   Then, on the debugging host, run firescope, for example by using -A:
+   Then, on the debugging host, run firescope, for example by using -A::
 
        firescope -A System.map-of-debug-target-kernel
 
@@ -178,6 +178,7 @@ Step-by-step instructions for using firescope with early OHCI initialization:
 
 Notes
 -----
+
 Documentation and specifications: http://halobates.de/firewire/
 
 FireWire is a trademark of Apple Inc. - for more information please refer to:
index d262e22..0fdb6aa 100644 (file)
@@ -1,18 +1,30 @@
-Purpose:
-Demonstrate the usage of the new open sourced rbu (Remote BIOS Update) driver
+=============================================================
+Usage of the new open sourced rbu (Remote BIOS Update) driver
+=============================================================
+
+Purpose
+=======
+
+Document demonstrating the use of the Dell Remote BIOS Update driver.
 for updating BIOS images on Dell servers and desktops.
 
-Scope:
+Scope
+=====
+
 This document discusses the functionality of the rbu driver only.
 It does not cover the support needed from applications to enable the BIOS to
 update itself with the image downloaded in to the memory.
 
-Overview:
+Overview
+========
+
 This driver works with Dell OpenManage or Dell Update Packages for updating
 the BIOS on Dell servers (starting from servers sold since 1999), desktops
 and notebooks (starting from those sold in 2005).
+
 Please go to  http://support.dell.com register and you can find info on
 OpenManage and Dell Update packages (DUP).
+
 Libsmbios can also be used to update BIOS on Dell systems go to
 http://linux.dell.com/libsmbios/ for details.
 
@@ -22,6 +34,7 @@ of physical pages having the BIOS image. In case of packetized the app
 using the driver breaks the image in to packets of fixed sizes and the driver
 would place each packet in contiguous physical memory. The driver also
 maintains a link list of packets for reading them back.
+
 If the dell_rbu driver is unloaded all the allocated memory is freed.
 
 The rbu driver needs to have an application (as mentioned above)which will
@@ -30,28 +43,33 @@ inform the BIOS to enable the update in the next system reboot.
 The user should not unload the rbu driver after downloading the BIOS image
 or updating.
 
-The driver load creates the following directories under the /sys file system.
-/sys/class/firmware/dell_rbu/loading
-/sys/class/firmware/dell_rbu/data
-/sys/devices/platform/dell_rbu/image_type
-/sys/devices/platform/dell_rbu/data
-/sys/devices/platform/dell_rbu/packet_size
+The driver load creates the following directories under the /sys file system::
+
+       /sys/class/firmware/dell_rbu/loading
+       /sys/class/firmware/dell_rbu/data
+       /sys/devices/platform/dell_rbu/image_type
+       /sys/devices/platform/dell_rbu/data
+       /sys/devices/platform/dell_rbu/packet_size
 
 The driver supports two types of update mechanism; monolithic and packetized.
 These update mechanism depends upon the BIOS currently running on the system.
 Most of the Dell systems support a monolithic update where the BIOS image is
 copied to a single contiguous block of physical memory.
+
 In case of packet mechanism the single memory can be broken in smaller chunks
 of contiguous memory and the BIOS image is scattered in these packets.
 
 By default the driver uses monolithic memory for the update type. This can be
 changed to packets during the driver load time by specifying the load
-parameter image_type=packet.  This can also be changed later as below
-echo packet > /sys/devices/platform/dell_rbu/image_type
+parameter image_type=packet.  This can also be changed later as below::
+
+       echo packet > /sys/devices/platform/dell_rbu/image_type
 
 In packet update mode the packet size has to be given before any packets can
-be downloaded. It is done as below
-echo XXXX > /sys/devices/platform/dell_rbu/packet_size
+be downloaded. It is done as below::
+
+       echo XXXX > /sys/devices/platform/dell_rbu/packet_size
+
 In the packet update mechanism, the user needs to create a new file having
 packets of data arranged back to back. It can be done as follows
 The user creates packets header, gets the chunk of the BIOS image and
@@ -60,41 +78,54 @@ added together should match the specified packet_size. This makes one
 packet, the user needs to create more such packets out of the entire BIOS
 image file and then arrange all these packets back to back in to one single
 file.
+
 This file is then copied to /sys/class/firmware/dell_rbu/data.
 Once this file gets to the driver, the driver extracts packet_size data from
 the file and spreads it across the physical memory in contiguous packet_sized
 space.
+
 This method makes sure that all the packets get to the driver in a single operation.
 
 In monolithic update the user simply get the BIOS image (.hdr file) and copies
 to the data file as is without any change to the BIOS image itself.
 
 Do the steps below to download the BIOS image.
+
 1) echo 1 > /sys/class/firmware/dell_rbu/loading
 2) cp bios_image.hdr /sys/class/firmware/dell_rbu/data
 3) echo 0 > /sys/class/firmware/dell_rbu/loading
 
 The /sys/class/firmware/dell_rbu/ entries will remain till the following is
 done.
-echo -1 > /sys/class/firmware/dell_rbu/loading
+
+::
+
+       echo -1 > /sys/class/firmware/dell_rbu/loading
+
 Until this step is completed the driver cannot be unloaded.
+
 Also echoing either mono, packet or init in to image_type will free up the
 memory allocated by the driver.
 
 If a user by accident executes steps 1 and 3 above without executing step 2;
 it will make the /sys/class/firmware/dell_rbu/ entries disappear.
-The entries can be recreated by doing the following
-echo init > /sys/devices/platform/dell_rbu/image_type
-NOTE: echoing init in image_type does not change it original value.
+
+The entries can be recreated by doing the following::
+
+       echo init > /sys/devices/platform/dell_rbu/image_type
+
+.. note:: echoing init in image_type does not change it original value.
 
 Also the driver provides /sys/devices/platform/dell_rbu/data readonly file to
 read back the image downloaded.
 
-NOTE:
-This driver requires a patch for firmware_class.c which has the modified
-request_firmware_nowait function.
-Also after updating the BIOS image a user mode application needs to execute
-code which sends the BIOS update request to the BIOS. So on the next reboot
-the BIOS knows about the new image downloaded and it updates itself.
-Also don't unload the rbu driver if the image has to be updated.
+.. note::
+
+   This driver requires a patch for firmware_class.c which has the modified
+   request_firmware_nowait function.
+
+   Also after updating the BIOS image a user mode application needs to execute
+   code which sends the BIOS update request to the BIOS. So on the next reboot
+   the BIOS knows about the new image downloaded and it updates itself.
+   Also don't unload the rbu driver if the image has to be updated.
 
index 7e06e65..4a0a746 100644 (file)
@@ -343,3 +343,4 @@ Version History
 1.11.0  Fix table line argument order
        (wrong raid10_copies/raid10_format sequence)
 1.11.1  Add raid4/5/6 journal write-back support via journal_mode option
+1.12.1  fix for MD deadlock between mddev_suspend() and md_write_start() available
index 0764f9a..e20eac7 100644 (file)
@@ -1,14 +1,22 @@
 * Renesas R-Car SATA
 
 Required properties:
-- compatible           : should contain one of the following:
+- compatible           : should contain one or more of the following:
                          - "renesas,sata-r8a7779" for R-Car H1
-                           ("renesas,rcar-sata" is deprecated)
                          - "renesas,sata-r8a7790-es1" for R-Car H2 ES1
                          - "renesas,sata-r8a7790" for R-Car H2 other than ES1
                          - "renesas,sata-r8a7791" for R-Car M2-W
                          - "renesas,sata-r8a7793" for R-Car M2-N
                          - "renesas,sata-r8a7795" for R-Car H3
+                         - "renesas,rcar-gen2-sata" for a generic R-Car Gen2 compatible device
+                         - "renesas,rcar-gen3-sata" for a generic R-Car Gen3 compatible device
+                         - "renesas,rcar-sata" is deprecated
+
+                         When compatible with the generic version nodes
+                         must list the SoC-specific version corresponding
+                         to the platform first followed by the generic
+                         version.
+
 - reg                  : address and length of the SATA registers;
 - interrupts           : must consist of one interrupt specifier.
 - clocks               : must contain a reference to the functional clock.
@@ -16,7 +24,7 @@ Required properties:
 Example:
 
 sata0: sata@ee300000 {
-       compatible = "renesas,sata-r8a7791";
+       compatible = "renesas,sata-r8a7791", "renesas,rcar-gen2-sata";
        reg = <0 0xee300000 0 0x2000>;
        interrupt-parent = <&gic>;
        interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/Documentation/devicetree/bindings/clock/img,boston-clock.txt b/Documentation/devicetree/bindings/clock/img,boston-clock.txt
new file mode 100644 (file)
index 0000000..7bc5e9f
--- /dev/null
@@ -0,0 +1,31 @@
+Binding for Imagination Technologies MIPS Boston clock sources.
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The device node must be a child node of the syscon node corresponding to the
+Boston system's platform registers.
+
+Required properties:
+- compatible : Should be "img,boston-clock".
+- #clock-cells : Should be set to 1.
+  Values available for clock consumers can be found in the header file:
+    <dt-bindings/clock/boston-clock.h>
+
+Example:
+
+       system-controller@17ffd000 {
+               compatible = "img,boston-platform-regs", "syscon";
+               reg = <0x17ffd000 0x1000>;
+
+               clk_boston: clock {
+                       compatible = "img,boston-clock";
+                       #clock-cells = <1>;
+               };
+       };
+
+       uart0: uart@17ffe000 {
+               /* ... */
+               clocks = <&clk_boston BOSTON_CLK_SYS>;
+       };
index f69773f..941bb6a 100644 (file)
@@ -8,7 +8,6 @@ Required properties:
 
 Optional properties:
 - clocks: Reference to the crypto engine clock.
-- dma-mask: The address mask limitation. Defaults to 64.
 
 Example:
 
@@ -24,6 +23,5 @@ Example:
                interrupt-names = "mem", "ring0", "ring1", "ring2", "ring3",
                                  "eip";
                clocks = <&cpm_syscon0 1 26>;
-               dma-mask = <0xff 0xffffffff>;
                status = "disabled";
        };
index aad9844..a58c173 100644 (file)
@@ -78,7 +78,6 @@ Example:
        };
 
        dwmmc0@12200000 {
-               num-slots = <1>;
                cap-mmc-highspeed;
                cap-sd-highspeed;
                broken-cd;
index 85de99f..c54e577 100644 (file)
@@ -24,6 +24,5 @@ Example:
 
                fifo-depth = <0x20>;
                bus-width = <4>;
-               num-slots = <1>;
                disable-wp;
        };
index 8af1afc..07242d1 100644 (file)
@@ -36,7 +36,6 @@ Example:
 
        /* Board portion */
        dwmmc0@fcd03000 {
-               num-slots = <1>;
                vmmc-supply = <&ldo12>;
                fifo-depth = <0x100>;
                pinctrl-names = "default";
@@ -52,7 +51,6 @@ Example:
 
        dwmmc_1: dwmmc1@f723e000 {
                compatible = "hisilicon,hi6220-dw-mshc";
-               num-slots = <0x1>;
                bus-width = <0x4>;
                disable-wp;
                cap-sd-highspeed;
index 9cb55ca..ef3e5f1 100644 (file)
@@ -12,12 +12,12 @@ Required Properties:
 * #address-cells: should be 1.
 * #size-cells: should be 0.
 
-# Slots: The slot specific information are contained within child-nodes with
-  each child-node representing a supported slot. There should be atleast one
-  child node representing a card slot. The name of the child node representing
-  the slot is recommended to be slot@n where n is the unique number of the slot
-  connected to the controller. The following are optional properties which
-  can be included in the slot child node.
+# Slots (DEPRECATED): The slot specific information are contained within
+  child-nodes with each child-node representing a supported slot. There should
+  be atleast one child node representing a card slot. The name of the child node
+  representing the slot is recommended to be slot@n where n is the unique number
+  of the slot connected to the controller. The following are optional properties
+  which can be included in the slot child node.
 
        * reg: specifies the physical slot number. The valid values of this
          property is 0 to (num-slots -1), where num-slots is the value
@@ -63,7 +63,7 @@ Optional properties:
   clock(cclk_out). If it's not specified, max is 200MHZ and min is 400KHz by default.
          (Use the "max-frequency" instead of "clock-freq-min-max".)
 
-* num-slots: specifies the number of slots supported by the controller.
+* num-slots (DEPRECATED): specifies the number of slots supported by the controller.
   The number of physical slots actually used could be equal or less than the
   value specified by num-slots. If this property is not specified, the value
   of num-slot property is assumed to be 1.
@@ -124,7 +124,6 @@ board specific portions as listed below.
        dwmmc0@12200000 {
                clock-frequency = <400000000>;
                clock-freq-min-max = <400000 200000000>;
-               num-slots = <1>;
                broken-cd;
                fifo-depth = <0x80>;
                card-detect-delay = <200>;
@@ -139,7 +138,6 @@ board specific portions as listed below.
        dwmmc0@12200000 {
                clock-frequency = <400000000>;
                clock-freq-min-max = <400000 200000000>;
-               num-slots = <1>;
                broken-cd;
                fifo-depth = <0x80>;
                card-detect-delay = <200>;
index eaade0e..906819a 100644 (file)
@@ -25,7 +25,6 @@ Example:
                clock-frequency = <50000000>;
                clocks = <&topcrm SD0_AHB>, <&topcrm SD0_WCLK>;
                clock-names = "biu", "ciu";
-               num-slots = <1>;
                max-frequency = <50000000>;
                cap-sdio-irq;
                cap-sd-highspeed;
index e593bbe..504291d 100644 (file)
@@ -3,10 +3,23 @@
 Required properties:
   - compatible : should be one of the following:
       "altr,socfpga-denali-nand"            - for Altera SOCFPGA
+      "socionext,uniphier-denali-nand-v5a"  - for Socionext UniPhier (v5a)
+      "socionext,uniphier-denali-nand-v5b"  - for Socionext UniPhier (v5b)
   - reg : should contain registers location and length for data and reg.
   - reg-names: Should contain the reg names "nand_data" and "denali_reg"
   - interrupts : The interrupt number.
 
+Optional properties:
+  - nand-ecc-step-size: see nand.txt for details.  If present, the value must be
+      512        for "altr,socfpga-denali-nand"
+      1024       for "socionext,uniphier-denali-nand-v5a"
+      1024       for "socionext,uniphier-denali-nand-v5b"
+  - nand-ecc-strength: see nand.txt for details.  Valid values are:
+      8, 15      for "altr,socfpga-denali-nand"
+      8, 16, 24  for "socionext,uniphier-denali-nand-v5a"
+      8, 16      for "socionext,uniphier-denali-nand-v5b"
+  - nand-ecc-maximize: see nand.txt for details
+
 The device tree may optionally contain sub-nodes describing partitions of the
 address space. See partition.txt for more detail.
 
index 8c1528c..59ddc61 100644 (file)
@@ -1,7 +1,7 @@
 Error location module
 
 Required properties:
-- compatible: Must be "ti,am33xx-elm"
+- compatible: Must be "ti,am3352-elm"
 - reg: physical base address and size of the registers map.
 - interrupts: Interrupt number for the elm.
 
index 174f68c..dd55904 100644 (file)
@@ -5,7 +5,7 @@ the GPMC controller with a name of "nand".
 
 All timing relevant properties as well as generic gpmc child properties are
 explained in a separate documents - please refer to
-Documentation/devicetree/bindings/bus/ti-gpmc.txt
+Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
 
 For NAND specific properties such as ECC modes or bus width, please refer to
 Documentation/devicetree/bindings/mtd/nand.txt
index 4828c17..131d3a7 100644 (file)
@@ -5,7 +5,7 @@ child nodes of the GPMC controller with a name of "nor".
 
 All timing relevant properties as well as generic GPMC child properties are
 explained in a separate documents. Please refer to
-Documentation/devicetree/bindings/bus/ti-gpmc.txt
+Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
 
 Required properties:
 - bank-width:          Width of NOR flash in bytes. GPMC supports 8-bit and
@@ -28,7 +28,7 @@ Required properties:
 
 Optional properties:
 - gpmc,XXX             Additional GPMC timings and settings parameters. See
-                       Documentation/devicetree/bindings/bus/ti-gpmc.txt
+                       Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
 
 Optional properties for partition table parsing:
 - #address-cells: should be set to 1
index 5d8fa52..b6e8bfd 100644 (file)
@@ -5,7 +5,7 @@ the GPMC controller with a name of "onenand".
 
 All timing relevant properties as well as generic gpmc child properties are
 explained in a separate documents - please refer to
-Documentation/devicetree/bindings/bus/ti-gpmc.txt
+Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
 
 Required properties:
 
index d02acaf..b289ef3 100644 (file)
@@ -4,7 +4,12 @@ The GPMI nand controller provides an interface to control the
 NAND flash chips.
 
 Required properties:
-  - compatible : should be "fsl,<chip>-gpmi-nand"
+  - compatible : should be "fsl,<chip>-gpmi-nand", chip can be:
+    * imx23
+    * imx28
+    * imx6q
+    * imx6sx
+    * imx7d
   - reg : should contain registers location and length for gpmi and bch.
   - reg-names: Should contain the reg names "gpmi-nand" and "bch"
   - interrupts : BCH interrupt number.
@@ -13,6 +18,13 @@ Required properties:
     and GPMI DMA channel ID.
     Refer to dma.txt and fsl-mxs-dma.txt for details.
   - dma-names: Must be "rx-tx".
+  - clocks : clocks phandle and clock specifier corresponding to each clock
+    specified in clock-names.
+  - clock-names : The "gpmi_io" clock is always required. Which clocks are
+    exactly required depends on chip:
+    * imx23/imx28 : "gpmi_io"
+    * imx6q/sx : "gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch"
+    * imx7d : "gpmi_io", "gpmi_bch_apb"
 
 Optional properties:
   - nand-on-flash-bbt: boolean to enable on flash bbt option if not
diff --git a/Documentation/devicetree/bindings/mtd/microchip,mchp23k256.txt b/Documentation/devicetree/bindings/mtd/microchip,mchp23k256.txt
new file mode 100644 (file)
index 0000000..7328eb9
--- /dev/null
@@ -0,0 +1,18 @@
+* MTD SPI driver for Microchip 23K256 (and similar) serial SRAM
+
+Required properties:
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+  representing partitions.
+- compatible : Must be one of "microchip,mchp23k256" or "microchip,mchp23lcv1024"
+- reg : Chip-Select number
+- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at
+
+Example:
+
+       spi-sram@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "microchip,mchp23k256";
+               reg = <0>;
+               spi-max-frequency = <20000000>;
+       };
index 069c192..dbf9e05 100644 (file)
@@ -12,7 +12,8 @@ tree nodes.
 
 The first part of NFC is NAND Controller Interface (NFI) HW.
 Required NFI properties:
-- compatible:                  Should be "mediatek,mtxxxx-nfc".
+- compatible:                  Should be one of "mediatek,mt2701-nfc",
+                               "mediatek,mt2712-nfc".
 - reg:                         Base physical address and size of NFI.
 - interrupts:                  Interrupts of NFI.
 - clocks:                      NFI required clocks.
@@ -141,7 +142,7 @@ Example:
 ==============
 
 Required BCH properties:
-- compatible:  Should be "mediatek,mtxxxx-ecc".
+- compatible:  Should be one of "mediatek,mt2701-ecc", "mediatek,mt2712-ecc".
 - reg:         Base physical address and size of ECC.
 - interrupts:  Interrupts of ECC.
 - clocks:      ECC required clocks.
index b056016..133f381 100644 (file)
@@ -21,7 +21,7 @@ Optional NAND chip properties:
 
 - nand-ecc-mode : String, operation mode of the NAND ecc mode.
                  Supported values are: "none", "soft", "hw", "hw_syndrome",
-                 "hw_oob_first".
+                 "hw_oob_first", "on-die".
                  Deprecated values:
                  "soft_bch": use "soft" and nand-ecc-algo instead
 - nand-ecc-algo: string, algorithm of NAND ECC.
index 81a224d..36f3b76 100644 (file)
@@ -1,29 +1,49 @@
-Representing flash partitions in devicetree
+Flash partitions in device tree
+===============================
 
-Partitions can be represented by sub-nodes of an mtd device. This can be used
+Flash devices can be partitioned into one or more functional ranges (e.g. "boot
+code", "nvram", "kernel").
+
+Different devices may be partitioned in a different ways. Some may use a fixed
+flash layout set at production time. Some may use on-flash table that describes
+the geometry and naming/purpose of each functional region. It is also possible
+to see these methods mixed.
+
+To assist system software in locating partitions, we allow describing which
+method is used for a given flash device. To describe the method there should be
+a subnode of the flash device that is named 'partitions'. It must have a
+'compatible' property, which is used to identify the method to use.
+
+We currently only document a binding for fixed layouts.
+
+
+Fixed Partitions
+================
+
+Partitions can be represented by sub-nodes of a flash device. This can be used
 on platforms which have strong conventions about which portions of a flash are
 used for what purposes, but which don't use an on-flash partition table such
 as RedBoot.
 
-The partition table should be a subnode of the mtd node and should be named
+The partition table should be a subnode of the flash node and should be named
 'partitions'. This node should have the following property:
 - compatible : (required) must be "fixed-partitions"
 Partitions are then defined in subnodes of the partitions node.
 
-For backwards compatibility partitions as direct subnodes of the mtd device are
+For backwards compatibility partitions as direct subnodes of the flash device are
 supported. This use is discouraged.
 NOTE: also for backwards compatibility, direct subnodes that have a compatible
 string are not considered partitions, as they may be used for other bindings.
 
 #address-cells & #size-cells must both be present in the partitions subnode of the
-mtd device. There are two valid values for both:
+flash device. There are two valid values for both:
 <1>: for partitions that require a single 32-bit cell to represent their
      size/address (aka the value is below 4 GiB)
 <2>: for partitions that require two 32-bit cells to represent their
      size/address (aka the value is 4 GiB or greater).
 
 Required properties:
-- reg : The partition's offset and size within the mtd bank.
+- reg : The partition's offset and size within the flash
 
 Optional properties:
 - label : The label / name for this partition.  If omitted, the label is taken
index 2fefa1a..ad16c1f 100644 (file)
@@ -11,6 +11,7 @@ Required properties:
  - reg-names:  Names of the registers.
                "amac_base":    Address and length of the GMAC registers
                "idm_base":     Address and length of the GMAC IDM registers
+                               (required for NSP and Northstar2)
                "nicpm_base":   Address and length of the NIC Port Manager
                                registers (required for Northstar2)
  - interrupts: Interrupt number
diff --git a/Documentation/devicetree/bindings/net/brcm,bgmac-nsp.txt b/Documentation/devicetree/bindings/net/brcm,bgmac-nsp.txt
deleted file mode 100644 (file)
index 022946c..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Broadcom GMAC Ethernet Controller Device Tree Bindings
--------------------------------------------------------------
-
-Required properties:
- - compatible: "brcm,bgmac-nsp"
- - reg:                Address and length of the GMAC registers,
-               Address and length of the GMAC IDM registers
- - reg-names:  Names of the registers.  Must have both "gmac_base" and
-               "idm_base"
- - interrupts: Interrupt number
-
-Optional properties:
-- mac-address: See ethernet.txt file in the same directory
-
-Examples:
-
-gmac0: ethernet@18022000 {
-       compatible = "brcm,bgmac-nsp";
-       reg = <0x18022000 0x1000>,
-             <0x18110000 0x1000>;
-       reg-names = "gmac_base", "idm_base";
-       interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
-       status = "disabled";
-};
index ace4a64..f7da3d7 100644 (file)
@@ -9,7 +9,7 @@ the GPMC controller with an "ethernet" name.
 
 All timing relevant properties as well as generic GPMC child properties are
 explained in a separate documents. Please refer to
-Documentation/devicetree/bindings/bus/ti-gpmc.txt
+Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
 
 For the properties relevant to the ethernet controller connected to the GPMC
 refer to the binding documentation of the device. For example, the documentation
@@ -43,7 +43,7 @@ Required properties:
 
 Optional properties:
 - gpmc,XXX             Additional GPMC timings and settings parameters. See
-                       Documentation/devicetree/bindings/bus/ti-gpmc.txt
+                       Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
 
 Example:
 
index c7194e8..1d1168b 100644 (file)
@@ -7,24 +7,30 @@ have dual GMAC each represented by a child node..
 * Ethernet controller node
 
 Required properties:
-- compatible: Should be "mediatek,mt2701-eth"
+- compatible: Should be
+               "mediatek,mt2701-eth": for MT2701 SoC
+               "mediatek,mt7623-eth", "mediatek,mt2701-eth": for MT7623 SoC
+               "mediatek,mt7622-eth": for MT7622 SoC
 - reg: Address and length of the register set for the device
 - interrupts: Should contain the three frame engines interrupts in numeric
        order. These are fe_int0, fe_int1 and fe_int2.
 - clocks: the clock used by the core
 - clock-names: the names of the clock listed in the clocks property. These are
-       "ethif", "esw", "gp2", "gp1"
+       "ethif", "esw", "gp2", "gp1" : For MT2701 and MT7623 SoC
+        "ethif", "esw", "gp0", "gp1", "gp2", "sgmii_tx250m", "sgmii_rx250m",
+       "sgmii_cdr_ref", "sgmii_cdr_fb", "sgmii_ck", "eth2pll" : For MT7622 SoC
 - power-domains: phandle to the power domain that the ethernet is part of
 - resets: Should contain a phandle to the ethsys reset signal
 - reset-names: Should contain the reset signal name "eth"
 - mediatek,ethsys: phandle to the syscon node that handles the port setup
+- mediatek,sgmiisys: phandle to the syscon node that handles the SGMII setup
+       which is required for those SoCs equipped with SGMII such as MT7622 SoC.
 - mediatek,pctl: phandle to the syscon node that handles the ports slew rate
        and driver current
 
 Optional properties:
 - interrupt-parent: Should be the phandle for the interrupt controller
   that services interrupts for this device
-
 * Ethernet MAC node
 
 Required properties:
index 194926f..1ff02af 100644 (file)
@@ -4,7 +4,7 @@ Required properties:
 - compatible: Should be one of the following.
   - "rockchip,rk3066a-efuse" - for RK3066a SoCs.
   - "rockchip,rk3188-efuse" - for RK3188 SoCs.
-  - "rockchip,rk322x-efuse" - for RK322x SoCs.
+  - "rockchip,rk3228-efuse" - for RK3228 SoCs.
   - "rockchip,rk3288-efuse" - for RK3288 SoCs.
   - "rockchip,rk3399-efuse" - for RK3399 SoCs.
 - reg: Should contain the registers location and exact eFuse size
index 07590bc..7c04e22 100644 (file)
@@ -1,13 +1,20 @@
-* Broadcom Digital Timing Engine(DTE) based PTP clock driver
+* Broadcom Digital Timing Engine(DTE) based PTP clock
 
 Required properties:
-- compatible: should be "brcm,ptp-dte"
+- compatible: should contain the core compatibility string
+              and the SoC compatibility string. The SoC
+              compatibility string is to handle SoC specific
+              hardware differences.
+              Core compatibility string:
+                 "brcm,ptp-dte"
+              SoC compatibility strings:
+                 "brcm,iproc-ptp-dte" - for iproc based SoC's
 - reg: address and length of the DTE block's NCO registers
 
 Example:
 
-ptp_dte: ptp_dte@180af650 {
-       compatible = "brcm,ptp-dte";
+ptp: ptp-dte@180af650 {
+       compatible = "brcm,iproc-ptp-dte", "brcm,ptp-dte";
        reg = <0x180af650 0x10>;
        status = "okay";
 };
index 5376a44..5b07beb 100644 (file)
@@ -2,7 +2,9 @@ Amlogic Meson PWM Controller
 ============================
 
 Required properties:
-- compatible: Shall contain "amlogic,meson8b-pwm" or "amlogic,meson-gxbb-pwm".
+- compatible: Shall contain "amlogic,meson8b-pwm"
+                         or "amlogic,meson-gxbb-pwm"
+                         or "amlogic,meson-gxbb-ao-pwm"
 - #pwm-cells: Should be 3. See pwm.txt in this directory for a description of
   the cells format.
 
index 6dd0403..3e6d550 100644 (file)
@@ -24,7 +24,7 @@ Example:
                compatible = "st,stm32-timers";
                reg = <0x40010000 0x400>;
                clocks = <&rcc 0 160>;
-               clock-names = "clk_int";
+               clock-names = "int";
 
                pwm {
                        compatible = "st,stm32-pwm";
index d6de643..7e94b80 100644 (file)
@@ -8,6 +8,7 @@ Required Properties:
  - "renesas,pwm-r8a7791": for R-Car M2-W
  - "renesas,pwm-r8a7794": for R-Car E2
  - "renesas,pwm-r8a7795": for R-Car H3
+ - "renesas,pwm-r8a7796": for R-Car M3-W
 - reg: base address and length of the registers block for the PWM.
 - #pwm-cells: should be 2. See pwm.txt in this directory for a description of
   the cells format.
diff --git a/Documentation/devicetree/bindings/rtc/brcm,brcmstb-waketimer.txt b/Documentation/devicetree/bindings/rtc/brcm,brcmstb-waketimer.txt
new file mode 100644 (file)
index 0000000..1d990bc
--- /dev/null
@@ -0,0 +1,22 @@
+Broadcom STB wake-up Timer
+
+The Broadcom STB wake-up timer provides a 27Mhz resolution timer, with the
+ability to wake up the system from low-power suspend/standby modes.
+
+Required properties:
+- compatible     : should contain "brcm,brcmstb-waketimer"
+- reg            : the register start and length for the WKTMR block
+- interrupts     : The TIMER interrupt
+- interrupt-parent: The phandle to the Always-On (AON) Power Management (PM) L2
+                    interrupt controller node
+- clocks        : The phandle to the UPG fixed clock (27Mhz domain)
+
+Example:
+
+waketimer@f0411580 {
+       compatible = "brcm,brcmstb-waketimer";
+       reg = <0xf0411580 0x14>;
+       interrupts = <0x3>;
+       interrupt-parent = <&aon_pm_l2_intc>;
+       clocks = <&upg_fixed>;
+};
diff --git a/Documentation/devicetree/bindings/rtc/cortina,gemini.txt b/Documentation/devicetree/bindings/rtc/cortina,gemini.txt
deleted file mode 100644 (file)
index 4ce4e79..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-* Cortina Systems Gemini RTC
-
-Gemini SoC real-time clock.
-
-Required properties:
-- compatible : Should be "cortina,gemini-rtc"
-
-Examples:
-
-rtc@45000000 {
-       compatible = "cortina,gemini-rtc";
-       reg = <0x45000000 0x100>;
-       interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
-};
diff --git a/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt b/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt
new file mode 100644 (file)
index 0000000..e3938f5
--- /dev/null
@@ -0,0 +1,28 @@
+* Faraday Technology FTRTC010 Real Time Clock
+
+This RTC appears in for example the Storlink Gemini family of
+SoCs.
+
+Required properties:
+- compatible : Should be one of:
+  "faraday,ftrtc010"
+  "cortina,gemini-rtc", "faraday,ftrtc010"
+
+Optional properties:
+- clocks: when present should contain clock references to the
+  PCLK and EXTCLK clocks. Faraday calls the later CLK1HZ and
+  says the clock should be 1 Hz, but implementers actually seem
+  to choose different clocks here, like Cortina who chose
+  32768 Hz (a typical low-power clock).
+- clock-names: should name the clocks "PCLK" and "EXTCLK"
+  respectively.
+
+Examples:
+
+rtc@45000000 {
+       compatible = "cortina,gemini-rtc";
+       reg = <0x45000000 0x100>;
+       interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
+       clocks = <&foo 0>, <&foo 1>;
+       clock-names = "PCLK", "EXTCLK";
+};
index e2837b9..0a4c371 100644 (file)
@@ -1,17 +1,25 @@
 STM32 Real Time Clock
 
 Required properties:
-- compatible: "st,stm32-rtc".
+- compatible: can be either "st,stm32-rtc" or "st,stm32h7-rtc", depending on
+  the device is compatible with stm32(f4/f7) or stm32h7.
 - reg: address range of rtc register set.
-- clocks: reference to the clock entry ck_rtc.
+- clocks: can use up to two clocks, depending on part used:
+  - "rtc_ck": RTC clock source.
+    It is required on stm32(f4/f7) and stm32h7.
+  - "pclk": RTC APB interface clock.
+    It is not present on stm32(f4/f7).
+    It is required on stm32h7.
+- clock-names: must be "rtc_ck" and "pclk".
+    It is required only on stm32h7.
 - interrupt-parent: phandle for the interrupt controller.
 - interrupts: rtc alarm interrupt.
 - st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
   (RTC registers) write protection.
 
-Optional properties (to override default ck_rtc parent clock):
-- assigned-clocks: reference to the ck_rtc clock entry.
-- assigned-clock-parents: phandle of the new parent clock of ck_rtc.
+Optional properties (to override default rtc_ck parent clock):
+- assigned-clocks: reference to the rtc_ck clock entry.
+- assigned-clock-parents: phandle of the new parent clock of rtc_ck.
 
 Example:
 
@@ -25,3 +33,17 @@ Example:
                interrupts = <17 1>;
                st,syscfg = <&pwrcfg>;
        };
+
+       rtc: rtc@58004000 {
+               compatible = "st,stm32h7-rtc";
+               reg = <0x58004000 0x400>;
+               clocks = <&rcc RTCAPB_CK>, <&rcc RTC_CK>;
+               clock-names = "pclk", "rtc_ck";
+               assigned-clocks = <&rcc RTC_CK>;
+               assigned-clock-parents = <&rcc LSE_CK>;
+               interrupt-parent = <&exti>;
+               interrupts = <17 1>;
+               interrupt-names = "alarm";
+               st,syscfg = <&pwrcfg>;
+               status = "disabled";
+       };
index e6b5724..574c3a2 100644 (file)
@@ -9,7 +9,6 @@ Optional properties:
 - fsl,irda-mode : Indicate the uart supports irda mode
 - fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
                   in DCE mode by default.
-- fsl,dma-size : Indicate the size of the DMA buffer and its periods
 
 Please check Documentation/devicetree/bindings/serial/serial.txt
 for the complete list of generic properties.
@@ -29,5 +28,4 @@ uart1: serial@73fbc000 {
        interrupts = <31>;
        uart-has-rtscts;
        fsl,dte-mode;
-       fsl,dma-size = <1024 4>;
 };
index 3f68288..f6a8902 100644 (file)
@@ -1,13 +1,20 @@
+==================================
 Digital Signature Verification API
+==================================
 
-CONTENTS
+:Author: Dmitry Kasatkin
+:Date: 06.10.2011
 
-1. Introduction
-2. API
-3. User-space utilities
 
+.. CONTENTS
 
-1. Introduction
+   1. Introduction
+   2. API
+   3. User-space utilities
+
+
+Introduction
+============
 
 Digital signature verification API provides a method to verify digital signature.
 Currently digital signatures are used by the IMA/EVM integrity protection subsystem.
@@ -17,25 +24,25 @@ GnuPG multi-precision integers (MPI) library. The kernel port provides
 memory allocation errors handling, has been refactored according to kernel
 coding style, and checkpatch.pl reported errors and warnings have been fixed.
 
-Public key and signature consist of header and MPIs.
-
-struct pubkey_hdr {
-       uint8_t         version;        /* key format version */
-       time_t          timestamp;      /* key made, always 0 for now */
-       uint8_t         algo;
-       uint8_t         nmpi;
-       char            mpi[0];
-} __packed;
-
-struct signature_hdr {
-       uint8_t         version;        /* signature format version */
-       time_t          timestamp;      /* signature made */
-       uint8_t         algo;
-       uint8_t         hash;
-       uint8_t         keyid[8];
-       uint8_t         nmpi;
-       char            mpi[0];
-} __packed;
+Public key and signature consist of header and MPIs::
+
+       struct pubkey_hdr {
+               uint8_t         version;        /* key format version */
+               time_t          timestamp;      /* key made, always 0 for now */
+               uint8_t         algo;
+               uint8_t         nmpi;
+               char            mpi[0];
+       } __packed;
+
+       struct signature_hdr {
+               uint8_t         version;        /* signature format version */
+               time_t          timestamp;      /* signature made */
+               uint8_t         algo;
+               uint8_t         hash;
+               uint8_t         keyid[8];
+               uint8_t         nmpi;
+               char            mpi[0];
+       } __packed;
 
 keyid equals to SHA1[12-19] over the total key content.
 Signature header is used as an input to generate a signature.
@@ -43,31 +50,33 @@ Such approach insures that key or signature header could not be changed.
 It protects timestamp from been changed and can be used for rollback
 protection.
 
-2. API
+API
+===
 
-API currently includes only 1 function:
+API currently includes only 1 function::
 
        digsig_verify() - digital signature verification with public key
 
 
-/**
- * digsig_verify() - digital signature verification with public key
- * @keyring:   keyring to search key in
- * @sig:       digital signature
- * @sigen:     length of the signature
- * @data:      data
- * @datalen:   length of the data
- * @return:    0 on success, -EINVAL otherwise
- *
- * Verifies data integrity against digital signature.
- * Currently only RSA is supported.
- * Normally hash of the content is used as a data for this function.
- *
- */
-int digsig_verify(struct key *keyring, const char *sig, int siglen,
-                                               const char *data, int datalen);
-
-3. User-space utilities
+       /**
+       * digsig_verify() - digital signature verification with public key
+       * @keyring:     keyring to search key in
+       * @sig: digital signature
+       * @sigen:       length of the signature
+       * @data:        data
+       * @datalen:     length of the data
+       * @return:      0 on success, -EINVAL otherwise
+       *
+       * Verifies data integrity against digital signature.
+       * Currently only RSA is supported.
+       * Normally hash of the content is used as a data for this function.
+       *
+       */
+       int digsig_verify(struct key *keyring, const char *sig, int siglen,
+                         const char *data, int datalen);
+
+User-space utilities
+====================
 
 The signing and key management utilities evm-utils provide functionality
 to generate signatures, to load keys into the kernel keyring.
@@ -75,22 +84,18 @@ Keys can be in PEM or converted to the kernel format.
 When the key is added to the kernel keyring, the keyid defines the name
 of the key: 5D2B05FC633EE3E8 in the example bellow.
 
-Here is example output of the keyctl utility.
-
-$ keyctl show
-Session Keyring
-       -3 --alswrv      0     0  keyring: _ses
-603976250 --alswrv      0    -1   \_ keyring: _uid.0
-817777377 --alswrv      0     0       \_ user: kmk
-891974900 --alswrv      0     0       \_ encrypted: evm-key
-170323636 --alswrv      0     0       \_ keyring: _module
-548221616 --alswrv      0     0       \_ keyring: _ima
-128198054 --alswrv      0     0       \_ keyring: _evm
-
-$ keyctl list 128198054
-1 key in keyring:
-620789745: --alswrv     0     0 user: 5D2B05FC633EE3E8
-
-
-Dmitry Kasatkin
-06.10.2011
+Here is example output of the keyctl utility::
+
+       $ keyctl show
+       Session Keyring
+       -3 --alswrv      0     0  keyring: _ses
+       603976250 --alswrv      0    -1   \_ keyring: _uid.0
+       817777377 --alswrv      0     0       \_ user: kmk
+       891974900 --alswrv      0     0       \_ encrypted: evm-key
+       170323636 --alswrv      0     0       \_ keyring: _module
+       548221616 --alswrv      0     0       \_ keyring: _ima
+       128198054 --alswrv      0     0       \_ keyring: _evm
+
+       $ keyctl list 128198054
+       1 key in keyring:
+       620789745: --alswrv     0     0 user: 5D2B05FC633EE3E8
index 472e7a6..ab82250 100644 (file)
@@ -106,9 +106,6 @@ Kernel utility functions
 .. kernel-doc:: kernel/sys.c
    :export:
 
-.. kernel-doc:: kernel/rcu/srcu.c
-   :export:
-
 .. kernel-doc:: kernel/rcu/tree.c
    :export:
 
index e157469..41df801 100644 (file)
@@ -1,5 +1,6 @@
-                         The EFI Boot Stub
-                    ---------------------------
+=================
+The EFI Boot Stub
+=================
 
 On the x86 and ARM platforms, a kernel zImage/bzImage can masquerade
 as a PE/COFF image, thereby convincing EFI firmware loaders to load
@@ -25,7 +26,8 @@ a certain sense it *IS* the boot loader.
 The EFI boot stub is enabled with the CONFIG_EFI_STUB kernel option.
 
 
-**** How to install bzImage.efi
+How to install bzImage.efi
+--------------------------
 
 The bzImage located in arch/x86/boot/bzImage must be copied to the EFI
 System Partition (ESP) and renamed with the extension ".efi". Without
@@ -37,14 +39,16 @@ may not need to be renamed. Similarly for arm64, arch/arm64/boot/Image
 should be copied but not necessarily renamed.
 
 
-**** Passing kernel parameters from the EFI shell
+Passing kernel parameters from the EFI shell
+--------------------------------------------
 
-Arguments to the kernel can be passed after bzImage.efi, e.g.
+Arguments to the kernel can be passed after bzImage.efi, e.g.::
 
        fs0:> bzImage.efi console=ttyS0 root=/dev/sda4
 
 
-**** The "initrd=" option
+The "initrd=" option
+--------------------
 
 Like most boot loaders, the EFI stub allows the user to specify
 multiple initrd files using the "initrd=" option. This is the only EFI
@@ -54,9 +58,9 @@ kernel when it boots.
 The path to the initrd file must be an absolute path from the
 beginning of the ESP, relative path names do not work. Also, the path
 is an EFI-style path and directory elements must be separated with
-backslashes (\). For example, given the following directory layout,
+backslashes (\). For example, given the following directory layout::
 
-fs0:>
+  fs0:>
        Kernels\
                        bzImage.efi
                        initrd-large.img
@@ -66,7 +70,7 @@ fs0:>
                        initrd-medium.img
 
 to boot with the initrd-large.img file if the current working
-directory is fs0:\Kernels, the following command must be used,
+directory is fs0:\Kernels, the following command must be used::
 
        fs0:\Kernels> bzImage.efi initrd=\Kernels\initrd-large.img
 
@@ -76,7 +80,8 @@ which understands relative paths, whereas the rest of the command line
 is passed to bzImage.efi.
 
 
-**** The "dtb=" option
+The "dtb=" option
+-----------------
 
 For the ARM and arm64 architectures, we also need to be able to provide a
 device tree to the kernel. This is done with the "dtb=" command line option,
index a55e491..2806e55 100644 (file)
@@ -1,4 +1,8 @@
-EISA bus support (Marc Zyngier <maz@wild-wind.fr.eu.org>)
+================
+EISA bus support
+================
+
+:Author: Marc Zyngier <maz@wild-wind.fr.eu.org>
 
 This document groups random notes about porting EISA drivers to the
 new EISA/sysfs API.
@@ -14,168 +18,189 @@ detection code is generally also used to probe ISA cards). Moreover,
 most EISA drivers are among the oldest Linux drivers so, as you can
 imagine, some dust has settled here over the years.
 
-The EISA infrastructure is made up of three parts :
+The EISA infrastructure is made up of three parts:
 
     - The bus code implements most of the generic code. It is shared
-    among all the architectures that the EISA code runs on. It
-    implements bus probing (detecting EISA cards available on the bus),
-    allocates I/O resources, allows fancy naming through sysfs, and
-    offers interfaces for driver to register.
+      among all the architectures that the EISA code runs on. It
+      implements bus probing (detecting EISA cards available on the bus),
+      allocates I/O resources, allows fancy naming through sysfs, and
+      offers interfaces for driver to register.
 
     - The bus root driver implements the glue between the bus hardware
-    and the generic bus code. It is responsible for discovering the
-    device implementing the bus, and setting it up to be latter probed
-    by the bus code. This can go from something as simple as reserving
-    an I/O region on x86, to the rather more complex, like the hppa
-    EISA code. This is the part to implement in order to have EISA
-    running on an "new" platform.
+      and the generic bus code. It is responsible for discovering the
+      device implementing the bus, and setting it up to be latter probed
+      by the bus code. This can go from something as simple as reserving
+      an I/O region on x86, to the rather more complex, like the hppa
+      EISA code. This is the part to implement in order to have EISA
+      running on an "new" platform.
 
     - The driver offers the bus a list of devices that it manages, and
-    implements the necessary callbacks to probe and release devices
-    whenever told to.
+      implements the necessary callbacks to probe and release devices
+      whenever told to.
 
 Every function/structure below lives in <linux/eisa.h>, which depends
 heavily on <linux/device.h>.
 
-** Bus root driver :
+Bus root driver
+===============
+
+::
 
-int eisa_root_register (struct eisa_root_device *root);
+       int eisa_root_register (struct eisa_root_device *root);
 
 The eisa_root_register function is used to declare a device as the
 root of an EISA bus. The eisa_root_device structure holds a reference
-to this device, as well as some parameters for probing purposes.
-
-struct eisa_root_device {
-       struct device   *dev;    /* Pointer to bridge device */
-       struct resource *res;
-       unsigned long    bus_base_addr;
-       int              slots;  /* Max slot number */
-       int              force_probe; /* Probe even when no slot 0 */
-       u64              dma_mask; /* from bridge device */
-       int              bus_nr; /* Set by eisa_root_register */
-       struct resource  eisa_root_res; /* ditto */
-};
-
-node          : used for eisa_root_register internal purpose
-dev           : pointer to the root device
-res           : root device I/O resource
-bus_base_addr : slot 0 address on this bus
-slots        : max slot number to probe
-force_probe   : Probe even when slot 0 is empty (no EISA mainboard)
-dma_mask      : Default DMA mask. Usually the bridge device dma_mask.
-bus_nr       : unique bus id, set by eisa_root_register
-
-** Driver :
-
-int eisa_driver_register (struct eisa_driver *edrv);
-void eisa_driver_unregister (struct eisa_driver *edrv);
+to this device, as well as some parameters for probing purposes::
+
+       struct eisa_root_device {
+               struct device   *dev;    /* Pointer to bridge device */
+               struct resource *res;
+               unsigned long    bus_base_addr;
+               int              slots;  /* Max slot number */
+               int              force_probe; /* Probe even when no slot 0 */
+               u64              dma_mask; /* from bridge device */
+               int              bus_nr; /* Set by eisa_root_register */
+               struct resource  eisa_root_res; /* ditto */
+       };
+
+============= ======================================================
+node          used for eisa_root_register internal purpose
+dev           pointer to the root device
+res           root device I/O resource
+bus_base_addr slot 0 address on this bus
+slots        max slot number to probe
+force_probe   Probe even when slot 0 is empty (no EISA mainboard)
+dma_mask      Default DMA mask. Usually the bridge device dma_mask.
+bus_nr       unique bus id, set by eisa_root_register
+============= ======================================================
+
+Driver
+======
+
+::
+
+       int eisa_driver_register (struct eisa_driver *edrv);
+       void eisa_driver_unregister (struct eisa_driver *edrv);
 
 Clear enough ?
 
-struct eisa_device_id {
-        char sig[EISA_SIG_LEN];
-       unsigned long driver_data;
-};
-
-struct eisa_driver {
-        const struct eisa_device_id *id_table;
-        struct device_driver         driver;
-};
-
-id_table       : an array of NULL terminated EISA id strings,
-                 followed by an empty string. Each string can
-                 optionally be paired with a driver-dependent value
-                 (driver_data).
-
-driver         : a generic driver, such as described in
-                 Documentation/driver-model/driver.txt. Only .name,
-                 .probe and .remove members are mandatory.
-
-An example is the 3c59x driver :
-
-static struct eisa_device_id vortex_eisa_ids[] = {
-       { "TCM5920", EISA_3C592_OFFSET },
-       { "TCM5970", EISA_3C597_OFFSET },
-       { "" }
-};
-
-static struct eisa_driver vortex_eisa_driver = {
-       .id_table = vortex_eisa_ids,
-       .driver   = {
-               .name    = "3c59x",
-               .probe   = vortex_eisa_probe,
-               .remove  = vortex_eisa_remove
-       }
-};
-
-** Device :
+::
+
+       struct eisa_device_id {
+               char sig[EISA_SIG_LEN];
+               unsigned long driver_data;
+       };
+
+       struct eisa_driver {
+               const struct eisa_device_id *id_table;
+               struct device_driver         driver;
+       };
+
+=============== ====================================================
+id_table       an array of NULL terminated EISA id strings,
+               followed by an empty string. Each string can
+               optionally be paired with a driver-dependent value
+               (driver_data).
+
+driver         a generic driver, such as described in
+               Documentation/driver-model/driver.txt. Only .name,
+               .probe and .remove members are mandatory.
+=============== ====================================================
+
+An example is the 3c59x driver::
+
+       static struct eisa_device_id vortex_eisa_ids[] = {
+               { "TCM5920", EISA_3C592_OFFSET },
+               { "TCM5970", EISA_3C597_OFFSET },
+               { "" }
+       };
+
+       static struct eisa_driver vortex_eisa_driver = {
+               .id_table = vortex_eisa_ids,
+               .driver   = {
+                       .name    = "3c59x",
+                       .probe   = vortex_eisa_probe,
+                       .remove  = vortex_eisa_remove
+               }
+       };
+
+Device
+======
 
 The sysfs framework calls .probe and .remove functions upon device
 discovery and removal (note that the .remove function is only called
 when driver is built as a module).
 
 Both functions are passed a pointer to a 'struct device', which is
-encapsulated in a 'struct eisa_device' described as follows :
-
-struct eisa_device {
-        struct eisa_device_id id;
-        int                   slot;
-       int                   state;
-       unsigned long         base_addr;
-       struct resource       res[EISA_MAX_RESOURCES];
-       u64                   dma_mask;
-        struct device         dev; /* generic device */
-};
-
-id     : EISA id, as read from device. id.driver_data is set from the
-         matching driver EISA id.
-slot   : slot number which the device was detected on
-state   : set of flags indicating the state of the device. Current
-         flags are EISA_CONFIG_ENABLED and EISA_CONFIG_FORCED.
-res    : set of four 256 bytes I/O regions allocated to this device
-dma_mask: DMA mask set from the parent device.
-dev    : generic device (see Documentation/driver-model/device.txt)
+encapsulated in a 'struct eisa_device' described as follows::
+
+       struct eisa_device {
+               struct eisa_device_id id;
+               int                   slot;
+               int                   state;
+               unsigned long         base_addr;
+               struct resource       res[EISA_MAX_RESOURCES];
+               u64                   dma_mask;
+               struct device         dev; /* generic device */
+       };
+
+======== ============================================================
+id      EISA id, as read from device. id.driver_data is set from the
+        matching driver EISA id.
+slot    slot number which the device was detected on
+state    set of flags indicating the state of the device. Current
+        flags are EISA_CONFIG_ENABLED and EISA_CONFIG_FORCED.
+res     set of four 256 bytes I/O regions allocated to this device
+dma_mask DMA mask set from the parent device.
+dev     generic device (see Documentation/driver-model/device.txt)
+======== ============================================================
 
 You can get the 'struct eisa_device' from 'struct device' using the
 'to_eisa_device' macro.
 
-** Misc stuff :
+Misc stuff
+==========
+
+::
 
-void eisa_set_drvdata (struct eisa_device *edev, void *data);
+       void eisa_set_drvdata (struct eisa_device *edev, void *data);
 
 Stores data into the device's driver_data area.
 
-void *eisa_get_drvdata (struct eisa_device *edev):
+::
+
+       void *eisa_get_drvdata (struct eisa_device *edev):
 
 Gets the pointer previously stored into the device's driver_data area.
 
-int eisa_get_region_index (void *addr);
+::
+
+       int eisa_get_region_index (void *addr);
 
 Returns the region number (0 <= x < EISA_MAX_RESOURCES) of a given
 address.
 
-** Kernel parameters :
+Kernel parameters
+=================
 
-eisa_bus.enable_dev :
+eisa_bus.enable_dev
+       A comma-separated list of slots to be enabled, even if the firmware
+       set the card as disabled. The driver must be able to properly
+       initialize the device in such conditions.
 
-A comma-separated list of slots to be enabled, even if the firmware
-set the card as disabled. The driver must be able to properly
-initialize the device in such conditions.
+eisa_bus.disable_dev
+       A comma-separated list of slots to be enabled, even if the firmware
+       set the card as enabled. The driver won't be called to handle this
+       device.
 
-eisa_bus.disable_dev :
+virtual_root.force_probe
+       Force the probing code to probe EISA slots even when it cannot find an
+       EISA compliant mainboard (nothing appears on slot 0). Defaults to 0
+       (don't force), and set to 1 (force probing) when either
+       CONFIG_ALPHA_JENSEN or CONFIG_EISA_VLB_PRIMING are set.
 
-A comma-separated list of slots to be enabled, even if the firmware
-set the card as enabled. The driver won't be called to handle this
-device.
-
-virtual_root.force_probe :
-
-Force the probing code to probe EISA slots even when it cannot find an
-EISA compliant mainboard (nothing appears on slot 0). Defaults to 0
-(don't force), and set to 1 (force probing) when either
-CONFIG_ALPHA_JENSEN or CONFIG_EISA_VLB_PRIMING are set.
-
-** Random notes :
+Random notes
+============
 
 Converting an EISA driver to the new API mostly involves *deleting*
 code (since probing is now in the core EISA code). Unfortunately, most
@@ -194,9 +219,11 @@ routine.
 For example, switching your favorite EISA SCSI card to the "hotplug"
 model is "the right thing"(tm).
 
-** Thanks :
+Thanks
+======
+
+I'd like to thank the following people for their help:
 
-I'd like to thank the following people for their help :
 - Xavier Benigni for lending me a wonderful Alpha Jensen,
 - James Bottomley, Jeff Garzik for getting this stuff into the kernel,
 - Andries Brouwer for contributing numerous EISA ids,
index 415484f..918972b 100644 (file)
@@ -134,6 +134,23 @@ use the boot option:
        fail_futex=
        mmc_core.fail_request=<interval>,<probability>,<space>,<times>
 
+o proc entries
+
+- /proc/<pid>/fail-nth:
+- /proc/self/task/<tid>/fail-nth:
+
+       Write to this file of integer N makes N-th call in the task fail.
+       Read from this file returns a integer value. A value of '0' indicates
+       that the fault setup with a previous write to this file was injected.
+       A positive integer N indicates that the fault wasn't yet injected.
+       Note that this file enables all types of faults (slab, futex, etc).
+       This setting takes precedence over all other generic debugfs settings
+       like probability, interval, times, etc. But per-capability settings
+       (e.g. fail_futex/ignore-private) take precedence over it.
+
+       This feature is intended for systematic testing of faults in a single
+       system call. See an example below.
+
 How to add new fault injection capability
 -----------------------------------------
 
@@ -278,3 +295,65 @@ allocation failure.
        # env FAILCMD_TYPE=fail_page_alloc \
                ./tools/testing/fault-injection/failcmd.sh --times=100 \
                 -- make -C tools/testing/selftests/ run_tests
+
+Systematic faults using fail-nth
+---------------------------------
+
+The following code systematically faults 0-th, 1-st, 2-nd and so on
+capabilities in the socketpair() system call.
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+int main()
+{
+       int i, err, res, fail_nth, fds[2];
+       char buf[128];
+
+       system("echo N > /sys/kernel/debug/failslab/ignore-gfp-wait");
+       sprintf(buf, "/proc/self/task/%ld/fail-nth", syscall(SYS_gettid));
+       fail_nth = open(buf, O_RDWR);
+       for (i = 1;; i++) {
+               sprintf(buf, "%d", i);
+               write(fail_nth, buf, strlen(buf));
+               res = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds);
+               err = errno;
+               pread(fail_nth, buf, sizeof(buf), 0);
+               if (res == 0) {
+                       close(fds[0]);
+                       close(fds[1]);
+               }
+               printf("%d-th fault %c: res=%d/%d\n", i, atoi(buf) ? 'N' : 'Y',
+                       res, err);
+               if (atoi(buf))
+                       break;
+       }
+       return 0;
+}
+
+An example output:
+
+1-th fault Y: res=-1/23
+2-th fault Y: res=-1/23
+3-th fault Y: res=-1/12
+4-th fault Y: res=-1/12
+5-th fault Y: res=-1/23
+6-th fault Y: res=-1/23
+7-th fault Y: res=-1/23
+8-th fault Y: res=-1/12
+9-th fault Y: res=-1/12
+10-th fault Y: res=-1/12
+11-th fault Y: res=-1/12
+12-th fault Y: res=-1/12
+13-th fault Y: res=-1/12
+14-th fault Y: res=-1/12
+15-th fault Y: res=-1/12
+16-th fault N: res=0/12
index 4cddbce..adba21b 100644 (file)
@@ -1786,12 +1786,16 @@ pair provide additional information particular to the objects they represent.
        pos:    0
        flags:  02
        mnt_id: 9
-       tfd:        5 events:       1d data: ffffffffffffffff
+       tfd:        5 events:       1d data: ffffffffffffffff pos:0 ino:61af sdev:7
 
        where 'tfd' is a target file descriptor number in decimal form,
        'events' is events mask being watched and the 'data' is data
        associated with a target [see epoll(7) for more details].
 
+       The 'pos' is current offset of the target file in decimal form
+       [see lseek(2)], 'ino' and 'sdev' are inode and device numbers
+       where target file resides, all in hex format.
+
        Fsnotify files
        ~~~~~~~~~~~~~~
        For inotify files the format is the following
index 48c9faa..73e7d91 100644 (file)
@@ -1225,12 +1225,6 @@ The underlying reason for the above rules is to make sure, that a
 mount can be accurately replicated (e.g. umounting and mounting again)
 based on the information found in /proc/mounts.
 
-A simple method of saving options at mount/remount time and showing
-them is provided with the save_mount_options() and
-generic_show_options() helper functions.  Please note, that using
-these may have drawbacks.  For more info see header comments for these
-functions in fs/namespace.c.
-
 Resources
 =========
 
index df904ae..a0f2989 100644 (file)
@@ -1,6 +1,9 @@
+===================================
 Using flexible arrays in the kernel
-Last updated for 2.6.32
-Jonathan Corbet <corbet@lwn.net>
+===================================
+
+:Updated: Last updated for 2.6.32
+:Author: Jonathan Corbet <corbet@lwn.net>
 
 Large contiguous memory allocations can be unreliable in the Linux kernel.
 Kernel programmers will sometimes respond to this problem by allocating
@@ -26,7 +29,7 @@ operation.  It's also worth noting that flexible arrays do no internal
 locking at all; if concurrent access to an array is possible, then the
 caller must arrange for appropriate mutual exclusion.
 
-The creation of a flexible array is done with:
+The creation of a flexible array is done with::
 
     #include <linux/flex_array.h>
 
@@ -40,14 +43,14 @@ argument is passed directly to the internal memory allocation calls.  With
 the current code, using flags to ask for high memory is likely to lead to
 notably unpleasant side effects.
 
-It is also possible to define flexible arrays at compile time with:
+It is also possible to define flexible arrays at compile time with::
 
     DEFINE_FLEX_ARRAY(name, element_size, total);
 
 This macro will result in a definition of an array with the given name; the
 element size and total will be checked for validity at compile time.
 
-Storing data into a flexible array is accomplished with a call to:
+Storing data into a flexible array is accomplished with a call to::
 
     int flex_array_put(struct flex_array *array, unsigned int element_nr,
                       void *src, gfp_t flags);
@@ -63,7 +66,7 @@ running in some sort of atomic context; in this situation, sleeping in the
 memory allocator would be a bad thing.  That can be avoided by using
 GFP_ATOMIC for the flags value, but, often, there is a better way.  The
 trick is to ensure that any needed memory allocations are done before
-entering atomic context, using:
+entering atomic context, using::
 
     int flex_array_prealloc(struct flex_array *array, unsigned int start,
                            unsigned int nr_elements, gfp_t flags);
@@ -73,7 +76,7 @@ defined by start and nr_elements has been allocated.  Thereafter, a
 flex_array_put() call on an element in that range is guaranteed not to
 block.
 
-Getting data back out of the array is done with:
+Getting data back out of the array is done with::
 
     void *flex_array_get(struct flex_array *fa, unsigned int element_nr);
 
@@ -89,7 +92,7 @@ involving that number probably result from use of unstored array entries.
 Note that, if array elements are allocated with __GFP_ZERO, they will be
 initialized to zero and this poisoning will not happen.
 
-Individual elements in the array can be cleared with:
+Individual elements in the array can be cleared with::
 
     int flex_array_clear(struct flex_array *array, unsigned int element_nr);
 
@@ -97,7 +100,7 @@ This function will set the given element to FLEX_ARRAY_FREE and return
 zero.  If storage for the indicated element is not allocated for the array,
 flex_array_clear() will return -EINVAL instead.  Note that clearing an
 element does not release the storage associated with it; to reduce the
-allocated size of an array, call:
+allocated size of an array, call::
 
     int flex_array_shrink(struct flex_array *array);
 
@@ -106,12 +109,12 @@ This function works by scanning the array for pages containing nothing but
 FLEX_ARRAY_FREE bytes, so (1) it can be expensive, and (2) it will not work
 if the array's pages are allocated with __GFP_ZERO.
 
-It is possible to remove all elements of an array with a call to:
+It is possible to remove all elements of an array with a call to::
 
     void flex_array_free_parts(struct flex_array *array);
 
 This call frees all elements, but leaves the array itself in place.
-Freeing the entire array is done with:
+Freeing the entire array is done with::
 
     void flex_array_free(struct flex_array *array);
 
index 77b36f5..14ab578 100644 (file)
@@ -1,5 +1,6 @@
+================
 Futex Requeue PI
-----------------
+================
 
 Requeueing of tasks from a non-PI futex to a PI futex requires
 special handling in order to ensure the underlying rt_mutex is never
@@ -20,28 +21,28 @@ implementation would wake the highest-priority waiter, and leave the
 rest to the natural wakeup inherent in unlocking the mutex
 associated with the condvar.
 
-Consider the simplified glibc calls:
-
-/* caller must lock mutex */
-pthread_cond_wait(cond, mutex)
-{
-       lock(cond->__data.__lock);
-       unlock(mutex);
-       do {
-          unlock(cond->__data.__lock);
-          futex_wait(cond->__data.__futex);
-          lock(cond->__data.__lock);
-       } while(...)
-       unlock(cond->__data.__lock);
-       lock(mutex);
-}
-
-pthread_cond_broadcast(cond)
-{
-       lock(cond->__data.__lock);
-       unlock(cond->__data.__lock);
-       futex_requeue(cond->data.__futex, cond->mutex);
-}
+Consider the simplified glibc calls::
+
+       /* caller must lock mutex */
+       pthread_cond_wait(cond, mutex)
+       {
+               lock(cond->__data.__lock);
+               unlock(mutex);
+               do {
+               unlock(cond->__data.__lock);
+               futex_wait(cond->__data.__futex);
+               lock(cond->__data.__lock);
+               } while(...)
+               unlock(cond->__data.__lock);
+               lock(mutex);
+       }
+
+       pthread_cond_broadcast(cond)
+       {
+               lock(cond->__data.__lock);
+               unlock(cond->__data.__lock);
+               futex_requeue(cond->data.__futex, cond->mutex);
+       }
 
 Once pthread_cond_broadcast() requeues the tasks, the cond->mutex
 has waiters. Note that pthread_cond_wait() attempts to lock the
@@ -53,29 +54,29 @@ In order to support PI-aware pthread_condvar's, the kernel needs to
 be able to requeue tasks to PI futexes.  This support implies that
 upon a successful futex_wait system call, the caller would return to
 user space already holding the PI futex.  The glibc implementation
-would be modified as follows:
-
-
-/* caller must lock mutex */
-pthread_cond_wait_pi(cond, mutex)
-{
-       lock(cond->__data.__lock);
-       unlock(mutex);
-       do {
-          unlock(cond->__data.__lock);
-          futex_wait_requeue_pi(cond->__data.__futex);
-          lock(cond->__data.__lock);
-       } while(...)
-       unlock(cond->__data.__lock);
-        /* the kernel acquired the mutex for us */
-}
-
-pthread_cond_broadcast_pi(cond)
-{
-       lock(cond->__data.__lock);
-       unlock(cond->__data.__lock);
-       futex_requeue_pi(cond->data.__futex, cond->mutex);
-}
+would be modified as follows::
+
+
+       /* caller must lock mutex */
+       pthread_cond_wait_pi(cond, mutex)
+       {
+               lock(cond->__data.__lock);
+               unlock(mutex);
+               do {
+               unlock(cond->__data.__lock);
+               futex_wait_requeue_pi(cond->__data.__futex);
+               lock(cond->__data.__lock);
+               } while(...)
+               unlock(cond->__data.__lock);
+               /* the kernel acquired the mutex for us */
+       }
+
+       pthread_cond_broadcast_pi(cond)
+       {
+               lock(cond->__data.__lock);
+               unlock(cond->__data.__lock);
+               futex_requeue_pi(cond->data.__futex, cond->mutex);
+       }
 
 The actual glibc implementation will likely test for PI and make the
 necessary changes inside the existing calls rather than creating new
index 433eaef..8502f24 100644 (file)
@@ -1,14 +1,15 @@
+=========================
 GCC plugin infrastructure
 =========================
 
 
-1. Introduction
-===============
+Introduction
+============
 
 GCC plugins are loadable modules that provide extra features to the
-compiler [1]. They are useful for runtime instrumentation and static analysis.
+compiler [1]_. They are useful for runtime instrumentation and static analysis.
 We can analyse, change and add further code during compilation via
-callbacks [2], GIMPLE [3], IPA [4] and RTL passes [5].
+callbacks [2]_, GIMPLE [3]_, IPA [4]_ and RTL passes [5]_.
 
 The GCC plugin infrastructure of the kernel supports all gcc versions from
 4.5 to 6.0, building out-of-tree modules, cross-compilation and building in a
@@ -21,56 +22,61 @@ and versions 4.8+ can only be compiled by a C++ compiler.
 Currently the GCC plugin infrastructure supports only the x86, arm, arm64 and
 powerpc architectures.
 
-This infrastructure was ported from grsecurity [6] and PaX [7].
+This infrastructure was ported from grsecurity [6]_ and PaX [7]_.
 
 --
-[1] https://gcc.gnu.org/onlinedocs/gccint/Plugins.html
-[2] https://gcc.gnu.org/onlinedocs/gccint/Plugin-API.html#Plugin-API
-[3] https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html
-[4] https://gcc.gnu.org/onlinedocs/gccint/IPA.html
-[5] https://gcc.gnu.org/onlinedocs/gccint/RTL.html
-[6] https://grsecurity.net/
-[7] https://pax.grsecurity.net/
 
+.. [1] https://gcc.gnu.org/onlinedocs/gccint/Plugins.html
+.. [2] https://gcc.gnu.org/onlinedocs/gccint/Plugin-API.html#Plugin-API
+.. [3] https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html
+.. [4] https://gcc.gnu.org/onlinedocs/gccint/IPA.html
+.. [5] https://gcc.gnu.org/onlinedocs/gccint/RTL.html
+.. [6] https://grsecurity.net/
+.. [7] https://pax.grsecurity.net/
+
+
+Files
+=====
 
-2. Files
-========
+**$(src)/scripts/gcc-plugins**
 
-$(src)/scripts/gcc-plugins
        This is the directory of the GCC plugins.
 
-$(src)/scripts/gcc-plugins/gcc-common.h
+**$(src)/scripts/gcc-plugins/gcc-common.h**
+
        This is a compatibility header for GCC plugins.
        It should be always included instead of individual gcc headers.
 
-$(src)/scripts/gcc-plugin.sh
+**$(src)/scripts/gcc-plugin.sh**
+
        This script checks the availability of the included headers in
        gcc-common.h and chooses the proper host compiler to build the plugins
        (gcc-4.7 can be built by either gcc or g++).
 
-$(src)/scripts/gcc-plugins/gcc-generate-gimple-pass.h
-$(src)/scripts/gcc-plugins/gcc-generate-ipa-pass.h
-$(src)/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h
-$(src)/scripts/gcc-plugins/gcc-generate-rtl-pass.h
+**$(src)/scripts/gcc-plugins/gcc-generate-gimple-pass.h,
+$(src)/scripts/gcc-plugins/gcc-generate-ipa-pass.h,
+$(src)/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h,
+$(src)/scripts/gcc-plugins/gcc-generate-rtl-pass.h**
+
        These headers automatically generate the registration structures for
        GIMPLE, SIMPLE_IPA, IPA and RTL passes. They support all gcc versions
        from 4.5 to 6.0.
        They should be preferred to creating the structures by hand.
 
 
-3. Usage
-========
+Usage
+=====
 
 You must install the gcc plugin headers for your gcc version,
-e.g., on Ubuntu for gcc-4.9:
+e.g., on Ubuntu for gcc-4.9::
 
        apt-get install gcc-4.9-plugin-dev
 
-Enable a GCC plugin based feature in the kernel config:
+Enable a GCC plugin based feature in the kernel config::
 
        CONFIG_GCC_PLUGIN_CYC_COMPLEXITY = y
 
-To compile only the plugin(s):
+To compile only the plugin(s)::
 
        make gcc-plugins
 
index 6bad6f1..6ee7046 100644 (file)
@@ -1,4 +1,9 @@
-Notes on the change from 16-bit UIDs to 32-bit UIDs:
+===================================================
+Notes on the change from 16-bit UIDs to 32-bit UIDs
+===================================================
+
+:Author: Chris Wing <wingc@umich.edu>
+:Last updated: January 11, 2000
 
 - kernel code MUST take into account __kernel_uid_t and __kernel_uid32_t
   when communicating between user and kernel space in an ioctl or data
@@ -28,30 +33,34 @@ What's left to be done for 32-bit UIDs on all Linux architectures:
   uses the 32-bit UID system calls properly otherwise.
 
   This affects at least:
-       iBCS on Intel
 
-       sparc32 emulation on sparc64
-       (need to support whatever new 32-bit UID system calls are added to
-       sparc32)
+       - iBCS on Intel
+
+       - sparc32 emulation on sparc64
+         (need to support whatever new 32-bit UID system calls are added to
+         sparc32)
 
 - Validate that all filesystems behave properly.
 
   At present, 32-bit UIDs _should_ work for:
-       ext2
-       ufs
-       isofs
-       nfs
-       coda
-       udf
+
+       - ext2
+       - ufs
+       - isofs
+       - nfs
+       - coda
+       - udf
 
   Ioctl() fixups have been made for:
-       ncpfs
-       smbfs
+
+       - ncpfs
+       - smbfs
 
   Filesystems with simple fixups to prevent 16-bit UID wraparound:
-       minix
-       sysv
-       qnx4
+
+       - minix
+       - sysv
+       - qnx4
 
   Other filesystems have not been checked yet.
 
@@ -69,9 +78,3 @@ What's left to be done for 32-bit UIDs on all Linux architectures:
 - make sure that the UID mapping feature of AX25 networking works properly
   (it should be safe because it's always used a 32-bit integer to
   communicate between user and kernel)
-
-
-Chris Wing
-wingc@umich.edu
-
-last updated: January 11, 2000
index fce1634..121de96 100644 (file)
-Introduction:
-
-       The hw_random framework is software that makes use of a
-       special hardware feature on your CPU or motherboard,
-       a Random Number Generator (RNG).  The software has two parts:
-       a core providing the /dev/hwrng character device and its
-       sysfs support, plus a hardware-specific driver that plugs
-       into that core.
-
-       To make the most effective use of these mechanisms, you
-       should download the support software as well.  Download the
-       latest version of the "rng-tools" package from the
-       hw_random driver's official Web site:
-
-               http://sourceforge.net/projects/gkernel/
-
-       Those tools use /dev/hwrng to fill the kernel entropy pool,
-       which is used internally and exported by the /dev/urandom and
-       /dev/random special files.
-
-Theory of operation:
-
-       CHARACTER DEVICE.  Using the standard open()
-       and read() system calls, you can read random data from
-       the hardware RNG device.  This data is NOT CHECKED by any
-       fitness tests, and could potentially be bogus (if the
-       hardware is faulty or has been tampered with).  Data is only
-       output if the hardware "has-data" flag is set, but nevertheless
-       a security-conscious person would run fitness tests on the
-       data before assuming it is truly random.
-
-       The rng-tools package uses such tests in "rngd", and lets you
-       run them by hand with a "rngtest" utility.
-
-       /dev/hwrng is char device major 10, minor 183.
-
-       CLASS DEVICE.  There is a /sys/class/misc/hw_random node with
-       two unique attributes, "rng_available" and "rng_current".  The
-       "rng_available" attribute lists the hardware-specific drivers
-       available, while "rng_current" lists the one which is currently
-       connected to /dev/hwrng.  If your system has more than one
-       RNG available, you may change the one used by writing a name from
-       the list in "rng_available" into "rng_current".
+==========================================================
+Linux support for random number generator in i8xx chipsets
+==========================================================
+
+Introduction
+============
+
+The hw_random framework is software that makes use of a
+special hardware feature on your CPU or motherboard,
+a Random Number Generator (RNG).  The software has two parts:
+a core providing the /dev/hwrng character device and its
+sysfs support, plus a hardware-specific driver that plugs
+into that core.
+
+To make the most effective use of these mechanisms, you
+should download the support software as well.  Download the
+latest version of the "rng-tools" package from the
+hw_random driver's official Web site:
+
+       http://sourceforge.net/projects/gkernel/
+
+Those tools use /dev/hwrng to fill the kernel entropy pool,
+which is used internally and exported by the /dev/urandom and
+/dev/random special files.
+
+Theory of operation
+===================
+
+CHARACTER DEVICE.  Using the standard open()
+and read() system calls, you can read random data from
+the hardware RNG device.  This data is NOT CHECKED by any
+fitness tests, and could potentially be bogus (if the
+hardware is faulty or has been tampered with).  Data is only
+output if the hardware "has-data" flag is set, but nevertheless
+a security-conscious person would run fitness tests on the
+data before assuming it is truly random.
+
+The rng-tools package uses such tests in "rngd", and lets you
+run them by hand with a "rngtest" utility.
+
+/dev/hwrng is char device major 10, minor 183.
+
+CLASS DEVICE.  There is a /sys/class/misc/hw_random node with
+two unique attributes, "rng_available" and "rng_current".  The
+"rng_available" attribute lists the hardware-specific drivers
+available, while "rng_current" lists the one which is currently
+connected to /dev/hwrng.  If your system has more than one
+RNG available, you may change the one used by writing a name from
+the list in "rng_available" into "rng_current".
 
 ==========================================================================
 
-       Hardware driver for Intel/AMD/VIA Random Number Generators (RNG)
-       Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
-       Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
+Hardware driver for Intel/AMD/VIA Random Number Generators (RNG)
+       - Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+       - Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
-About the Intel RNG hardware, from the firmware hub datasheet:
 
-       The Firmware Hub integrates a Random Number Generator (RNG)
-       using thermal noise generated from inherently random quantum
-       mechanical properties of silicon. When not generating new random
-       bits the RNG circuitry will enter a low power state. Intel will
-       provide a binary software driver to give third party software
-       access to our RNG for use as a security feature. At this time,
-       the RNG is only to be used with a system in an OS-present state.
+About the Intel RNG hardware, from the firmware hub datasheet
+=============================================================
 
-Intel RNG Driver notes:
+The Firmware Hub integrates a Random Number Generator (RNG)
+using thermal noise generated from inherently random quantum
+mechanical properties of silicon. When not generating new random
+bits the RNG circuitry will enter a low power state. Intel will
+provide a binary software driver to give third party software
+access to our RNG for use as a security feature. At this time,
+the RNG is only to be used with a system in an OS-present state.
 
-       * FIXME: support poll(2)
+Intel RNG Driver notes
+======================
 
-       NOTE: request_mem_region was removed, for three reasons:
-       1) Only one RNG is supported by this driver, 2) The location
-       used by the RNG is a fixed location in MMIO-addressable memory,
+FIXME: support poll(2)
+
+.. note::
+
+       request_mem_region was removed, for three reasons:
+
+       1) Only one RNG is supported by this driver;
+       2) The location used by the RNG is a fixed location in
+          MMIO-addressable memory;
        3) users with properly working BIOS e820 handling will always
-       have the region in which the RNG is located reserved, so
-       request_mem_region calls always fail for proper setups.
-       However, for people who use mem=XX, BIOS e820 information is
-       -not- in /proc/iomem, and request_mem_region(RNG_ADDR) can
-       succeed.
+          have the region in which the RNG is located reserved, so
+          request_mem_region calls always fail for proper setups.
+          However, for people who use mem=XX, BIOS e820 information is
+          **not** in /proc/iomem, and request_mem_region(RNG_ADDR) can
+          succeed.
 
-Driver details:
+Driver details
+==============
 
-       Based on:
+Based on:
        Intel 82802AB/82802AC Firmware Hub (FWH) Datasheet
-               May 1999 Order Number: 290658-002 R
+       May 1999 Order Number: 290658-002 R
 
-       Intel 82802 Firmware Hub: Random Number Generator
+Intel 82802 Firmware Hub:
+       Random Number Generator
        Programmer's Reference Manual
-               December 1999 Order Number: 298029-001 R
+       December 1999 Order Number: 298029-001 R
 
-       Intel 82802 Firmware HUB Random Number Generator Driver
+Intel 82802 Firmware HUB Random Number Generator Driver
        Copyright (c) 2000 Matt Sottek <msottek@quiknet.com>
 
-       Special thanks to Matt Sottek.  I did the "guts", he
-       did the "brains" and all the testing.
+Special thanks to Matt Sottek.  I did the "guts", he
+did the "brains" and all the testing.
index 61c1ee9..ed640a2 100644 (file)
@@ -1,6 +1,9 @@
+===========================
 Hardware Spinlock Framework
+===========================
 
-1. Introduction
+Introduction
+============
 
 Hardware spinlock modules provide hardware assistance for synchronization
 and mutual exclusion between heterogeneous processors and those not operating
@@ -32,286 +35,370 @@ structure).
 A common hwspinlock interface makes it possible to have generic, platform-
 independent, drivers.
 
-2. User API
+User API
+========
+
+::
 
   struct hwspinlock *hwspin_lock_request(void);
-   - dynamically assign an hwspinlock and return its address, or NULL
-     in case an unused hwspinlock isn't available. Users of this
-     API will usually want to communicate the lock's id to the remote core
-     before it can be used to achieve synchronization.
-     Should be called from a process context (might sleep).
+
+Dynamically assign an hwspinlock and return its address, or NULL
+in case an unused hwspinlock isn't available. Users of this
+API will usually want to communicate the lock's id to the remote core
+before it can be used to achieve synchronization.
+
+Should be called from a process context (might sleep).
+
+::
 
   struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
-   - assign a specific hwspinlock id and return its address, or NULL
-     if that hwspinlock is already in use. Usually board code will
-     be calling this function in order to reserve specific hwspinlock
-     ids for predefined purposes.
-     Should be called from a process context (might sleep).
+
+Assign a specific hwspinlock id and return its address, or NULL
+if that hwspinlock is already in use. Usually board code will
+be calling this function in order to reserve specific hwspinlock
+ids for predefined purposes.
+
+Should be called from a process context (might sleep).
+
+::
 
   int of_hwspin_lock_get_id(struct device_node *np, int index);
-   - retrieve the global lock id for an OF phandle-based specific lock.
-     This function provides a means for DT users of a hwspinlock module
-     to get the global lock id of a specific hwspinlock, so that it can
-     be requested using the normal hwspin_lock_request_specific() API.
-     The function returns a lock id number on success, -EPROBE_DEFER if
-     the hwspinlock device is not yet registered with the core, or other
-     error values.
-     Should be called from a process context (might sleep).
+
+Retrieve the global lock id for an OF phandle-based specific lock.
+This function provides a means for DT users of a hwspinlock module
+to get the global lock id of a specific hwspinlock, so that it can
+be requested using the normal hwspin_lock_request_specific() API.
+
+The function returns a lock id number on success, -EPROBE_DEFER if
+the hwspinlock device is not yet registered with the core, or other
+error values.
+
+Should be called from a process context (might sleep).
+
+::
 
   int hwspin_lock_free(struct hwspinlock *hwlock);
-   - free a previously-assigned hwspinlock; returns 0 on success, or an
-     appropriate error code on failure (e.g. -EINVAL if the hwspinlock
-     is already free).
-     Should be called from a process context (might sleep).
+
+Free a previously-assigned hwspinlock; returns 0 on success, or an
+appropriate error code on failure (e.g. -EINVAL if the hwspinlock
+is already free).
+
+Should be called from a process context (might sleep).
+
+::
 
   int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout);
-   - lock a previously-assigned hwspinlock with a timeout limit (specified in
-     msecs). If the hwspinlock is already taken, the function will busy loop
-     waiting for it to be released, but give up when the timeout elapses.
-     Upon a successful return from this function, preemption is disabled so
-     the caller must not sleep, and is advised to release the hwspinlock as
-     soon as possible, in order to minimize remote cores polling on the
-     hardware interconnect.
-     Returns 0 when successful and an appropriate error code otherwise (most
-     notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
-     The function will never sleep.
+
+Lock a previously-assigned hwspinlock with a timeout limit (specified in
+msecs). If the hwspinlock is already taken, the function will busy loop
+waiting for it to be released, but give up when the timeout elapses.
+Upon a successful return from this function, preemption is disabled so
+the caller must not sleep, and is advised to release the hwspinlock as
+soon as possible, in order to minimize remote cores polling on the
+hardware interconnect.
+
+Returns 0 when successful and an appropriate error code otherwise (most
+notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
+The function will never sleep.
+
+::
 
   int hwspin_lock_timeout_irq(struct hwspinlock *hwlock, unsigned int timeout);
-   - lock a previously-assigned hwspinlock with a timeout limit (specified in
-     msecs). If the hwspinlock is already taken, the function will busy loop
-     waiting for it to be released, but give up when the timeout elapses.
-     Upon a successful return from this function, preemption and the local
-     interrupts are disabled, so the caller must not sleep, and is advised to
-     release the hwspinlock as soon as possible.
-     Returns 0 when successful and an appropriate error code otherwise (most
-     notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
-     The function will never sleep.
+
+Lock a previously-assigned hwspinlock with a timeout limit (specified in
+msecs). If the hwspinlock is already taken, the function will busy loop
+waiting for it to be released, but give up when the timeout elapses.
+Upon a successful return from this function, preemption and the local
+interrupts are disabled, so the caller must not sleep, and is advised to
+release the hwspinlock as soon as possible.
+
+Returns 0 when successful and an appropriate error code otherwise (most
+notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
+The function will never sleep.
+
+::
 
   int hwspin_lock_timeout_irqsave(struct hwspinlock *hwlock, unsigned int to,
-                                                       unsigned long *flags);
-   - lock a previously-assigned hwspinlock with a timeout limit (specified in
-     msecs). If the hwspinlock is already taken, the function will busy loop
-     waiting for it to be released, but give up when the timeout elapses.
-     Upon a successful return from this function, preemption is disabled,
-     local interrupts are disabled and their previous state is saved at the
-     given flags placeholder. The caller must not sleep, and is advised to
-     release the hwspinlock as soon as possible.
-     Returns 0 when successful and an appropriate error code otherwise (most
-     notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
-     The function will never sleep.
+                                 unsigned long *flags);
+
+Lock a previously-assigned hwspinlock with a timeout limit (specified in
+msecs). If the hwspinlock is already taken, the function will busy loop
+waiting for it to be released, but give up when the timeout elapses.
+Upon a successful return from this function, preemption is disabled,
+local interrupts are disabled and their previous state is saved at the
+given flags placeholder. The caller must not sleep, and is advised to
+release the hwspinlock as soon as possible.
+
+Returns 0 when successful and an appropriate error code otherwise (most
+notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
+
+The function will never sleep.
+
+::
 
   int hwspin_trylock(struct hwspinlock *hwlock);
-   - attempt to lock a previously-assigned hwspinlock, but immediately fail if
-     it is already taken.
-     Upon a successful return from this function, preemption is disabled so
-     caller must not sleep, and is advised to release the hwspinlock as soon as
-     possible, in order to minimize remote cores polling on the hardware
-     interconnect.
-     Returns 0 on success and an appropriate error code otherwise (most
-     notably -EBUSY if the hwspinlock was already taken).
-     The function will never sleep.
+
+
+Attempt to lock a previously-assigned hwspinlock, but immediately fail if
+it is already taken.
+
+Upon a successful return from this function, preemption is disabled so
+caller must not sleep, and is advised to release the hwspinlock as soon as
+possible, in order to minimize remote cores polling on the hardware
+interconnect.
+
+Returns 0 on success and an appropriate error code otherwise (most
+notably -EBUSY if the hwspinlock was already taken).
+The function will never sleep.
+
+::
 
   int hwspin_trylock_irq(struct hwspinlock *hwlock);
-   - attempt to lock a previously-assigned hwspinlock, but immediately fail if
-     it is already taken.
-     Upon a successful return from this function, preemption and the local
-     interrupts are disabled so caller must not sleep, and is advised to
-     release the hwspinlock as soon as possible.
-     Returns 0 on success and an appropriate error code otherwise (most
-     notably -EBUSY if the hwspinlock was already taken).
-     The function will never sleep.
+
+
+Attempt to lock a previously-assigned hwspinlock, but immediately fail if
+it is already taken.
+
+Upon a successful return from this function, preemption and the local
+interrupts are disabled so caller must not sleep, and is advised to
+release the hwspinlock as soon as possible.
+
+Returns 0 on success and an appropriate error code otherwise (most
+notably -EBUSY if the hwspinlock was already taken).
+
+The function will never sleep.
+
+::
 
   int hwspin_trylock_irqsave(struct hwspinlock *hwlock, unsigned long *flags);
-   - attempt to lock a previously-assigned hwspinlock, but immediately fail if
-     it is already taken.
-     Upon a successful return from this function, preemption is disabled,
-     the local interrupts are disabled and their previous state is saved
-     at the given flags placeholder. The caller must not sleep, and is advised
-     to release the hwspinlock as soon as possible.
-     Returns 0 on success and an appropriate error code otherwise (most
-     notably -EBUSY if the hwspinlock was already taken).
-     The function will never sleep.
+
+Attempt to lock a previously-assigned hwspinlock, but immediately fail if
+it is already taken.
+
+Upon a successful return from this function, preemption is disabled,
+the local interrupts are disabled and their previous state is saved
+at the given flags placeholder. The caller must not sleep, and is advised
+to release the hwspinlock as soon as possible.
+
+Returns 0 on success and an appropriate error code otherwise (most
+notably -EBUSY if the hwspinlock was already taken).
+The function will never sleep.
+
+::
 
   void hwspin_unlock(struct hwspinlock *hwlock);
-   - unlock a previously-locked hwspinlock. Always succeed, and can be called
-     from any context (the function never sleeps). Note: code should _never_
-     unlock an hwspinlock which is already unlocked (there is no protection
-     against this).
+
+Unlock a previously-locked hwspinlock. Always succeed, and can be called
+from any context (the function never sleeps).
+
+.. note::
+
+  code should **never** unlock an hwspinlock which is already unlocked
+  (there is no protection against this).
+
+::
 
   void hwspin_unlock_irq(struct hwspinlock *hwlock);
-   - unlock a previously-locked hwspinlock and enable local interrupts.
-     The caller should _never_ unlock an hwspinlock which is already unlocked.
-     Doing so is considered a bug (there is no protection against this).
-     Upon a successful return from this function, preemption and local
-     interrupts are enabled. This function will never sleep.
+
+Unlock a previously-locked hwspinlock and enable local interrupts.
+The caller should **never** unlock an hwspinlock which is already unlocked.
+
+Doing so is considered a bug (there is no protection against this).
+Upon a successful return from this function, preemption and local
+interrupts are enabled. This function will never sleep.
+
+::
 
   void
   hwspin_unlock_irqrestore(struct hwspinlock *hwlock, unsigned long *flags);
-   - unlock a previously-locked hwspinlock.
-     The caller should _never_ unlock an hwspinlock which is already unlocked.
-     Doing so is considered a bug (there is no protection against this).
-     Upon a successful return from this function, preemption is reenabled,
-     and the state of the local interrupts is restored to the state saved at
-     the given flags. This function will never sleep.
+
+Unlock a previously-locked hwspinlock.
+
+The caller should **never** unlock an hwspinlock which is already unlocked.
+Doing so is considered a bug (there is no protection against this).
+Upon a successful return from this function, preemption is reenabled,
+and the state of the local interrupts is restored to the state saved at
+the given flags. This function will never sleep.
+
+::
 
   int hwspin_lock_get_id(struct hwspinlock *hwlock);
-   - retrieve id number of a given hwspinlock. This is needed when an
-     hwspinlock is dynamically assigned: before it can be used to achieve
-     mutual exclusion with a remote cpu, the id number should be communicated
-     to the remote task with which we want to synchronize.
-     Returns the hwspinlock id number, or -EINVAL if hwlock is null.
-
-3. Typical usage
-
-#include <linux/hwspinlock.h>
-#include <linux/err.h>
-
-int hwspinlock_example1(void)
-{
-       struct hwspinlock *hwlock;
-       int ret;
-
-       /* dynamically assign a hwspinlock */
-       hwlock = hwspin_lock_request();
-       if (!hwlock)
-               ...
-
-       id = hwspin_lock_get_id(hwlock);
-       /* probably need to communicate id to a remote processor now */
-
-       /* take the lock, spin for 1 sec if it's already taken */
-       ret = hwspin_lock_timeout(hwlock, 1000);
-       if (ret)
-               ...
-
-       /*
-        * we took the lock, do our thing now, but do NOT sleep
-        */
-
-       /* release the lock */
-       hwspin_unlock(hwlock);
-
-       /* free the lock */
-       ret = hwspin_lock_free(hwlock);
-       if (ret)
-               ...
-
-       return ret;
-}
-
-int hwspinlock_example2(void)
-{
-       struct hwspinlock *hwlock;
-       int ret;
-
-       /*
-        * assign a specific hwspinlock id - this should be called early
-        * by board init code.
-        */
-       hwlock = hwspin_lock_request_specific(PREDEFINED_LOCK_ID);
-       if (!hwlock)
-               ...
-
-       /* try to take it, but don't spin on it */
-       ret = hwspin_trylock(hwlock);
-       if (!ret) {
-               pr_info("lock is already taken\n");
-               return -EBUSY;
-       }
 
-       /*
-        * we took the lock, do our thing now, but do NOT sleep
-        */
+Retrieve id number of a given hwspinlock. This is needed when an
+hwspinlock is dynamically assigned: before it can be used to achieve
+mutual exclusion with a remote cpu, the id number should be communicated
+to the remote task with which we want to synchronize.
+
+Returns the hwspinlock id number, or -EINVAL if hwlock is null.
+
+Typical usage
+=============
 
-       /* release the lock */
-       hwspin_unlock(hwlock);
+::
 
-       /* free the lock */
-       ret = hwspin_lock_free(hwlock);
-       if (ret)
-               ...
+       #include <linux/hwspinlock.h>
+       #include <linux/err.h>
 
-       return ret;
-}
+       int hwspinlock_example1(void)
+       {
+               struct hwspinlock *hwlock;
+               int ret;
 
+               /* dynamically assign a hwspinlock */
+               hwlock = hwspin_lock_request();
+               if (!hwlock)
+                       ...
 
-4. API for implementors
+               id = hwspin_lock_get_id(hwlock);
+               /* probably need to communicate id to a remote processor now */
+
+               /* take the lock, spin for 1 sec if it's already taken */
+               ret = hwspin_lock_timeout(hwlock, 1000);
+               if (ret)
+                       ...
+
+               /*
+               * we took the lock, do our thing now, but do NOT sleep
+               */
+
+               /* release the lock */
+               hwspin_unlock(hwlock);
+
+               /* free the lock */
+               ret = hwspin_lock_free(hwlock);
+               if (ret)
+                       ...
+
+               return ret;
+       }
+
+       int hwspinlock_example2(void)
+       {
+               struct hwspinlock *hwlock;
+               int ret;
+
+               /*
+               * assign a specific hwspinlock id - this should be called early
+               * by board init code.
+               */
+               hwlock = hwspin_lock_request_specific(PREDEFINED_LOCK_ID);
+               if (!hwlock)
+                       ...
+
+               /* try to take it, but don't spin on it */
+               ret = hwspin_trylock(hwlock);
+               if (!ret) {
+                       pr_info("lock is already taken\n");
+                       return -EBUSY;
+               }
+
+               /*
+               * we took the lock, do our thing now, but do NOT sleep
+               */
+
+               /* release the lock */
+               hwspin_unlock(hwlock);
+
+               /* free the lock */
+               ret = hwspin_lock_free(hwlock);
+               if (ret)
+                       ...
+
+               return ret;
+       }
+
+
+API for implementors
+====================
+
+::
 
   int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
                const struct hwspinlock_ops *ops, int base_id, int num_locks);
-   - to be called from the underlying platform-specific implementation, in
-     order to register a new hwspinlock device (which is usually a bank of
-     numerous locks). Should be called from a process context (this function
-     might sleep).
-     Returns 0 on success, or appropriate error code on failure.
+
+To be called from the underlying platform-specific implementation, in
+order to register a new hwspinlock device (which is usually a bank of
+numerous locks). Should be called from a process context (this function
+might sleep).
+
+Returns 0 on success, or appropriate error code on failure.
+
+::
 
   int hwspin_lock_unregister(struct hwspinlock_device *bank);
-   - to be called from the underlying vendor-specific implementation, in order
-     to unregister an hwspinlock device (which is usually a bank of numerous
-     locks).
-     Should be called from a process context (this function might sleep).
-     Returns the address of hwspinlock on success, or NULL on error (e.g.
-     if the hwspinlock is still in use).
 
-5. Important structs
+To be called from the underlying vendor-specific implementation, in order
+to unregister an hwspinlock device (which is usually a bank of numerous
+locks).
+
+Should be called from a process context (this function might sleep).
+
+Returns the address of hwspinlock on success, or NULL on error (e.g.
+if the hwspinlock is still in use).
+
+Important structs
+=================
 
 struct hwspinlock_device is a device which usually contains a bank
 of hardware locks. It is registered by the underlying hwspinlock
 implementation using the hwspin_lock_register() API.
 
-/**
- * struct hwspinlock_device - a device which usually spans numerous hwspinlocks
- * @dev: underlying device, will be used to invoke runtime PM api
- * @ops: platform-specific hwspinlock handlers
- * @base_id: id index of the first lock in this device
- * @num_locks: number of locks in this device
- * @lock: dynamically allocated array of 'struct hwspinlock'
- */
-struct hwspinlock_device {
-       struct device *dev;
-       const struct hwspinlock_ops *ops;
-       int base_id;
-       int num_locks;
-       struct hwspinlock lock[0];
-};
+::
+
+       /**
+       * struct hwspinlock_device - a device which usually spans numerous hwspinlocks
+       * @dev: underlying device, will be used to invoke runtime PM api
+       * @ops: platform-specific hwspinlock handlers
+       * @base_id: id index of the first lock in this device
+       * @num_locks: number of locks in this device
+       * @lock: dynamically allocated array of 'struct hwspinlock'
+       */
+       struct hwspinlock_device {
+               struct device *dev;
+               const struct hwspinlock_ops *ops;
+               int base_id;
+               int num_locks;
+               struct hwspinlock lock[0];
+       };
 
 struct hwspinlock_device contains an array of hwspinlock structs, each
-of which represents a single hardware lock:
-
-/**
- * struct hwspinlock - this struct represents a single hwspinlock instance
- * @bank: the hwspinlock_device structure which owns this lock
- * @lock: initialized and used by hwspinlock core
- * @priv: private data, owned by the underlying platform-specific hwspinlock drv
- */
-struct hwspinlock {
-       struct hwspinlock_device *bank;
-       spinlock_t lock;
-       void *priv;
-};
+of which represents a single hardware lock::
+
+       /**
      * struct hwspinlock - this struct represents a single hwspinlock instance
      * @bank: the hwspinlock_device structure which owns this lock
      * @lock: initialized and used by hwspinlock core
      * @priv: private data, owned by the underlying platform-specific hwspinlock drv
      */
+       struct hwspinlock {
+               struct hwspinlock_device *bank;
+               spinlock_t lock;
+               void *priv;
+       };
 
 When registering a bank of locks, the hwspinlock driver only needs to
 set the priv members of the locks. The rest of the members are set and
 initialized by the hwspinlock core itself.
 
-6. Implementation callbacks
+Implementation callbacks
+========================
 
-There are three possible callbacks defined in 'struct hwspinlock_ops':
+There are three possible callbacks defined in 'struct hwspinlock_ops'::
 
-struct hwspinlock_ops {
-       int (*trylock)(struct hwspinlock *lock);
-       void (*unlock)(struct hwspinlock *lock);
-       void (*relax)(struct hwspinlock *lock);
-};
+       struct hwspinlock_ops {
+               int (*trylock)(struct hwspinlock *lock);
+               void (*unlock)(struct hwspinlock *lock);
+               void (*relax)(struct hwspinlock *lock);
+       };
 
 The first two callbacks are mandatory:
 
 The ->trylock() callback should make a single attempt to take the lock, and
-return 0 on failure and 1 on success. This callback may _not_ sleep.
+return 0 on failure and 1 on success. This callback may **not** sleep.
 
 The ->unlock() callback releases the lock. It always succeed, and it, too,
-may _not_ sleep.
+may **not** sleep.
 
 The ->relax() callback is optional. It is called by hwspinlock core while
 spinning on a lock, and can be used by the underlying implementation to force
-a delay between two successive invocations of ->trylock(). It may _not_ sleep.
+a delay between two successive invocations of ->trylock(). It may **not** sleep.
index 7a3e71c..9888f5c 100644 (file)
@@ -6,7 +6,6 @@ Contents:
 
 .. toctree::
    :maxdepth: 2
-   :numbered:
 
    input_uapi
    input_kapi
index 91d89c5..d83c1a2 100644 (file)
@@ -1,4 +1,5 @@
-Intel(R) TXT Overview:
+=====================
+Intel(R) TXT Overview
 =====================
 
 Intel's technology for safer computing, Intel(R) Trusted Execution
@@ -8,9 +9,10 @@ provide the building blocks for creating trusted platforms.
 Intel TXT was formerly known by the code name LaGrande Technology (LT).
 
 Intel TXT in Brief:
-o  Provides dynamic root of trust for measurement (DRTM)
-o  Data protection in case of improper shutdown
-o  Measurement and verification of launched environment
+
+-  Provides dynamic root of trust for measurement (DRTM)
+-  Data protection in case of improper shutdown
+-  Measurement and verification of launched environment
 
 Intel TXT is part of the vPro(TM) brand and is also available some
 non-vPro systems.  It is currently available on desktop systems
@@ -24,16 +26,21 @@ which has been updated for the new released platforms.
 
 Intel TXT has been presented at various events over the past few
 years, some of which are:
-      LinuxTAG 2008:
+
+      - LinuxTAG 2008:
           http://www.linuxtag.org/2008/en/conf/events/vp-donnerstag.html
-      TRUST2008:
+
+      - TRUST2008:
           http://www.trust-conference.eu/downloads/Keynote-Speakers/
           3_David-Grawrock_The-Front-Door-of-Trusted-Computing.pdf
-      IDF, Shanghai:
+
+      - IDF, Shanghai:
           http://www.prcidf.com.cn/index_en.html
-      IDFs 2006, 2007 (I'm not sure if/where they are online)
 
-Trusted Boot Project Overview:
+      - IDFs 2006, 2007
+         (I'm not sure if/where they are online)
+
+Trusted Boot Project Overview
 =============================
 
 Trusted Boot (tboot) is an open source, pre-kernel/VMM module that
@@ -87,11 +94,12 @@ Intel-provided firmware).
 How Does it Work?
 =================
 
-o  Tboot is an executable that is launched by the bootloader as
+-  Tboot is an executable that is launched by the bootloader as
    the "kernel" (the binary the bootloader executes).
-o  It performs all of the work necessary to determine if the
+-  It performs all of the work necessary to determine if the
    platform supports Intel TXT and, if so, executes the GETSEC[SENTER]
    processor instruction that initiates the dynamic root of trust.
+
    -  If tboot determines that the system does not support Intel TXT
       or is not configured correctly (e.g. the SINIT AC Module was
       incorrect), it will directly launch the kernel with no changes
@@ -99,12 +107,14 @@ o  It performs all of the work necessary to determine if the
    -  Tboot will output various information about its progress to the
       terminal, serial port, and/or an in-memory log; the output
       locations can be configured with a command line switch.
-o  The GETSEC[SENTER] instruction will return control to tboot and
+
+-  The GETSEC[SENTER] instruction will return control to tboot and
    tboot then verifies certain aspects of the environment (e.g. TPM NV
    lock, e820 table does not have invalid entries, etc.).
-o  It will wake the APs from the special sleep state the GETSEC[SENTER]
+-  It will wake the APs from the special sleep state the GETSEC[SENTER]
    instruction had put them in and place them into a wait-for-SIPI
    state.
+
    -  Because the processors will not respond to an INIT or SIPI when
       in the TXT environment, it is necessary to create a small VT-x
       guest for the APs.  When they run in this guest, they will
@@ -112,8 +122,10 @@ o  It will wake the APs from the special sleep state the GETSEC[SENTER]
       VMEXITs, and then disable VT and jump to the SIPI vector.  This
       approach seemed like a better choice than having to insert
       special code into the kernel's MP wakeup sequence.
-o  Tboot then applies an (optional) user-defined launch policy to
+
+-  Tboot then applies an (optional) user-defined launch policy to
    verify the kernel and initrd.
+
    -  This policy is rooted in TPM NV and is described in the tboot
       project.  The tboot project also contains code for tools to
       create and provision the policy.
@@ -121,30 +133,34 @@ o  Tboot then applies an (optional) user-defined launch policy to
       then any kernel will be launched.
    -  Policy action is flexible and can include halting on failures
       or simply logging them and continuing.
-o  Tboot adjusts the e820 table provided by the bootloader to reserve
+
+-  Tboot adjusts the e820 table provided by the bootloader to reserve
    its own location in memory as well as to reserve certain other
    TXT-related regions.
-o  As part of its launch, tboot DMA protects all of RAM (using the
+-  As part of its launch, tboot DMA protects all of RAM (using the
    VT-d PMRs).  Thus, the kernel must be booted with 'intel_iommu=on'
    in order to remove this blanket protection and use VT-d's
    page-level protection.
-o  Tboot will populate a shared page with some data about itself and
+-  Tboot will populate a shared page with some data about itself and
    pass this to the Linux kernel as it transfers control.
+
    -  The location of the shared page is passed via the boot_params
       struct as a physical address.
-o  The kernel will look for the tboot shared page address and, if it
+
+-  The kernel will look for the tboot shared page address and, if it
    exists, map it.
-o  As one of the checks/protections provided by TXT, it makes a copy
+-  As one of the checks/protections provided by TXT, it makes a copy
    of the VT-d DMARs in a DMA-protected region of memory and verifies
    them for correctness.  The VT-d code will detect if the kernel was
    launched with tboot and use this copy instead of the one in the
    ACPI table.
-o  At this point, tboot and TXT are out of the picture until a
+-  At this point, tboot and TXT are out of the picture until a
    shutdown (S<n>)
-o  In order to put a system into any of the sleep states after a TXT
+-  In order to put a system into any of the sleep states after a TXT
    launch, TXT must first be exited.  This is to prevent attacks that
    attempt to crash the system to gain control on reboot and steal
    data left in memory.
+
    -  The kernel will perform all of its sleep preparation and
       populate the shared page with the ACPI data needed to put the
       platform in the desired sleep state.
@@ -172,7 +188,7 @@ o  In order to put a system into any of the sleep states after a TXT
 That's pretty much it for TXT support.
 
 
-Configuring the System:
+Configuring the System
 ======================
 
 This code works with 32bit, 32bit PAE, and 64bit (x86_64) kernels.
@@ -181,7 +197,8 @@ In BIOS, the user must enable:  TPM, TXT, VT-x, VT-d.  Not all BIOSes
 allow these to be individually enabled/disabled and the screens in
 which to find them are BIOS-specific.
 
-grub.conf needs to be modified as follows:
+grub.conf needs to be modified as follows::
+
         title Linux 2.6.29-tip w/ tboot
           root (hd0,0)
                 kernel /tboot.gz logging=serial,vga,memory
index 5ca7842..a966239 100644 (file)
@@ -1,66 +1,81 @@
+========================
+The io_mapping functions
+========================
+
+API
+===
+
 The io_mapping functions in linux/io-mapping.h provide an abstraction for
 efficiently mapping small regions of an I/O device to the CPU. The initial
 usage is to support the large graphics aperture on 32-bit processors where
 ioremap_wc cannot be used to statically map the entire aperture to the CPU
 as it would consume too much of the kernel address space.
 
-A mapping object is created during driver initialization using
+A mapping object is created during driver initialization using::
 
        struct io_mapping *io_mapping_create_wc(unsigned long base,
                                                unsigned long size)
 
-               'base' is the bus address of the region to be made
-               mappable, while 'size' indicates how large a mapping region to
-               enable. Both are in bytes.
+'base' is the bus address of the region to be made
+mappable, while 'size' indicates how large a mapping region to
+enable. Both are in bytes.
 
-               This _wc variant provides a mapping which may only be used
-               with the io_mapping_map_atomic_wc or io_mapping_map_wc.
+This _wc variant provides a mapping which may only be used
+with the io_mapping_map_atomic_wc or io_mapping_map_wc.
 
 With this mapping object, individual pages can be mapped either atomically
 or not, depending on the necessary scheduling environment. Of course, atomic
-maps are more efficient:
+maps are more efficient::
 
        void *io_mapping_map_atomic_wc(struct io_mapping *mapping,
                                       unsigned long offset)
 
-               'offset' is the offset within the defined mapping region.
-               Accessing addresses beyond the region specified in the
-               creation function yields undefined results. Using an offset
-               which is not page aligned yields an undefined result. The
-               return value points to a single page in CPU address space.
+'offset' is the offset within the defined mapping region.
+Accessing addresses beyond the region specified in the
+creation function yields undefined results. Using an offset
+which is not page aligned yields an undefined result. The
+return value points to a single page in CPU address space.
+
+This _wc variant returns a write-combining map to the
+page and may only be used with mappings created by
+io_mapping_create_wc
 
-               This _wc variant returns a write-combining map to the
-               page and may only be used with mappings created by
-               io_mapping_create_wc
+Note that the task may not sleep while holding this page
+mapped.
 
-               Note that the task may not sleep while holding this page
-               mapped.
+::
 
        void io_mapping_unmap_atomic(void *vaddr)
 
-               'vaddr' must be the value returned by the last
-               io_mapping_map_atomic_wc call. This unmaps the specified
-               page and allows the task to sleep once again.
+'vaddr' must be the value returned by the last
+io_mapping_map_atomic_wc call. This unmaps the specified
+page and allows the task to sleep once again.
 
 If you need to sleep while holding the lock, you can use the non-atomic
 variant, although they may be significantly slower.
 
+::
+
        void *io_mapping_map_wc(struct io_mapping *mapping,
                                unsigned long offset)
 
-               This works like io_mapping_map_atomic_wc except it allows
-               the task to sleep while holding the page mapped.
+This works like io_mapping_map_atomic_wc except it allows
+the task to sleep while holding the page mapped.
+
+
+::
 
        void io_mapping_unmap(void *vaddr)
 
-               This works like io_mapping_unmap_atomic, except it is used
-               for pages mapped with io_mapping_map_wc.
+This works like io_mapping_unmap_atomic, except it is used
+for pages mapped with io_mapping_map_wc.
 
-At driver close time, the io_mapping object must be freed:
+At driver close time, the io_mapping object must be freed::
 
        void io_mapping_free(struct io_mapping *mapping)
 
-Current Implementation:
+Current Implementation
+======================
 
 The initial implementation of these functions uses existing mapping
 mechanisms and so provides only an abstraction layer and no new
index 9faae6f..2ab303c 100644 (file)
@@ -1,3 +1,7 @@
+==============================================
+Ordering I/O writes to memory-mapped addresses
+==============================================
+
 On some platforms, so-called memory-mapped I/O is weakly ordered.  On such
 platforms, driver writers are responsible for ensuring that I/O writes to
 memory-mapped addresses on their device arrive in the order intended.  This is
@@ -8,39 +12,39 @@ critical section of code protected by spinlocks.  This would ensure that
 subsequent writes to I/O space arrived only after all prior writes (much like a
 memory barrier op, mb(), only with respect to I/O).
 
-A more concrete example from a hypothetical device driver:
+A more concrete example from a hypothetical device driver::
 
-        ...
-CPU A:  spin_lock_irqsave(&dev_lock, flags)
-CPU A:  val = readl(my_status);
-CPU A:  ...
-CPU A:  writel(newval, ring_ptr);
-CPU A:  spin_unlock_irqrestore(&dev_lock, flags)
-        ...
-CPU B:  spin_lock_irqsave(&dev_lock, flags)
-CPU B:  val = readl(my_status);
-CPU B:  ...
-CPU B:  writel(newval2, ring_ptr);
-CPU B:  spin_unlock_irqrestore(&dev_lock, flags)
-        ...
+               ...
+       CPU A:  spin_lock_irqsave(&dev_lock, flags)
+       CPU A:  val = readl(my_status);
+       CPU A:  ...
+       CPU A:  writel(newval, ring_ptr);
+       CPU A:  spin_unlock_irqrestore(&dev_lock, flags)
+               ...
+       CPU B:  spin_lock_irqsave(&dev_lock, flags)
+       CPU B:  val = readl(my_status);
+       CPU B:  ...
+       CPU B:  writel(newval2, ring_ptr);
+       CPU B:  spin_unlock_irqrestore(&dev_lock, flags)
+               ...
 
 In the case above, the device may receive newval2 before it receives newval,
-which could cause problems.  Fixing it is easy enough though:
+which could cause problems.  Fixing it is easy enough though::
 
-        ...
-CPU A:  spin_lock_irqsave(&dev_lock, flags)
-CPU A:  val = readl(my_status);
-CPU A:  ...
-CPU A:  writel(newval, ring_ptr);
-CPU A:  (void)readl(safe_register); /* maybe a config register? */
-CPU A:  spin_unlock_irqrestore(&dev_lock, flags)
-        ...
-CPU B:  spin_lock_irqsave(&dev_lock, flags)
-CPU B:  val = readl(my_status);
-CPU B:  ...
-CPU B:  writel(newval2, ring_ptr);
-CPU B:  (void)readl(safe_register); /* maybe a config register? */
-CPU B:  spin_unlock_irqrestore(&dev_lock, flags)
+               ...
+       CPU A:  spin_lock_irqsave(&dev_lock, flags)
+       CPU A:  val = readl(my_status);
+       CPU A:  ...
+       CPU A:  writel(newval, ring_ptr);
+       CPU A:  (void)readl(safe_register); /* maybe a config register? */
+       CPU A:  spin_unlock_irqrestore(&dev_lock, flags)
+               ...
+       CPU B:  spin_lock_irqsave(&dev_lock, flags)
+       CPU B:  val = readl(my_status);
+       CPU B:  ...
+       CPU B:  writel(newval2, ring_ptr);
+       CPU B:  (void)readl(safe_register); /* maybe a config register? */
+       CPU B:  spin_unlock_irqrestore(&dev_lock, flags)
 
 Here, the reads from safe_register will cause the I/O chipset to flush any
 pending writes before actually posting the read to the chipset, preventing
index 65f694f..04d394a 100644 (file)
@@ -1,49 +1,50 @@
+=====================
 I/O statistics fields
----------------
+=====================
 
 Since 2.4.20 (and some versions before, with patches), and 2.5.45,
 more extensive disk statistics have been introduced to help measure disk
-activity. Tools such as sar and iostat typically interpret these and do
+activity. Tools such as ``sar`` and ``iostat`` typically interpret these and do
 the work for you, but in case you are interested in creating your own
 tools, the fields are explained here.
 
 In 2.4 now, the information is found as additional fields in
-/proc/partitions.  In 2.6, the same information is found in two
-places: one is in the file /proc/diskstats, and the other is within
+``/proc/partitions``.  In 2.6 and upper, the same information is found in two
+places: one is in the file ``/proc/diskstats``, and the other is within
 the sysfs file system, which must be mounted in order to obtain
 the information. Throughout this document we'll assume that sysfs
-is mounted on /sys, although of course it may be mounted anywhere.
-Both /proc/diskstats and sysfs use the same source for the information
+is mounted on ``/sys``, although of course it may be mounted anywhere.
+Both ``/proc/diskstats`` and sysfs use the same source for the information
 and so should not differ.
 
-Here are examples of these different formats:
+Here are examples of these different formats::
 
-2.4:
-   3     0   39082680 hda 446216 784926 9550688 4382310 424847 312726 5922052 19310380 0 3376340 23705160
-   3     1    9221278 hda1 35486 0 35496 38030 0 0 0 0 0 38030 38030
+   2.4:
+      3     0   39082680 hda 446216 784926 9550688 4382310 424847 312726 5922052 19310380 0 3376340 23705160
+      3     1    9221278 hda1 35486 0 35496 38030 0 0 0 0 0 38030 38030
 
+   2.6+ sysfs:
+      446216 784926 9550688 4382310 424847 312726 5922052 19310380 0 3376340 23705160
+      35486    38030    38030    38030
 
-2.6 sysfs:
-   446216 784926 9550688 4382310 424847 312726 5922052 19310380 0 3376340 23705160
-   35486    38030    38030    38030
+   2.6+ diskstats:
+      3    0   hda 446216 784926 9550688 4382310 424847 312726 5922052 19310380 0 3376340 23705160
+      3    1   hda1 35486 38030 38030 38030
 
-2.6 diskstats:
-   3    0   hda 446216 784926 9550688 4382310 424847 312726 5922052 19310380 0 3376340 23705160
-   3    1   hda1 35486 38030 38030 38030
+On 2.4 you might execute ``grep 'hda ' /proc/partitions``. On 2.6+, you have
+a choice of ``cat /sys/block/hda/stat`` or ``grep 'hda ' /proc/diskstats``.
 
-On 2.4 you might execute "grep 'hda ' /proc/partitions". On 2.6, you have
-a choice of "cat /sys/block/hda/stat" or "grep 'hda ' /proc/diskstats".
 The advantage of one over the other is that the sysfs choice works well
-if you are watching a known, small set of disks.  /proc/diskstats may
+if you are watching a known, small set of disks.  ``/proc/diskstats`` may
 be a better choice if you are watching a large number of disks because
 you'll avoid the overhead of 50, 100, or 500 or more opens/closes with
 each snapshot of your disk statistics.
 
 In 2.4, the statistics fields are those after the device name. In
 the above example, the first field of statistics would be 446216.
-By contrast, in 2.6 if you look at /sys/block/hda/stat, you'll
+By contrast, in 2.6+ if you look at ``/sys/block/hda/stat``, you'll
 find just the eleven fields, beginning with 446216.  If you look at
-/proc/diskstats, the eleven fields will be preceded by the major and
+``/proc/diskstats``, the eleven fields will be preceded by the major and
 minor device numbers, and device name.  Each of these formats provides
 eleven fields of statistics, each meaning exactly the same things.
 All fields except field 9 are cumulative since boot.  Field 9 should
@@ -59,30 +60,40 @@ system-wide stats you'll have to find all the devices and sum them all up.
 
 Field  1 -- # of reads completed
     This is the total number of reads completed successfully.
+
 Field  2 -- # of reads merged, field 6 -- # of writes merged
     Reads and writes which are adjacent to each other may be merged for
     efficiency.  Thus two 4K reads may become one 8K read before it is
     ultimately handed to the disk, and so it will be counted (and queued)
     as only one I/O.  This field lets you know how often this was done.
+
 Field  3 -- # of sectors read
     This is the total number of sectors read successfully.
+
 Field  4 -- # of milliseconds spent reading
     This is the total number of milliseconds spent by all reads (as
     measured from __make_request() to end_that_request_last()).
+
 Field  5 -- # of writes completed
     This is the total number of writes completed successfully.
+
 Field  6 -- # of writes merged
     See the description of field 2.
+
 Field  7 -- # of sectors written
     This is the total number of sectors written successfully.
+
 Field  8 -- # of milliseconds spent writing
     This is the total number of milliseconds spent by all writes (as
     measured from __make_request() to end_that_request_last()).
+
 Field  9 -- # of I/Os currently in progress
     The only field that should go to zero. Incremented as requests are
     given to appropriate struct request_queue and decremented as they finish.
+
 Field 10 -- # of milliseconds spent doing I/Os
     This field increases so long as field 9 is nonzero.
+
 Field 11 -- weighted # of milliseconds spent doing I/Os
     This field is incremented at each I/O start, I/O completion, I/O
     merge, or read of these stats by the number of I/Os in progress
@@ -97,7 +108,7 @@ introduced when changes collide, so (for instance) adding up all the
 read I/Os issued per partition should equal those made to the disks ...
 but due to the lack of locking it may only be very close.
 
-In 2.6, there are counters for each CPU, which make the lack of locking
+In 2.6+, there are counters for each CPU, which make the lack of locking
 almost a non-issue.  When the statistics are read, the per-CPU counters
 are summed (possibly overflowing the unsigned long variable they are
 summed to) and the result given to the user.  There is no convenient
@@ -106,22 +117,25 @@ user interface for accessing the per-CPU counters themselves.
 Disks vs Partitions
 -------------------
 
-There were significant changes between 2.4 and 2.6 in the I/O subsystem.
+There were significant changes between 2.4 and 2.6+ in the I/O subsystem.
 As a result, some statistic information disappeared. The translation from
 a disk address relative to a partition to the disk address relative to
 the host disk happens much earlier.  All merges and timings now happen
 at the disk level rather than at both the disk and partition level as
-in 2.4.  Consequently, you'll see a different statistics output on 2.6 for
+in 2.4.  Consequently, you'll see a different statistics output on 2.6+ for
 partitions from that for disks.  There are only *four* fields available
-for partitions on 2.6 machines.  This is reflected in the examples above.
+for partitions on 2.6+ machines.  This is reflected in the examples above.
 
 Field  1 -- # of reads issued
     This is the total number of reads issued to this partition.
+
 Field  2 -- # of sectors read
     This is the total number of sectors requested to be read from this
     partition.
+
 Field  3 -- # of writes issued
     This is the total number of writes issued to this partition.
+
 Field  4 -- # of sectors written
     This is the total number of sectors requested to be written to
     this partition.
@@ -149,16 +163,16 @@ to some (probably insignificant) inaccuracy.
 Additional notes
 ----------------
 
-In 2.6, sysfs is not mounted by default.  If your distribution of
+In 2.6+, sysfs is not mounted by default.  If your distribution of
 Linux hasn't added it already, here's the line you'll want to add to
-your /etc/fstab:
+your ``/etc/fstab``::
 
-none /sys sysfs defaults 0 0
+       none /sys sysfs defaults 0 0
 
 
-In 2.6, all disk statistics were removed from /proc/stat.  In 2.4, they
-appear in both /proc/partitions and /proc/stat, although the ones in
-/proc/stat take a very different format from those in /proc/partitions
+In 2.6+, all disk statistics were removed from ``/proc/stat``.  In 2.4, they
+appear in both ``/proc/partitions`` and ``/proc/stat``, although the ones in
+``/proc/stat`` take a very different format from those in ``/proc/partitions``
 (see proc(5), if your system has it.)
 
 -- ricklind@us.ibm.com
index f6da056..bdd2082 100644 (file)
@@ -1,8 +1,10 @@
+=======================
 IRQ-flags state tracing
+=======================
 
-started by Ingo Molnar <mingo@redhat.com>
+:Author: started by Ingo Molnar <mingo@redhat.com>
 
-the "irq-flags tracing" feature "traces" hardirq and softirq state, in
+The "irq-flags tracing" feature "traces" hardirq and softirq state, in
 that it gives interested subsystems an opportunity to be notified of
 every hardirqs-off/hardirqs-on, softirqs-off/softirqs-on event that
 happens in the kernel.
@@ -14,7 +16,7 @@ CONFIG_PROVE_RWSEM_LOCKING will be offered on an architecture - these
 are locking APIs that are not used in IRQ context. (the one exception
 for rwsems is worked around)
 
-architecture support for this is certainly not in the "trivial"
+Architecture support for this is certainly not in the "trivial"
 category, because lots of lowlevel assembly code deal with irq-flags
 state changes. But an architecture can be irq-flags-tracing enabled in a
 rather straightforward and risk-free manner.
@@ -41,7 +43,7 @@ irq-flags-tracing support:
   excluded from the irq-tracing [and lock validation] mechanism via
   lockdep_off()/lockdep_on().
 
-in general there is no risk from having an incomplete irq-flags-tracing
+In general there is no risk from having an incomplete irq-flags-tracing
 implementation in an architecture: lockdep will detect that and will
 turn itself off. I.e. the lock validator will still be reliable. There
 should be no crashes due to irq-tracing bugs. (except if the assembly
index f232c26..def4a7b 100644 (file)
@@ -1,5 +1,6 @@
+===========
 ISA Drivers
------------
+===========
 
 The following text is adapted from the commit message of the initial
 commit of the ISA bus driver authored by Rene Herman.
@@ -23,17 +24,17 @@ that all device creation has been made internal as well.
 
 The usage model this provides is nice, and has been acked from the ALSA
 side by Takashi Iwai and Jaroslav Kysela. The ALSA driver module_init's
-now (for oldisa-only drivers) become:
+now (for oldisa-only drivers) become::
 
-static int __init alsa_card_foo_init(void)
-{
-       return isa_register_driver(&snd_foo_isa_driver, SNDRV_CARDS);
-}
+       static int __init alsa_card_foo_init(void)
+       {
+               return isa_register_driver(&snd_foo_isa_driver, SNDRV_CARDS);
+       }
 
-static void __exit alsa_card_foo_exit(void)
-{
-       isa_unregister_driver(&snd_foo_isa_driver);
-}
+       static void __exit alsa_card_foo_exit(void)
+       {
+               isa_unregister_driver(&snd_foo_isa_driver);
+       }
 
 Quite like the other bus models therefore. This removes a lot of
 duplicated init code from the ALSA ISA drivers.
@@ -47,11 +48,11 @@ parameter, indicating how many devices to create and call our methods
 with.
 
 The platform_driver callbacks are called with a platform_device param;
-the isa_driver callbacks are being called with a "struct device *dev,
-unsigned int id" pair directly -- with the device creation completely
+the isa_driver callbacks are being called with a ``struct device *dev,
+unsigned int id`` pair directly -- with the device creation completely
 internal to the bus it's much cleaner to not leak isa_dev's by passing
 them in at all. The id is the only thing we ever want other then the
-struct device anyways, and it makes for nicer code in the callbacks as
+struct device anyways, and it makes for nicer code in the callbacks as
 well.
 
 With this additional .match() callback ISA drivers have all options. If
@@ -75,20 +76,20 @@ This exports only two functions; isa_{,un}register_driver().
 
 isa_register_driver() register's the struct device_driver, and then
 loops over the passed in ndev creating devices and registering them.
-This causes the bus match method to be called for them, which is:
+This causes the bus match method to be called for them, which is::
 
-int isa_bus_match(struct device *dev, struct device_driver *driver)
-{
-          struct isa_driver *isa_driver = to_isa_driver(driver);
+       int isa_bus_match(struct device *dev, struct device_driver *driver)
+       {
+               struct isa_driver *isa_driver = to_isa_driver(driver);
 
-          if (dev->platform_data == isa_driver) {
-                  if (!isa_driver->match ||
-                          isa_driver->match(dev, to_isa_dev(dev)->id))
-                          return 1;
-                  dev->platform_data = NULL;
-          }
-          return 0;
-}
+               if (dev->platform_data == isa_driver) {
+                       if (!isa_driver->match ||
+                               isa_driver->match(dev, to_isa_dev(dev)->id))
+                               return 1;
+                       dev->platform_data = NULL;
+               }
+               return 0;
+       }
 
 The first thing this does is check if this device is in fact one of this
 driver's devices by seeing if the device's platform_data pointer is set
@@ -102,7 +103,7 @@ well.
 Then, if the the driver did not provide a .match, it matches. If it did,
 the driver match() method is called to determine a match.
 
-If it did _not_ match, dev->platform_data is reset to indicate this to
+If it did **not** match, dev->platform_data is reset to indicate this to
 isa_register_driver which can then unregister the device again.
 
 If during all this, there's any error, or no devices matched at all
index 400d1b5..8d0840a 100644 (file)
@@ -1,3 +1,4 @@
+==========================================================
 ISA Plug & Play support by Jaroslav Kysela <perex@suse.cz>
 ==========================================================
 
index 615434d..5181445 100644 (file)
@@ -112,8 +112,8 @@ 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, ia64 and arm architectures support relocatable
-   kernel.
+   of today, i386, x86_64, ppc64, ia64, arm and arm64 architectures support
+   relocatable kernel.
 
 Building a relocatable kernel is advantageous from the point of view that
 one does not have to build a second kernel for capturing the dump. But
@@ -339,7 +339,7 @@ For arm:
 For arm64:
        - Use vmlinux or Image
 
-If you are using a uncompressed vmlinux image then use following command
+If you are using an uncompressed vmlinux image then use following command
 to load dump-capture kernel.
 
    kexec -p <dump-capture-kernel-vmlinux-image> \
@@ -361,6 +361,12 @@ to load dump-capture kernel.
    --dtb=<dtb-for-dump-capture-kernel> \
    --append="root=<root-dev> <arch-specific-options>"
 
+If you are using an uncompressed Image, then use following command
+to load dump-capture kernel.
+
+   kexec -p <dump-capture-kernel-Image> \
+   --initrd=<initrd-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
index 2cb7dc5..0f00f9c 100644 (file)
@@ -1,27 +1,29 @@
-REDUCING OS JITTER DUE TO PER-CPU KTHREADS
+==========================================
+Reducing OS jitter due to per-cpu kthreads
+==========================================
 
 This document lists per-CPU kthreads in the Linux kernel and presents
 options to control their OS jitter.  Note that non-per-CPU kthreads are
 not listed here.  To reduce OS jitter from non-per-CPU kthreads, bind
 them to a "housekeeping" CPU dedicated to such work.
 
+References
+==========
 
-REFERENCES
+-      Documentation/IRQ-affinity.txt:  Binding interrupts to sets of CPUs.
 
-o      Documentation/IRQ-affinity.txt:  Binding interrupts to sets of CPUs.
+-      Documentation/cgroup-v1:  Using cgroups to bind tasks to sets of CPUs.
 
-o      Documentation/cgroup-v1:  Using cgroups to bind tasks to sets of CPUs.
-
-o      man taskset:  Using the taskset command to bind tasks to sets
+-      man taskset:  Using the taskset command to bind tasks to sets
        of CPUs.
 
-o      man sched_setaffinity:  Using the sched_setaffinity() system
+-      man sched_setaffinity:  Using the sched_setaffinity() system
        call to bind tasks to sets of CPUs.
 
-o      /sys/devices/system/cpu/cpuN/online:  Control CPU N's hotplug state,
+-      /sys/devices/system/cpu/cpuN/online:  Control CPU N's hotplug state,
        writing "0" to offline and "1" to online.
 
-o      In order to locate kernel-generated OS jitter on CPU N:
+-      In order to locate kernel-generated OS jitter on CPU N:
 
                cd /sys/kernel/debug/tracing
                echo 1 > max_graph_depth # Increase the "1" for more detail
@@ -29,12 +31,17 @@ o   In order to locate kernel-generated OS jitter on CPU N:
                # run workload
                cat per_cpu/cpuN/trace
 
+kthreads
+========
+
+Name:
+  ehca_comp/%u
 
-KTHREADS
+Purpose:
+  Periodically process Infiniband-related work.
 
-Name: ehca_comp/%u
-Purpose: Periodically process Infiniband-related work.
 To reduce its OS jitter, do any of the following:
+
 1.     Don't use eHCA Infiniband hardware, instead choosing hardware
        that does not require per-CPU kthreads.  This will prevent these
        kthreads from being created in the first place.  (This will
@@ -46,26 +53,45 @@ To reduce its OS jitter, do any of the following:
        provisioned only on selected CPUs.
 
 
-Name: irq/%d-%s
-Purpose: Handle threaded interrupts.
+Name:
+  irq/%d-%s
+
+Purpose:
+  Handle threaded interrupts.
+
 To reduce its OS jitter, do the following:
+
 1.     Use irq affinity to force the irq threads to execute on
        some other CPU.
 
-Name: kcmtpd_ctr_%d
-Purpose: Handle Bluetooth work.
+Name:
+  kcmtpd_ctr_%d
+
+Purpose:
+  Handle Bluetooth work.
+
 To reduce its OS jitter, do one of the following:
+
 1.     Don't use Bluetooth, in which case these kthreads won't be
        created in the first place.
 2.     Use irq affinity to force Bluetooth-related interrupts to
        occur on some other CPU and furthermore initiate all
        Bluetooth activity on some other CPU.
 
-Name: ksoftirqd/%u
-Purpose: Execute softirq handlers when threaded or when under heavy load.
+Name:
+  ksoftirqd/%u
+
+Purpose:
+  Execute softirq handlers when threaded or when under heavy load.
+
 To reduce its OS jitter, each softirq vector must be handled
 separately as follows:
-TIMER_SOFTIRQ:  Do all of the following:
+
+TIMER_SOFTIRQ
+-------------
+
+Do all of the following:
+
 1.     To the extent possible, keep the CPU out of the kernel when it
        is non-idle, for example, by avoiding system calls and by forcing
        both kernel threads and interrupts to execute elsewhere.
@@ -76,34 +102,59 @@ TIMER_SOFTIRQ:  Do all of the following:
        first one back online.  Once you have onlined the CPUs in question,
        do not offline any other CPUs, because doing so could force the
        timer back onto one of the CPUs in question.
-NET_TX_SOFTIRQ and NET_RX_SOFTIRQ:  Do all of the following:
+
+NET_TX_SOFTIRQ and NET_RX_SOFTIRQ
+---------------------------------
+
+Do all of the following:
+
 1.     Force networking interrupts onto other CPUs.
 2.     Initiate any network I/O on other CPUs.
 3.     Once your application has started, prevent CPU-hotplug operations
        from being initiated from tasks that might run on the CPU to
        be de-jittered.  (It is OK to force this CPU offline and then
        bring it back online before you start your application.)
-BLOCK_SOFTIRQ:  Do all of the following:
+
+BLOCK_SOFTIRQ
+-------------
+
+Do all of the following:
+
 1.     Force block-device interrupts onto some other CPU.
 2.     Initiate any block I/O on other CPUs.
 3.     Once your application has started, prevent CPU-hotplug operations
        from being initiated from tasks that might run on the CPU to
        be de-jittered.  (It is OK to force this CPU offline and then
        bring it back online before you start your application.)
-IRQ_POLL_SOFTIRQ:  Do all of the following:
+
+IRQ_POLL_SOFTIRQ
+----------------
+
+Do all of the following:
+
 1.     Force block-device interrupts onto some other CPU.
 2.     Initiate any block I/O and block-I/O polling on other CPUs.
 3.     Once your application has started, prevent CPU-hotplug operations
        from being initiated from tasks that might run on the CPU to
        be de-jittered.  (It is OK to force this CPU offline and then
        bring it back online before you start your application.)
-TASKLET_SOFTIRQ: Do one or more of the following:
+
+TASKLET_SOFTIRQ
+---------------
+
+Do one or more of the following:
+
 1.     Avoid use of drivers that use tasklets.  (Such drivers will contain
        calls to things like tasklet_schedule().)
 2.     Convert all drivers that you must use from tasklets to workqueues.
 3.     Force interrupts for drivers using tasklets onto other CPUs,
        and also do I/O involving these drivers on other CPUs.
-SCHED_SOFTIRQ: Do all of the following:
+
+SCHED_SOFTIRQ
+-------------
+
+Do all of the following:
+
 1.     Avoid sending scheduler IPIs to the CPU to be de-jittered,
        for example, ensure that at most one runnable kthread is present
        on that CPU.  If a thread that expects to run on the de-jittered
@@ -120,7 +171,12 @@ SCHED_SOFTIRQ: Do all of the following:
        forcing both kernel threads and interrupts to execute elsewhere.
        This further reduces the number of scheduler-clock interrupts
        received by the de-jittered CPU.
-HRTIMER_SOFTIRQ:  Do all of the following:
+
+HRTIMER_SOFTIRQ
+---------------
+
+Do all of the following:
+
 1.     To the extent possible, keep the CPU out of the kernel when it
        is non-idle.  For example, avoid system calls and force both
        kernel threads and interrupts to execute elsewhere.
@@ -131,9 +187,15 @@ HRTIMER_SOFTIRQ:  Do all of the following:
        back online.  Once you have onlined the CPUs in question, do not
        offline any other CPUs, because doing so could force the timer
        back onto one of the CPUs in question.
-RCU_SOFTIRQ:  Do at least one of the following:
+
+RCU_SOFTIRQ
+-----------
+
+Do at least one of the following:
+
 1.     Offload callbacks and keep the CPU in either dyntick-idle or
        adaptive-ticks state by doing all of the following:
+
        a.      CONFIG_NO_HZ_FULL=y and ensure that the CPU to be
                de-jittered is marked as an adaptive-ticks CPU using the
                "nohz_full=" boot parameter.  Bind the rcuo kthreads to
@@ -142,8 +204,10 @@ RCU_SOFTIRQ:  Do at least one of the following:
                when it is non-idle, for example, by avoiding system
                calls and by forcing both kernel threads and interrupts
                to execute elsewhere.
+
 2.     Enable RCU to do its processing remotely via dyntick-idle by
        doing all of the following:
+
        a.      Build with CONFIG_NO_HZ=y and CONFIG_RCU_FAST_NO_HZ=y.
        b.      Ensure that the CPU goes idle frequently, allowing other
                CPUs to detect that it has passed through an RCU quiescent
@@ -155,15 +219,20 @@ RCU_SOFTIRQ:  Do at least one of the following:
                calls and by forcing both kernel threads and interrupts
                to execute elsewhere.
 
-Name: kworker/%u:%d%s (cpu, id, priority)
-Purpose: Execute workqueue requests
+Name:
+  kworker/%u:%d%s (cpu, id, priority)
+
+Purpose:
+  Execute workqueue requests
+
 To reduce its OS jitter, do any of the following:
+
 1.     Run your workload at a real-time priority, which will allow
        preempting the kworker daemons.
 2.     A given workqueue can be made visible in the sysfs filesystem
        by passing the WQ_SYSFS to that workqueue's alloc_workqueue().
        Such a workqueue can be confined to a given subset of the
-       CPUs using the /sys/devices/virtual/workqueue/*/cpumask sysfs
+       CPUs using the ``/sys/devices/virtual/workqueue/*/cpumask`` sysfs
        files.  The set of WQ_SYSFS workqueues can be displayed using
        "ls sys/devices/virtual/workqueue".  That said, the workqueues
        maintainer would like to caution people against indiscriminately
@@ -173,6 +242,7 @@ To reduce its OS jitter, do any of the following:
        to remove it, even if its addition was a mistake.
 3.     Do any of the following needed to avoid jitter that your
        application cannot tolerate:
+
        a.      Build your kernel with CONFIG_SLUB=y rather than
                CONFIG_SLAB=y, thus avoiding the slab allocator's periodic
                use of each CPU's workqueues to run its cache_reap()
@@ -186,6 +256,7 @@ To reduce its OS jitter, do any of the following:
                be able to build your kernel with CONFIG_CPU_FREQ=n to
                avoid the CPU-frequency governor periodically running
                on each CPU, including cs_dbs_timer() and od_dbs_timer().
+
                WARNING:  Please check your CPU specifications to
                make sure that this is safe on your particular system.
        d.      As of v3.18, Christoph Lameter's on-demand vmstat workers
@@ -222,9 +293,14 @@ To reduce its OS jitter, do any of the following:
                CONFIG_PMAC_RACKMETER=n to disable the CPU-meter,
                avoiding OS jitter from rackmeter_do_timer().
 
-Name: rcuc/%u
-Purpose: Execute RCU callbacks in CONFIG_RCU_BOOST=y kernels.
+Name:
+  rcuc/%u
+
+Purpose:
+  Execute RCU callbacks in CONFIG_RCU_BOOST=y kernels.
+
 To reduce its OS jitter, do at least one of the following:
+
 1.     Build the kernel with CONFIG_PREEMPT=n.  This prevents these
        kthreads from being created in the first place, and also obviates
        the need for RCU priority boosting.  This approach is feasible
@@ -244,9 +320,14 @@ To reduce its OS jitter, do at least one of the following:
        CPU, again preventing the rcuc/%u kthreads from having any work
        to do.
 
-Name: rcuob/%d, rcuop/%d, and rcuos/%d
-Purpose: Offload RCU callbacks from the corresponding CPU.
+Name:
+  rcuob/%d, rcuop/%d, and rcuos/%d
+
+Purpose:
+  Offload RCU callbacks from the corresponding CPU.
+
 To reduce its OS jitter, do at least one of the following:
+
 1.     Use affinity, cgroups, or other mechanism to force these kthreads
        to execute on some other CPU.
 2.     Build with CONFIG_RCU_NOCB_CPU=n, which will prevent these
@@ -254,9 +335,14 @@ To reduce its OS jitter, do at least one of the following:
        note that this will not eliminate OS jitter, but will instead
        shift it to RCU_SOFTIRQ.
 
-Name: watchdog/%u
-Purpose: Detect software lockups on each CPU.
+Name:
+  watchdog/%u
+
+Purpose:
+  Detect software lockups on each CPU.
+
 To reduce its OS jitter, do at least one of the following:
+
 1.     Build with CONFIG_LOCKUP_DETECTOR=n, which will prevent these
        kthreads from being created in the first place.
 2.     Boot with "nosoftlockup=0", which will also prevent these kthreads
index 1be59a3..fc9485d 100644 (file)
@@ -1,13 +1,13 @@
+=====================================================================
 Everything you never wanted to know about kobjects, ksets, and ktypes
+=====================================================================
 
-Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+:Author: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+:Last updated: December 19, 2007
 
 Based on an original article by Jon Corbet for lwn.net written October 1,
 2003 and located at http://lwn.net/Articles/51437/
 
-Last updated December 19, 2007
-
-
 Part of the difficulty in understanding the driver model - and the kobject
 abstraction upon which it is built - is that there is no obvious starting
 place. Dealing with kobjects requires understanding a few different types,
@@ -47,6 +47,7 @@ approach will be taken, so we'll go back to kobjects.
 
 
 Embedding kobjects
+==================
 
 It is rare for kernel code to create a standalone kobject, with one major
 exception explained below.  Instead, kobjects are used to control access to
@@ -65,7 +66,7 @@ their own, but are invariably found embedded in the larger objects of
 interest.)
 
 So, for example, the UIO code in drivers/uio/uio.c has a structure that
-defines the memory region associated with a uio device:
+defines the memory region associated with a uio device::
 
     struct uio_map {
        struct kobject kobj;
@@ -77,7 +78,7 @@ just a matter of using the kobj member.  Code that works with kobjects will
 often have the opposite problem, however: given a struct kobject pointer,
 what is the pointer to the containing structure?  You must avoid tricks
 (such as assuming that the kobject is at the beginning of the structure)
-and, instead, use the container_of() macro, found in <linux/kernel.h>:
+and, instead, use the container_of() macro, found in <linux/kernel.h>::
 
     container_of(pointer, type, member)
 
@@ -90,13 +91,13 @@ where:
 The return value from container_of() is a pointer to the corresponding
 container type. So, for example, a pointer "kp" to a struct kobject
 embedded *within* a struct uio_map could be converted to a pointer to the
-*containing* uio_map structure with:
+*containing* uio_map structure with::
 
     struct uio_map *u_map = container_of(kp, struct uio_map, kobj);
 
 For convenience, programmers often define a simple macro for "back-casting"
 kobject pointers to the containing type.  Exactly this happens in the
-earlier drivers/uio/uio.c, as you can see here:
+earlier drivers/uio/uio.c, as you can see here::
 
     struct uio_map {
         struct kobject kobj;
@@ -106,23 +107,25 @@ earlier drivers/uio/uio.c, as you can see here:
     #define to_map(map) container_of(map, struct uio_map, kobj)
 
 where the macro argument "map" is a pointer to the struct kobject in
-question.  That macro is subsequently invoked with:
+question.  That macro is subsequently invoked with::
 
     struct uio_map *map = to_map(kobj);
 
 
 Initialization of kobjects
+==========================
 
 Code which creates a kobject must, of course, initialize that object. Some
-of the internal fields are setup with a (mandatory) call to kobject_init():
+of the internal fields are setup with a (mandatory) call to kobject_init()::
 
     void kobject_init(struct kobject *kobj, struct kobj_type *ktype);
 
 The ktype is required for a kobject to be created properly, as every kobject
 must have an associated kobj_type.  After calling kobject_init(), to
-register the kobject with sysfs, the function kobject_add() must be called:
+register the kobject with sysfs, the function kobject_add() must be called::
 
-    int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...);
+    int kobject_add(struct kobject *kobj, struct kobject *parent,
+                   const char *fmt, ...);
 
 This sets up the parent of the kobject and the name for the kobject
 properly.  If the kobject is to be associated with a specific kset,
@@ -133,7 +136,7 @@ kset itself.
 
 As the name of the kobject is set when it is added to the kernel, the name
 of the kobject should never be manipulated directly.  If you must change
-the name of the kobject, call kobject_rename():
+the name of the kobject, call kobject_rename()::
 
     int kobject_rename(struct kobject *kobj, const char *new_name);
 
@@ -146,12 +149,12 @@ is being removed.  If your code needs to call this function, it is
 incorrect and needs to be fixed.
 
 To properly access the name of the kobject, use the function
-kobject_name():
+kobject_name()::
 
     const char *kobject_name(const struct kobject * kobj);
 
 There is a helper function to both initialize and add the kobject to the
-kernel at the same time, called surprisingly enough kobject_init_and_add():
+kernel at the same time, called surprisingly enough kobject_init_and_add()::
 
     int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
                              struct kobject *parent, const char *fmt, ...);
@@ -161,10 +164,11 @@ kobject_add() functions described above.
 
 
 Uevents
+=======
 
 After a kobject has been registered with the kobject core, you need to
 announce to the world that it has been created.  This can be done with a
-call to kobject_uevent():
+call to kobject_uevent()::
 
     int kobject_uevent(struct kobject *kobj, enum kobject_action action);
 
@@ -180,11 +184,12 @@ hand.
 
 
 Reference counts
+================
 
 One of the key functions of a kobject is to serve as a reference counter
 for the object in which it is embedded. As long as references to the object
 exist, the object (and the code which supports it) must continue to exist.
-The low-level functions for manipulating a kobject's reference counts are:
+The low-level functions for manipulating a kobject's reference counts are::
 
     struct kobject *kobject_get(struct kobject *kobj);
     void kobject_put(struct kobject *kobj);
@@ -209,21 +214,24 @@ file Documentation/kref.txt in the Linux kernel source tree.
 
 
 Creating "simple" kobjects
+==========================
 
 Sometimes all that a developer wants is a way to create a simple directory
 in the sysfs hierarchy, and not have to mess with the whole complication of
 ksets, show and store functions, and other details.  This is the one
 exception where a single kobject should be created.  To create such an
-entry, use the function:
+entry, use the function::
 
     struct kobject *kobject_create_and_add(char *name, struct kobject *parent);
 
 This function will create a kobject and place it in sysfs in the location
 underneath the specified parent kobject.  To create simple attributes
-associated with this kobject, use:
+associated with this kobject, use::
 
     int sysfs_create_file(struct kobject *kobj, struct attribute *attr);
-or
+
+or::
+
     int sysfs_create_group(struct kobject *kobj, struct attribute_group *grp);
 
 Both types of attributes used here, with a kobject that has been created
@@ -236,6 +244,7 @@ implementation of a simple kobject and attributes.
 
 
 ktypes and release methods
+==========================
 
 One important thing still missing from the discussion is what happens to a
 kobject when its reference count reaches zero. The code which created the
@@ -257,7 +266,7 @@ is good practice to always use kobject_put() after kobject_init() to avoid
 errors creeping in.
 
 This notification is done through a kobject's release() method. Usually
-such a method has a form like:
+such a method has a form like::
 
     void my_object_release(struct kobject *kobj)
     {
@@ -281,7 +290,7 @@ leak in the kobject core, which makes people unhappy.
 
 Interestingly, the release() method is not stored in the kobject itself;
 instead, it is associated with the ktype. So let us introduce struct
-kobj_type:
+kobj_type::
 
     struct kobj_type {
            void (*release)(struct kobject *kobj);
@@ -306,6 +315,7 @@ automatically created for any kobject that is registered with this ktype.
 
 
 ksets
+=====
 
 A kset is merely a collection of kobjects that want to be associated with
 each other.  There is no restriction that they be of the same ktype, but be
@@ -335,13 +345,16 @@ kobject) in their parent.
 
 As a kset contains a kobject within it, it should always be dynamically
 created and never declared statically or on the stack.  To create a new
-kset use:
+kset use::
+
   struct kset *kset_create_and_add(const char *name,
                                   struct kset_uevent_ops *u,
                                   struct kobject *parent);
 
-When you are finished with the kset, call:
+When you are finished with the kset, call::
+
   void kset_unregister(struct kset *kset);
+
 to destroy it.  This removes the kset from sysfs and decrements its reference
 count.  When the reference count goes to zero, the kset will be released.
 Because other references to the kset may still exist, the release may happen
@@ -351,14 +364,14 @@ An example of using a kset can be seen in the
 samples/kobject/kset-example.c file in the kernel tree.
 
 If a kset wishes to control the uevent operations of the kobjects
-associated with it, it can use the struct kset_uevent_ops to handle it:
+associated with it, it can use the struct kset_uevent_ops to handle it::
 
-struct kset_uevent_ops {
+  struct kset_uevent_ops {
         int (*filter)(struct kset *kset, struct kobject *kobj);
         const char *(*name)(struct kset *kset, struct kobject *kobj);
         int (*uevent)(struct kset *kset, struct kobject *kobj,
                       struct kobj_uevent_env *env);
-};
+  };
 
 
 The filter function allows a kset to prevent a uevent from being emitted to
@@ -386,6 +399,7 @@ added below the parent kobject.
 
 
 Kobject removal
+===============
 
 After a kobject has been registered with the kobject core successfully, it
 must be cleaned up when the code is finished with it.  To do that, call
@@ -409,6 +423,7 @@ called, and the objects in the former circle release each other.
 
 
 Example code to copy from
+=========================
 
 For a more complete example of using ksets and kobjects properly, see the
 example programs samples/kobject/{kobject-example.c,kset-example.c},
index 1f6d45a..2335715 100644 (file)
@@ -1,30 +1,36 @@
-Title  : Kernel Probes (Kprobes)
-Authors        : Jim Keniston <jkenisto@us.ibm.com>
-       : Prasanna S Panchamukhi <prasanna.panchamukhi@gmail.com>
-       : Masami Hiramatsu <mhiramat@redhat.com>
-
-CONTENTS
-
-1. Concepts: Kprobes, Jprobes, Return Probes
-2. Architectures Supported
-3. Configuring Kprobes
-4. API Reference
-5. Kprobes Features and Limitations
-6. Probe Overhead
-7. TODO
-8. Kprobes Example
-9. Jprobes Example
-10. Kretprobes Example
-Appendix A: The kprobes debugfs interface
-Appendix B: The kprobes sysctl interface
-
-1. Concepts: Kprobes, Jprobes, Return Probes
+=======================
+Kernel Probes (Kprobes)
+=======================
+
+:Author: Jim Keniston <jkenisto@us.ibm.com>
+:Author: Prasanna S Panchamukhi <prasanna.panchamukhi@gmail.com>
+:Author: Masami Hiramatsu <mhiramat@redhat.com>
+
+.. CONTENTS
+
+  1. Concepts: Kprobes, Jprobes, Return Probes
+  2. Architectures Supported
+  3. Configuring Kprobes
+  4. API Reference
+  5. Kprobes Features and Limitations
+  6. Probe Overhead
+  7. TODO
+  8. Kprobes Example
+  9. Jprobes Example
+  10. Kretprobes Example
+  Appendix A: The kprobes debugfs interface
+  Appendix B: The kprobes sysctl interface
+
+Concepts: Kprobes, Jprobes, Return Probes
+=========================================
 
 Kprobes enables you to dynamically break into any kernel routine and
 collect debugging and performance information non-disruptively. You
-can trap at almost any kernel code address(*), specifying a handler
+can trap at almost any kernel code address [1]_, specifying a handler
 routine to be invoked when the breakpoint is hit.
-(*: some parts of the kernel code can not be trapped, see 1.5 Blacklist)
+
+.. [1] some parts of the kernel code can not be trapped, see
+       :ref:`kprobes_blacklist`)
 
 There are currently three types of probes: kprobes, jprobes, and
 kretprobes (also called return probes).  A kprobe can be inserted
@@ -40,8 +46,8 @@ registration function such as register_kprobe() specifies where
 the probe is to be inserted and what handler is to be called when
 the probe is hit.
 
-There are also register_/unregister_*probes() functions for batch
-registration/unregistration of a group of *probes. These functions
+There are also ``register_/unregister_*probes()`` functions for batch
+registration/unregistration of a group of ``*probes``. These functions
 can speed up unregistration process when you have to unregister
 a lot of probes at once.
 
@@ -51,9 +57,10 @@ things that you'll need to know in order to make the best use of
 Kprobes -- e.g., the difference between a pre_handler and
 a post_handler, and how to use the maxactive and nmissed fields of
 a kretprobe.  But if you're in a hurry to start using Kprobes, you
-can skip ahead to section 2.
+can skip ahead to :ref:`kprobes_archs_supported`.
 
-1.1 How Does a Kprobe Work?
+How Does a Kprobe Work?
+-----------------------
 
 When a kprobe is registered, Kprobes makes a copy of the probed
 instruction and replaces the first byte(s) of the probed instruction
@@ -75,7 +82,8 @@ After the instruction is single-stepped, Kprobes executes the
 "post_handler," if any, that is associated with the kprobe.
 Execution then continues with the instruction following the probepoint.
 
-1.2 How Does a Jprobe Work?
+How Does a Jprobe Work?
+-----------------------
 
 A jprobe is implemented using a kprobe that is placed on a function's
 entry point.  It employs a simple mirroring principle to allow
@@ -113,9 +121,11 @@ more than eight function arguments, an argument of more than sixteen
 bytes, or more than 64 bytes of argument data, depending on
 architecture).
 
-1.3 Return Probes
+Return Probes
+-------------
 
-1.3.1 How Does a Return Probe Work?
+How Does a Return Probe Work?
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 When you call register_kretprobe(), Kprobes establishes a kprobe at
 the entry to the function.  When the probed function is called and this
@@ -150,7 +160,8 @@ zero when the return probe is registered, and is incremented every
 time the probed function is entered but there is no kretprobe_instance
 object available for establishing the return probe.
 
-1.3.2 Kretprobe entry-handler
+Kretprobe entry-handler
+^^^^^^^^^^^^^^^^^^^^^^^
 
 Kretprobes also provides an optional user-specified handler which runs
 on function entry. This handler is specified by setting the entry_handler
@@ -174,7 +185,10 @@ In case probed function is entered but there is no kretprobe_instance
 object available, then in addition to incrementing the nmissed count,
 the user entry_handler invocation is also skipped.
 
-1.4 How Does Jump Optimization Work?
+.. _kprobes_jump_optimization:
+
+How Does Jump Optimization Work?
+--------------------------------
 
 If your kernel is built with CONFIG_OPTPROBES=y (currently this flag
 is automatically set 'y' on x86/x86-64, non-preemptive kernel) and
@@ -182,53 +196,60 @@ the "debug.kprobes_optimization" kernel parameter is set to 1 (see
 sysctl(8)), Kprobes tries to reduce probe-hit overhead by using a jump
 instruction instead of a breakpoint instruction at each probepoint.
 
-1.4.1 Init a Kprobe
+Init a Kprobe
+^^^^^^^^^^^^^
 
 When a probe is registered, before attempting this optimization,
 Kprobes inserts an ordinary, breakpoint-based kprobe at the specified
 address. So, even if it's not possible to optimize this particular
 probepoint, there'll be a probe there.
 
-1.4.2 Safety Check
+Safety Check
+^^^^^^^^^^^^
 
 Before optimizing a probe, Kprobes performs the following safety checks:
 
 - Kprobes verifies that the region that will be replaced by the jump
-instruction (the "optimized region") lies entirely within one function.
-(A jump instruction is multiple bytes, and so may overlay multiple
-instructions.)
+  instruction (the "optimized region") lies entirely within one function.
+  (A jump instruction is multiple bytes, and so may overlay multiple
+  instructions.)
 
 - Kprobes analyzes the entire function and verifies that there is no
-jump into the optimized region.  Specifically:
+  jump into the optimized region.  Specifically:
+
   - the function contains no indirect jump;
   - the function contains no instruction that causes an exception (since
-  the fixup code triggered by the exception could jump back into the
-  optimized region -- Kprobes checks the exception tables to verify this);
-  and
+    the fixup code triggered by the exception could jump back into the
+    optimized region -- Kprobes checks the exception tables to verify this);
   - there is no near jump to the optimized region (other than to the first
-  byte).
+    byte).
 
 - For each instruction in the optimized region, Kprobes verifies that
-the instruction can be executed out of line.
+  the instruction can be executed out of line.
 
-1.4.3 Preparing Detour Buffer
+Preparing Detour Buffer
+^^^^^^^^^^^^^^^^^^^^^^^
 
 Next, Kprobes prepares a "detour" buffer, which contains the following
 instruction sequence:
+
 - code to push the CPU's registers (emulating a breakpoint trap)
 - a call to the trampoline code which calls user's probe handlers.
 - code to restore registers
 - the instructions from the optimized region
 - a jump back to the original execution path.
 
-1.4.4 Pre-optimization
+Pre-optimization
+^^^^^^^^^^^^^^^^
 
 After preparing the detour buffer, Kprobes verifies that none of the
 following situations exist:
+
 - The probe has either a break_handler (i.e., it's a jprobe) or a
-post_handler.
+  post_handler.
 - Other instructions in the optimized region are probed.
 - The probe is disabled.
+
 In any of the above cases, Kprobes won't start optimizing the probe.
 Since these are temporary situations, Kprobes tries to start
 optimizing it again if the situation is changed.
@@ -240,21 +261,23 @@ Kprobes returns control to the original instruction path by setting
 the CPU's instruction pointer to the copied code in the detour buffer
 -- thus at least avoiding the single-step.
 
-1.4.5 Optimization
+Optimization
+^^^^^^^^^^^^
 
 The Kprobe-optimizer doesn't insert the jump instruction immediately;
 rather, it calls synchronize_sched() for safety first, because it's
 possible for a CPU to be interrupted in the middle of executing the
-optimized region(*).  As you know, synchronize_sched() can ensure
+optimized region [3]_.  As you know, synchronize_sched() can ensure
 that all interruptions that were active when synchronize_sched()
 was called are done, but only if CONFIG_PREEMPT=n.  So, this version
-of kprobe optimization supports only kernels with CONFIG_PREEMPT=n.(**)
+of kprobe optimization supports only kernels with CONFIG_PREEMPT=n [4]_.
 
 After that, the Kprobe-optimizer calls stop_machine() to replace
 the optimized region with a jump instruction to the detour buffer,
 using text_poke_smp().
 
-1.4.6 Unoptimization
+Unoptimization
+^^^^^^^^^^^^^^
 
 When an optimized kprobe is unregistered, disabled, or blocked by
 another kprobe, it will be unoptimized.  If this happens before
@@ -263,15 +286,15 @@ optimized list.  If the optimization has been done, the jump is
 replaced with the original code (except for an int3 breakpoint in
 the first byte) by using text_poke_smp().
 
-(*)Please imagine that the 2nd instruction is interrupted and then
-the optimizer replaces the 2nd instruction with the jump *address*
-while the interrupt handler is running. When the interrupt
-returns to original address, there is no valid instruction,
-and it causes an unexpected result.
+.. [3] Please imagine that the 2nd instruction is interrupted and then
+   the optimizer replaces the 2nd instruction with the jump *address*
+   while the interrupt handler is running. When the interrupt
+   returns to original address, there is no valid instruction,
+   and it causes an unexpected result.
 
-(**)This optimization-safety checking may be replaced with the
-stop-machine method that ksplice uses for supporting a CONFIG_PREEMPT=y
-kernel.
+.. [4] This optimization-safety checking may be replaced with the
+   stop-machine method that ksplice uses for supporting a CONFIG_PREEMPT=y
+   kernel.
 
 NOTE for geeks:
 The jump optimization changes the kprobe's pre_handler behavior.
@@ -280,11 +303,17 @@ path by changing regs->ip and returning 1.  However, when the probe
 is optimized, that modification is ignored.  Thus, if you want to
 tweak the kernel's execution path, you need to suppress optimization,
 using one of the following techniques:
+
 - Specify an empty function for the kprobe's post_handler or break_handler.
- or
+
+or
+
 - Execute 'sysctl -w debug.kprobes_optimization=n'
 
-1.5 Blacklist
+.. _kprobes_blacklist:
+
+Blacklist
+---------
 
 Kprobes can probe most of the kernel except itself. This means
 that there are some functions where kprobes cannot probe. Probing
@@ -297,7 +326,10 @@ to specify a blacklisted function.
 Kprobes checks the given probe address against the blacklist and
 rejects registering it, if the given address is in the blacklist.
 
-2. Architectures Supported
+.. _kprobes_archs_supported:
+
+Architectures Supported
+=======================
 
 Kprobes, jprobes, and return probes are implemented on the following
 architectures:
@@ -312,7 +344,8 @@ architectures:
 - mips
 - s390
 
-3. Configuring Kprobes
+Configuring Kprobes
+===================
 
 When configuring the kernel using make menuconfig/xconfig/oldconfig,
 ensure that CONFIG_KPROBES is set to "y". Under "General setup", look
@@ -331,7 +364,8 @@ it useful to "Compile the kernel with debug info" (CONFIG_DEBUG_INFO),
 so you can use "objdump -d -l vmlinux" to see the source-to-object
 code mapping.
 
-4. API Reference
+API Reference
+=============
 
 The Kprobes API includes a "register" function and an "unregister"
 function for each type of probe. The API also includes "register_*probes"
@@ -340,10 +374,13 @@ Here are terse, mini-man-page specifications for these functions and
 the associated probe handlers that you'll write. See the files in the
 samples/kprobes/ sub-directory for examples.
 
-4.1 register_kprobe
+register_kprobe
+---------------
+
+::
 
-#include <linux/kprobes.h>
-int register_kprobe(struct kprobe *kp);
+       #include <linux/kprobes.h>
+       int register_kprobe(struct kprobe *kp);
 
 Sets a breakpoint at the address kp->addr.  When the breakpoint is
 hit, Kprobes calls kp->pre_handler.  After the probed instruction
@@ -354,61 +391,68 @@ kp->fault_handler.  Any or all handlers can be NULL. If kp->flags
 is set KPROBE_FLAG_DISABLED, that kp will be registered but disabled,
 so, its handlers aren't hit until calling enable_kprobe(kp).
 
-NOTE:
-1. With the introduction of the "symbol_name" field to struct kprobe,
-the probepoint address resolution will now be taken care of by the kernel.
-The following will now work:
+.. note::
+
+   1. With the introduction of the "symbol_name" field to struct kprobe,
+      the probepoint address resolution will now be taken care of by the kernel.
+      The following will now work::
 
        kp.symbol_name = "symbol_name";
 
-(64-bit powerpc intricacies such as function descriptors are handled
-transparently)
+      (64-bit powerpc intricacies such as function descriptors are handled
+      transparently)
 
-2. Use the "offset" field of struct kprobe if the offset into the symbol
-to install a probepoint is known. This field is used to calculate the
-probepoint.
+   2. Use the "offset" field of struct kprobe if the offset into the symbol
+      to install a probepoint is known. This field is used to calculate the
+      probepoint.
 
-3. Specify either the kprobe "symbol_name" OR the "addr". If both are
-specified, kprobe registration will fail with -EINVAL.
+   3. Specify either the kprobe "symbol_name" OR the "addr". If both are
+      specified, kprobe registration will fail with -EINVAL.
 
-4. With CISC architectures (such as i386 and x86_64), the kprobes code
-does not validate if the kprobe.addr is at an instruction boundary.
-Use "offset" with caution.
+   4. With CISC architectures (such as i386 and x86_64), the kprobes code
+      does not validate if the kprobe.addr is at an instruction boundary.
+      Use "offset" with caution.
 
 register_kprobe() returns 0 on success, or a negative errno otherwise.
 
-User's pre-handler (kp->pre_handler):
-#include <linux/kprobes.h>
-#include <linux/ptrace.h>
-int pre_handler(struct kprobe *p, struct pt_regs *regs);
+User's pre-handler (kp->pre_handler)::
+
+       #include <linux/kprobes.h>
+       #include <linux/ptrace.h>
+       int pre_handler(struct kprobe *p, struct pt_regs *regs);
 
 Called with p pointing to the kprobe associated with the breakpoint,
 and regs pointing to the struct containing the registers saved when
 the breakpoint was hit.  Return 0 here unless you're a Kprobes geek.
 
-User's post-handler (kp->post_handler):
-#include <linux/kprobes.h>
-#include <linux/ptrace.h>
-void post_handler(struct kprobe *p, struct pt_regs *regs,
-       unsigned long flags);
+User's post-handler (kp->post_handler)::
+
+       #include <linux/kprobes.h>
+       #include <linux/ptrace.h>
+       void post_handler(struct kprobe *p, struct pt_regs *regs,
+                         unsigned long flags);
 
 p and regs are as described for the pre_handler.  flags always seems
 to be zero.
 
-User's fault-handler (kp->fault_handler):
-#include <linux/kprobes.h>
-#include <linux/ptrace.h>
-int fault_handler(struct kprobe *p, struct pt_regs *regs, int trapnr);
+User's fault-handler (kp->fault_handler)::
+
+       #include <linux/kprobes.h>
+       #include <linux/ptrace.h>
+       int fault_handler(struct kprobe *p, struct pt_regs *regs, int trapnr);
 
 p and regs are as described for the pre_handler.  trapnr is the
 architecture-specific trap number associated with the fault (e.g.,
 on i386, 13 for a general protection fault or 14 for a page fault).
 Returns 1 if it successfully handled the exception.
 
-4.2 register_jprobe
+register_jprobe
+---------------
 
-#include <linux/kprobes.h>
-int register_jprobe(struct jprobe *jp)
+::
+
+       #include <linux/kprobes.h>
+       int register_jprobe(struct jprobe *jp)
 
 Sets a breakpoint at the address jp->kp.addr, which must be the address
 of the first instruction of a function.  When the breakpoint is hit,
@@ -423,10 +467,13 @@ declaration must match.
 
 register_jprobe() returns 0 on success, or a negative errno otherwise.
 
-4.3 register_kretprobe
+register_kretprobe
+------------------
+
+::
 
-#include <linux/kprobes.h>
-int register_kretprobe(struct kretprobe *rp);
+       #include <linux/kprobes.h>
+       int register_kretprobe(struct kretprobe *rp);
 
 Establishes a return probe for the function whose address is
 rp->kp.addr.  When that function returns, Kprobes calls rp->handler.
@@ -436,14 +483,17 @@ register_kretprobe(); see "How Does a Return Probe Work?" for details.
 register_kretprobe() returns 0 on success, or a negative errno
 otherwise.
 
-User's return-probe handler (rp->handler):
-#include <linux/kprobes.h>
-#include <linux/ptrace.h>
-int kretprobe_handler(struct kretprobe_instance *ri, struct pt_regs *regs);
+User's return-probe handler (rp->handler)::
+
+       #include <linux/kprobes.h>
+       #include <linux/ptrace.h>
+       int kretprobe_handler(struct kretprobe_instance *ri,
+                             struct pt_regs *regs);
 
 regs is as described for kprobe.pre_handler.  ri points to the
 kretprobe_instance object, of which the following fields may be
 of interest:
+
 - ret_addr: the return address
 - rp: points to the corresponding kretprobe object
 - task: points to the corresponding task struct
@@ -456,74 +506,94 @@ the architecture's ABI.
 
 The handler's return value is currently ignored.
 
-4.4 unregister_*probe
+unregister_*probe
+------------------
+
+::
 
-#include <linux/kprobes.h>
-void unregister_kprobe(struct kprobe *kp);
-void unregister_jprobe(struct jprobe *jp);
-void unregister_kretprobe(struct kretprobe *rp);
+       #include <linux/kprobes.h>
+       void unregister_kprobe(struct kprobe *kp);
+       void unregister_jprobe(struct jprobe *jp);
+       void unregister_kretprobe(struct kretprobe *rp);
 
 Removes the specified probe.  The unregister function can be called
 at any time after the probe has been registered.
 
-NOTE:
-If the functions find an incorrect probe (ex. an unregistered probe),
-they clear the addr field of the probe.
+.. note::
+
+   If the functions find an incorrect probe (ex. an unregistered probe),
+   they clear the addr field of the probe.
+
+register_*probes
+----------------
 
-4.5 register_*probes
+::
 
-#include <linux/kprobes.h>
-int register_kprobes(struct kprobe **kps, int num);
-int register_kretprobes(struct kretprobe **rps, int num);
-int register_jprobes(struct jprobe **jps, int num);
+       #include <linux/kprobes.h>
+       int register_kprobes(struct kprobe **kps, int num);
+       int register_kretprobes(struct kretprobe **rps, int num);
+       int register_jprobes(struct jprobe **jps, int num);
 
 Registers each of the num probes in the specified array.  If any
 error occurs during registration, all probes in the array, up to
 the bad probe, are safely unregistered before the register_*probes
 function returns.
-- kps/rps/jps: an array of pointers to *probe data structures
+
+- kps/rps/jps: an array of pointers to ``*probe`` data structures
 - num: the number of the array entries.
 
-NOTE:
-You have to allocate(or define) an array of pointers and set all
-of the array entries before using these functions.
+.. note::
+
+   You have to allocate(or define) an array of pointers and set all
+   of the array entries before using these functions.
 
-4.6 unregister_*probes
+unregister_*probes
+------------------
 
-#include <linux/kprobes.h>
-void unregister_kprobes(struct kprobe **kps, int num);
-void unregister_kretprobes(struct kretprobe **rps, int num);
-void unregister_jprobes(struct jprobe **jps, int num);
+::
+
+       #include <linux/kprobes.h>
+       void unregister_kprobes(struct kprobe **kps, int num);
+       void unregister_kretprobes(struct kretprobe **rps, int num);
+       void unregister_jprobes(struct jprobe **jps, int num);
 
 Removes each of the num probes in the specified array at once.
 
-NOTE:
-If the functions find some incorrect probes (ex. unregistered
-probes) in the specified array, they clear the addr field of those
-incorrect probes. However, other probes in the array are
-unregistered correctly.
+.. note::
+
+   If the functions find some incorrect probes (ex. unregistered
+   probes) in the specified array, they clear the addr field of those
+   incorrect probes. However, other probes in the array are
+   unregistered correctly.
 
-4.7 disable_*probe
+disable_*probe
+--------------
 
-#include <linux/kprobes.h>
-int disable_kprobe(struct kprobe *kp);
-int disable_kretprobe(struct kretprobe *rp);
-int disable_jprobe(struct jprobe *jp);
+::
 
-Temporarily disables the specified *probe. You can enable it again by using
+       #include <linux/kprobes.h>
+       int disable_kprobe(struct kprobe *kp);
+       int disable_kretprobe(struct kretprobe *rp);
+       int disable_jprobe(struct jprobe *jp);
+
+Temporarily disables the specified ``*probe``. You can enable it again by using
 enable_*probe(). You must specify the probe which has been registered.
 
-4.8 enable_*probe
+enable_*probe
+-------------
+
+::
 
-#include <linux/kprobes.h>
-int enable_kprobe(struct kprobe *kp);
-int enable_kretprobe(struct kretprobe *rp);
-int enable_jprobe(struct jprobe *jp);
+       #include <linux/kprobes.h>
+       int enable_kprobe(struct kprobe *kp);
+       int enable_kretprobe(struct kretprobe *rp);
+       int enable_jprobe(struct jprobe *jp);
 
-Enables *probe which has been disabled by disable_*probe(). You must specify
+Enables ``*probe`` which has been disabled by disable_*probe(). You must specify
 the probe which has been registered.
 
-5. Kprobes Features and Limitations
+Kprobes Features and Limitations
+================================
 
 Kprobes allows multiple probes at the same address.  Currently,
 however, there cannot be multiple jprobes on the same function at
@@ -538,7 +608,7 @@ are discussed in this section.
 
 The register_*probe functions will return -EINVAL if you attempt
 to install a probe in the code that implements Kprobes (mostly
-kernel/kprobes.c and arch/*/kernel/kprobes.c, but also functions such
+kernel/kprobes.c and ``arch/*/kernel/kprobes.c``, but also functions such
 as do_page_fault and notifier_call_chain).
 
 If you install a probe in an inline-able function, Kprobes makes
@@ -602,19 +672,21 @@ explain it, we introduce some terminology. Imagine a 3-instruction
 sequence consisting of a two 2-byte instructions and one 3-byte
 instruction.
 
-        IA
-         |
-[-2][-1][0][1][2][3][4][5][6][7]
-        [ins1][ins2][  ins3 ]
-       [<-     DCR       ->]
-          [<- JTPR ->]
+::
 
-ins1: 1st Instruction
-ins2: 2nd Instruction
-ins3: 3rd Instruction
-IA:  Insertion Address
-JTPR: Jump Target Prohibition Region
-DCR: Detoured Code Region
+               IA
+               |
+       [-2][-1][0][1][2][3][4][5][6][7]
+               [ins1][ins2][  ins3 ]
+               [<-     DCR       ->]
+               [<- JTPR ->]
+
+       ins1: 1st Instruction
+       ins2: 2nd Instruction
+       ins3: 3rd Instruction
+       IA:  Insertion Address
+       JTPR: Jump Target Prohibition Region
+       DCR: Detoured Code Region
 
 The instructions in DCR are copied to the out-of-line buffer
 of the kprobe, because the bytes in DCR are replaced by
@@ -628,7 +700,8 @@ d) DCR must not straddle the border between functions.
 Anyway, these limitations are checked by the in-kernel instruction
 decoder, so you don't need to worry about that.
 
-6. Probe Overhead
+Probe Overhead
+==============
 
 On a typical CPU in use in 2005, a kprobe hit takes 0.5 to 1.0
 microseconds to process.  Specifically, a benchmark that hits the same
@@ -638,70 +711,80 @@ return-probe hit typically takes 50-75% longer than a kprobe hit.
 When you have a return probe set on a function, adding a kprobe at
 the entry to that function adds essentially no overhead.
 
-Here are sample overhead figures (in usec) for different architectures.
-k = kprobe; j = jprobe; r = return probe; kr = kprobe + return probe
-on same function; jr = jprobe + return probe on same function
+Here are sample overhead figures (in usec) for different architectures::
+
+  k = kprobe; j = jprobe; r = return probe; kr = kprobe + return probe
+  on same function; jr = jprobe + return probe on same function::
 
-i386: Intel Pentium M, 1495 MHz, 2957.31 bogomips
-k = 0.57 usec; j = 1.00; r = 0.92; kr = 0.99; jr = 1.40
+  i386: Intel Pentium M, 1495 MHz, 2957.31 bogomips
+  k = 0.57 usec; j = 1.00; r = 0.92; kr = 0.99; jr = 1.40
 
-x86_64: AMD Opteron 246, 1994 MHz, 3971.48 bogomips
-k = 0.49 usec; j = 0.76; r = 0.80; kr = 0.82; jr = 1.07
+  x86_64: AMD Opteron 246, 1994 MHz, 3971.48 bogomips
+  k = 0.49 usec; j = 0.76; r = 0.80; kr = 0.82; jr = 1.07
 
-ppc64: POWER5 (gr), 1656 MHz (SMT disabled, 1 virtual CPU per physical CPU)
-k = 0.77 usec; j = 1.31; r = 1.26; kr = 1.45; jr = 1.99
+  ppc64: POWER5 (gr), 1656 MHz (SMT disabled, 1 virtual CPU per physical CPU)
+  k = 0.77 usec; j = 1.31; r = 1.26; kr = 1.45; jr = 1.99
 
-6.1 Optimized Probe Overhead
+Optimized Probe Overhead
+------------------------
 
 Typically, an optimized kprobe hit takes 0.07 to 0.1 microseconds to
-process. Here are sample overhead figures (in usec) for x86 architectures.
-k = unoptimized kprobe, b = boosted (single-step skipped), o = optimized kprobe,
-r = unoptimized kretprobe, rb = boosted kretprobe, ro = optimized kretprobe.
+process. Here are sample overhead figures (in usec) for x86 architectures::
 
-i386: Intel(R) Xeon(R) E5410, 2.33GHz, 4656.90 bogomips
-k = 0.80 usec; b = 0.33; o = 0.05; r = 1.10; rb = 0.61; ro = 0.33
+  k = unoptimized kprobe, b = boosted (single-step skipped), o = optimized kprobe,
+  r = unoptimized kretprobe, rb = boosted kretprobe, ro = optimized kretprobe.
 
-x86-64: Intel(R) Xeon(R) E5410, 2.33GHz, 4656.90 bogomips
-k = 0.99 usec; b = 0.43; o = 0.06; r = 1.24; rb = 0.68; ro = 0.30
+  i386: Intel(R) Xeon(R) E5410, 2.33GHz, 4656.90 bogomips
+  k = 0.80 usec; b = 0.33; o = 0.05; r = 1.10; rb = 0.61; ro = 0.33
 
-7. TODO
+  x86-64: Intel(R) Xeon(R) E5410, 2.33GHz, 4656.90 bogomips
+  k = 0.99 usec; b = 0.43; o = 0.06; r = 1.24; rb = 0.68; ro = 0.30
+
+TODO
+====
 
 a. SystemTap (http://sourceware.org/systemtap): Provides a simplified
-programming interface for probe-based instrumentation.  Try it out.
+   programming interface for probe-based instrumentation.  Try it out.
 b. Kernel return probes for sparc64.
 c. Support for other architectures.
 d. User-space probes.
 e. Watchpoint probes (which fire on data references).
 
-8. Kprobes Example
+Kprobes Example
+===============
 
 See samples/kprobes/kprobe_example.c
 
-9. Jprobes Example
+Jprobes Example
+===============
 
 See samples/kprobes/jprobe_example.c
 
-10. Kretprobes Example
+Kretprobes Example
+==================
 
 See samples/kprobes/kretprobe_example.c
 
 For additional information on Kprobes, refer to the following URLs:
-http://www-106.ibm.com/developerworks/library/l-kprobes.html?ca=dgr-lnxw42Kprobe
-http://www.redhat.com/magazine/005mar05/features/kprobes/
-http://www-users.cs.umn.edu/~boutcher/kprobes/
-http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115)
+
+- http://www-106.ibm.com/developerworks/library/l-kprobes.html?ca=dgr-lnxw42Kprobe
+- http://www.redhat.com/magazine/005mar05/features/kprobes/
+- http://www-users.cs.umn.edu/~boutcher/kprobes/
+- http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115)
 
 
-Appendix A: The kprobes debugfs interface
+The kprobes debugfs interface
+=============================
+
 
 With recent kernels (> 2.6.20) the list of registered kprobes is visible
 under the /sys/kernel/debug/kprobes/ directory (assuming debugfs is mounted at //sys/kernel/debug).
 
-/sys/kernel/debug/kprobes/list: Lists all registered probes on the system
+/sys/kernel/debug/kprobes/list: Lists all registered probes on the system::
 
-c015d71a  k  vfs_read+0x0
-c011a316  j  do_fork+0x0
-c03dedc5  r  tcp_v4_rcv+0x0
+       c015d71a  k  vfs_read+0x0
+       c011a316  j  do_fork+0x0
+       c03dedc5  r  tcp_v4_rcv+0x0
 
 The first column provides the kernel address where the probe is inserted.
 The second column identifies the type of probe (k - kprobe, r - kretprobe
@@ -725,17 +808,19 @@ change each probe's disabling state. This means that disabled kprobes (marked
 [DISABLED]) will be not enabled if you turn ON all kprobes by this knob.
 
 
-Appendix B: The kprobes sysctl interface
+The kprobes sysctl interface
+============================
 
 /proc/sys/debug/kprobes-optimization: Turn kprobes optimization ON/OFF.
 
 When CONFIG_OPTPROBES=y, this sysctl interface appears and it provides
 a knob to globally and forcibly turn jump optimization (see section
-1.4) ON or OFF. By default, jump optimization is allowed (ON).
-If you echo "0" to this file or set "debug.kprobes_optimization" to
-0 via sysctl, all optimized probes will be unoptimized, and any new
-probes registered after that will not be optimized.  Note that this
-knob *changes* the optimized state. This means that optimized probes
-(marked [OPTIMIZED]) will be unoptimized ([OPTIMIZED] tag will be
+:ref:`kprobes_jump_optimization`) ON or OFF. By default, jump optimization
+is allowed (ON). If you echo "0" to this file or set
+"debug.kprobes_optimization" to 0 via sysctl, all optimized probes will be
+unoptimized, and any new probes registered after that will not be optimized.
+
+Note that this knob *changes* the optimized state. This means that optimized
+probes (marked [OPTIMIZED]) will be unoptimized ([OPTIMIZED] tag will be
 removed). If the knob is turned on, they will be optimized again.
 
index d26a27c..3af3841 100644 (file)
@@ -1,24 +1,42 @@
+===================================================
+Adding reference counters (krefs) to kernel objects
+===================================================
+
+:Author: Corey Minyard <minyard@acm.org>
+:Author: Thomas Hellstrom <thellstrom@vmware.com>
+
+A lot of this was lifted from Greg Kroah-Hartman's 2004 OLS paper and
+presentation on krefs, which can be found at:
+
+  - http://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdf
+  - http://www.kroah.com/linux/talks/ols_2004_kref_talk/
+
+Introduction
+============
 
 krefs allow you to add reference counters to your objects.  If you
 have objects that are used in multiple places and passed around, and
 you don't have refcounts, your code is almost certainly broken.  If
 you want refcounts, krefs are the way to go.
 
-To use a kref, add one to your data structures like:
+To use a kref, add one to your data structures like::
 
-struct my_data
-{
+    struct my_data
+    {
        .
        .
        struct kref refcount;
        .
        .
-};
+    };
 
 The kref can occur anywhere within the data structure.
 
+Initialization
+==============
+
 You must initialize the kref after you allocate it.  To do this, call
-kref_init as so:
+kref_init as so::
 
      struct my_data *data;
 
@@ -29,18 +47,25 @@ kref_init as so:
 
 This sets the refcount in the kref to 1.
 
+Kref rules
+==========
+
 Once you have an initialized kref, you must follow the following
 rules:
 
 1) If you make a non-temporary copy of a pointer, especially if
    it can be passed to another thread of execution, you must
-   increment the refcount with kref_get() before passing it off:
+   increment the refcount with kref_get() before passing it off::
+
        kref_get(&data->refcount);
+
    If you already have a valid pointer to a kref-ed structure (the
    refcount cannot go to zero) you may do this without a lock.
 
-2) When you are done with a pointer, you must call kref_put():
+2) When you are done with a pointer, you must call kref_put()::
+
        kref_put(&data->refcount, data_release);
+
    If this is the last reference to the pointer, the release
    routine will be called.  If the code never tries to get
    a valid pointer to a kref-ed structure without already
@@ -53,25 +78,25 @@ rules:
    structure must remain valid during the kref_get().
 
 For example, if you allocate some data and then pass it to another
-thread to process:
+thread to process::
 
-void data_release(struct kref *ref)
-{
+    void data_release(struct kref *ref)
+    {
        struct my_data *data = container_of(ref, struct my_data, refcount);
        kfree(data);
-}
+    }
 
-void more_data_handling(void *cb_data)
-{
+    void more_data_handling(void *cb_data)
+    {
        struct my_data *data = cb_data;
        .
        . do stuff with data here
        .
        kref_put(&data->refcount, data_release);
-}
+    }
 
-int my_data_handler(void)
-{
+    int my_data_handler(void)
+    {
        int rv = 0;
        struct my_data *data;
        struct task_struct *task;
@@ -91,10 +116,10 @@ int my_data_handler(void)
        .
        . do stuff with data here
        .
- out:
   out:
        kref_put(&data->refcount, data_release);
        return rv;
-}
+    }
 
 This way, it doesn't matter what order the two threads handle the
 data, the kref_put() handles knowing when the data is not referenced
@@ -104,7 +129,7 @@ put needs no lock because nothing tries to get the data without
 already holding a pointer.
 
 Note that the "before" in rule 1 is very important.  You should never
-do something like:
+do something like::
 
        task = kthread_run(more_data_handling, data, "more_data_handling");
        if (task == ERR_PTR(-ENOMEM)) {
@@ -124,14 +149,14 @@ bad style.  Don't do it.
 There are some situations where you can optimize the gets and puts.
 For instance, if you are done with an object and enqueuing it for
 something else or passing it off to something else, there is no reason
-to do a get then a put:
+to do a get then a put::
 
        /* Silly extra get and put */
        kref_get(&obj->ref);
        enqueue(obj);
        kref_put(&obj->ref, obj_cleanup);
 
-Just do the enqueue.  A comment about this is always welcome:
+Just do the enqueue.  A comment about this is always welcome::
 
        enqueue(obj);
        /* We are done with obj, so we pass our refcount off
@@ -142,109 +167,99 @@ instance, you have a list of items that are each kref-ed, and you wish
 to get the first one.  You can't just pull the first item off the list
 and kref_get() it.  That violates rule 3 because you are not already
 holding a valid pointer.  You must add a mutex (or some other lock).
-For instance:
-
-static DEFINE_MUTEX(mutex);
-static LIST_HEAD(q);
-struct my_data
-{
-       struct kref      refcount;
-       struct list_head link;
-};
-
-static struct my_data *get_entry()
-{
-       struct my_data *entry = NULL;
-       mutex_lock(&mutex);
-       if (!list_empty(&q)) {
-               entry = container_of(q.next, struct my_data, link);
-               kref_get(&entry->refcount);
+For instance::
+
+       static DEFINE_MUTEX(mutex);
+       static LIST_HEAD(q);
+       struct my_data
+       {
+               struct kref      refcount;
+               struct list_head link;
+       };
+
+       static struct my_data *get_entry()
+       {
+               struct my_data *entry = NULL;
+               mutex_lock(&mutex);
+               if (!list_empty(&q)) {
+                       entry = container_of(q.next, struct my_data, link);
+                       kref_get(&entry->refcount);
+               }
+               mutex_unlock(&mutex);
+               return entry;
        }
-       mutex_unlock(&mutex);
-       return entry;
-}
 
-static void release_entry(struct kref *ref)
-{
-       struct my_data *entry = container_of(ref, struct my_data, refcount);
+       static void release_entry(struct kref *ref)
+       {
+               struct my_data *entry = container_of(ref, struct my_data, refcount);
 
-       list_del(&entry->link);
-       kfree(entry);
-}
+               list_del(&entry->link);
+               kfree(entry);
+       }
 
-static void put_entry(struct my_data *entry)
-{
-       mutex_lock(&mutex);
-       kref_put(&entry->refcount, release_entry);
-       mutex_unlock(&mutex);
-}
+       static void put_entry(struct my_data *entry)
+       {
+               mutex_lock(&mutex);
+               kref_put(&entry->refcount, release_entry);
+               mutex_unlock(&mutex);
+       }
 
 The kref_put() return value is useful if you do not want to hold the
 lock during the whole release operation.  Say you didn't want to call
 kfree() with the lock held in the example above (since it is kind of
-pointless to do so).  You could use kref_put() as follows:
+pointless to do so).  You could use kref_put() as follows::
 
-static void release_entry(struct kref *ref)
-{
-       /* All work is done after the return from kref_put(). */
-}
+       static void release_entry(struct kref *ref)
+       {
+               /* All work is done after the return from kref_put(). */
+       }
 
-static void put_entry(struct my_data *entry)
-{
-       mutex_lock(&mutex);
-       if (kref_put(&entry->refcount, release_entry)) {
-               list_del(&entry->link);
-               mutex_unlock(&mutex);
-               kfree(entry);
-       } else
-               mutex_unlock(&mutex);
-}
+       static void put_entry(struct my_data *entry)
+       {
+               mutex_lock(&mutex);
+               if (kref_put(&entry->refcount, release_entry)) {
+                       list_del(&entry->link);
+                       mutex_unlock(&mutex);
+                       kfree(entry);
+               } else
+                       mutex_unlock(&mutex);
+       }
 
 This is really more useful if you have to call other routines as part
 of the free operations that could take a long time or might claim the
 same lock.  Note that doing everything in the release routine is still
 preferred as it is a little neater.
 
-
-Corey Minyard <minyard@acm.org>
-
-A lot of this was lifted from Greg Kroah-Hartman's 2004 OLS paper and
-presentation on krefs, which can be found at:
-  http://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdf
-and:
-  http://www.kroah.com/linux/talks/ols_2004_kref_talk/
-
-
 The above example could also be optimized using kref_get_unless_zero() in
-the following way:
-
-static struct my_data *get_entry()
-{
-       struct my_data *entry = NULL;
-       mutex_lock(&mutex);
-       if (!list_empty(&q)) {
-               entry = container_of(q.next, struct my_data, link);
-               if (!kref_get_unless_zero(&entry->refcount))
-                       entry = NULL;
+the following way::
+
+       static struct my_data *get_entry()
+       {
+               struct my_data *entry = NULL;
+               mutex_lock(&mutex);
+               if (!list_empty(&q)) {
+                       entry = container_of(q.next, struct my_data, link);
+                       if (!kref_get_unless_zero(&entry->refcount))
+                               entry = NULL;
+               }
+               mutex_unlock(&mutex);
+               return entry;
        }
-       mutex_unlock(&mutex);
-       return entry;
-}
 
-static void release_entry(struct kref *ref)
-{
-       struct my_data *entry = container_of(ref, struct my_data, refcount);
+       static void release_entry(struct kref *ref)
+       {
+               struct my_data *entry = container_of(ref, struct my_data, refcount);
 
-       mutex_lock(&mutex);
-       list_del(&entry->link);
-       mutex_unlock(&mutex);
-       kfree(entry);
-}
+               mutex_lock(&mutex);
+               list_del(&entry->link);
+               mutex_unlock(&mutex);
+               kfree(entry);
+       }
 
-static void put_entry(struct my_data *entry)
-{
-       kref_put(&entry->refcount, release_entry);
-}
+       static void put_entry(struct my_data *entry)
+       {
+               kref_put(&entry->refcount, release_entry);
+       }
 
 Which is useful to remove the mutex lock around kref_put() in put_entry(), but
 it's important that kref_get_unless_zero is enclosed in the same critical
@@ -254,51 +269,51 @@ Note that it is illegal to use kref_get_unless_zero without checking its
 return value. If you are sure (by already having a valid pointer) that
 kref_get_unless_zero() will return true, then use kref_get() instead.
 
-The function kref_get_unless_zero also makes it possible to use rcu
-locking for lookups in the above example:
+Krefs and RCU
+=============
 
-struct my_data
-{
-       struct rcu_head rhead;
-       .
-       struct kref refcount;
-       .
-       .
-};
-
-static struct my_data *get_entry_rcu()
-{
-       struct my_data *entry = NULL;
-       rcu_read_lock();
-       if (!list_empty(&q)) {
-               entry = container_of(q.next, struct my_data, link);
-               if (!kref_get_unless_zero(&entry->refcount))
-                       entry = NULL;
+The function kref_get_unless_zero also makes it possible to use rcu
+locking for lookups in the above example::
+
+       struct my_data
+       {
+               struct rcu_head rhead;
+               .
+               struct kref refcount;
+               .
+               .
+       };
+
+       static struct my_data *get_entry_rcu()
+       {
+               struct my_data *entry = NULL;
+               rcu_read_lock();
+               if (!list_empty(&q)) {
+                       entry = container_of(q.next, struct my_data, link);
+                       if (!kref_get_unless_zero(&entry->refcount))
+                               entry = NULL;
+               }
+               rcu_read_unlock();
+               return entry;
        }
-       rcu_read_unlock();
-       return entry;
-}
 
-static void release_entry_rcu(struct kref *ref)
-{
-       struct my_data *entry = container_of(ref, struct my_data, refcount);
+       static void release_entry_rcu(struct kref *ref)
+       {
+               struct my_data *entry = container_of(ref, struct my_data, refcount);
 
-       mutex_lock(&mutex);
-       list_del_rcu(&entry->link);
-       mutex_unlock(&mutex);
-       kfree_rcu(entry, rhead);
-}
+               mutex_lock(&mutex);
+               list_del_rcu(&entry->link);
+               mutex_unlock(&mutex);
+               kfree_rcu(entry, rhead);
+       }
 
-static void put_entry(struct my_data *entry)
-{
-       kref_put(&entry->refcount, release_entry_rcu);
-}
+       static void put_entry(struct my_data *entry)
+       {
+               kref_put(&entry->refcount, release_entry_rcu);
+       }
 
 But note that the struct kref member needs to remain in valid memory for a
 rcu grace period after release_entry_rcu was called. That can be accomplished
 by using kfree_rcu(entry, rhead) as done above, or by calling synchronize_rcu()
 before using kfree, but note that synchronize_rcu() may sleep for a
 substantial amount of time.
-
-
-Thomas Hellstrom <thellstrom@vmware.com>
index 4f80edd..12c5713 100644 (file)
@@ -1,9 +1,9 @@
+==========================================
+LDM - Logical Disk Manager (Dynamic Disks)
+==========================================
 
-            LDM - Logical Disk Manager (Dynamic Disks)
-            ------------------------------------------
-
-Originally Written by FlatCap - Richard Russon <ldm@flatcap.org>.
-Last Updated by Anton Altaparmakov on 30 March 2007 for Windows Vista.
+:Author: Originally Written by FlatCap - Richard Russon <ldm@flatcap.org>.
+:Last Updated: Anton Altaparmakov on 30 March 2007 for Windows Vista.
 
 Overview
 --------
@@ -37,24 +37,36 @@ Example
 -------
 
 Below we have a 50MiB disk, divided into seven partitions.
-N.B.  The missing 1MiB at the end of the disk is where the LDM database is
-      stored.
-
-  Device | Offset Bytes  Sectors  MiB | Size   Bytes  Sectors  MiB
-  -------+----------------------------+---------------------------
-  hda    |            0        0    0 |     52428800   102400   50
-  hda1   |     51380224   100352   49 |      1048576     2048    1
-  hda2   |        16384       32    0 |      6979584    13632    6
-  hda3   |      6995968    13664    6 |     10485760    20480   10
-  hda4   |     17481728    34144   16 |      4194304     8192    4
-  hda5   |     21676032    42336   20 |      5242880    10240    5
-  hda6   |     26918912    52576   25 |     10485760    20480   10
-  hda7   |     37404672    73056   35 |     13959168    27264   13
+
+.. note::
+
+   The missing 1MiB at the end of the disk is where the LDM database is
+   stored.
+
++-------++--------------+---------+-----++--------------+---------+----+
+|Device || Offset Bytes | Sectors | MiB || Size   Bytes | Sectors | MiB|
++=======++==============+=========+=====++==============+=========+====+
+|hda    ||            0 |       0 |   0 ||     52428800 |  102400 |  50|
++-------++--------------+---------+-----++--------------+---------+----+
+|hda1   ||     51380224 |  100352 |  49 ||      1048576 |    2048 |   1|
++-------++--------------+---------+-----++--------------+---------+----+
+|hda2   ||        16384 |      32 |   0 ||      6979584 |   13632 |   6|
++-------++--------------+---------+-----++--------------+---------+----+
+|hda3   ||      6995968 |   13664 |   6 ||     10485760 |   20480 |  10|
++-------++--------------+---------+-----++--------------+---------+----+
+|hda4   ||     17481728 |   34144 |  16 ||      4194304 |    8192 |   4|
++-------++--------------+---------+-----++--------------+---------+----+
+|hda5   ||     21676032 |   42336 |  20 ||      5242880 |   10240 |   5|
++-------++--------------+---------+-----++--------------+---------+----+
+|hda6   ||     26918912 |   52576 |  25 ||     10485760 |   20480 |  10|
++-------++--------------+---------+-----++--------------+---------+----+
+|hda7   ||     37404672 |   73056 |  35 ||     13959168 |   27264 |  13|
++-------++--------------+---------+-----++--------------+---------+----+
 
 The LDM Database may not store the partitions in the order that they appear on
 disk, but the driver will sort them.
 
-When Linux boots, you will see something like:
+When Linux boots, you will see something like::
 
   hda: 102400 sectors w/32KiB Cache, CHS=50/64/32
   hda: [LDM] hda1 hda2 hda3 hda4 hda5 hda6 hda7
@@ -65,13 +77,13 @@ Compiling LDM Support
 
 To enable LDM, choose the following two options: 
 
-  "Advanced partition selection" CONFIG_PARTITION_ADVANCED
-  "Windows Logical Disk Manager (Dynamic Disk) support" CONFIG_LDM_PARTITION
+  "Advanced partition selection" CONFIG_PARTITION_ADVANCED
+  "Windows Logical Disk Manager (Dynamic Disk) support" CONFIG_LDM_PARTITION
 
 If you believe the driver isn't working as it should, you can enable the extra
 debugging code.  This will produce a LOT of output.  The option is:
 
-  "Windows LDM extra logging" CONFIG_LDM_DEBUG
+  "Windows LDM extra logging" CONFIG_LDM_DEBUG
 
 N.B. The partition code cannot be compiled as a module.
 
index c8b8378..290840c 100644 (file)
@@ -30,7 +30,8 @@ timeout is set through the confusingly named "kernel.panic" sysctl),
 to cause the system to reboot automatically after a specified amount
 of time.
 
-=== Implementation ===
+Implementation
+==============
 
 The soft and hard lockup detectors are built on top of the hrtimer and
 perf subsystems, respectively. A direct consequence of this is that,
index 285c54f..6fa6a93 100644 (file)
@@ -1,8 +1,9 @@
-
+===========================================================
 LZO stream format as understood by Linux's LZO decompressor
 ===========================================================
 
 Introduction
+============
 
   This is not a specification. No specification seems to be publicly available
   for the LZO stream format. This document describes what input format the LZO
@@ -14,12 +15,13 @@ Introduction
   for future bug reports.
 
 Description
+===========
 
   The stream is composed of a series of instructions, operands, and data. The
   instructions consist in a few bits representing an opcode, and bits forming
   the operands for the instruction, whose size and position depend on the
   opcode and on the number of literals copied by previous instruction. The
-  operands are used to indicate :
+  operands are used to indicate:
 
     - a distance when copying data from the dictionary (past output buffer)
     - a length (number of bytes to copy from dictionary)
@@ -38,7 +40,7 @@ Description
   of bits in the operand. If the number of bits isn't enough to represent the
   length, up to 255 may be added in increments by consuming more bytes with a
   rate of at most 255 per extra byte (thus the compression ratio cannot exceed
-  around 255:1). The variable length encoding using #bits is always the same :
+  around 255:1). The variable length encoding using #bits is always the same::
 
        length = byte & ((1 << #bits) - 1)
        if (!length) {
@@ -67,15 +69,19 @@ Description
   instruction may encode this distance (0001HLLL), it takes one LE16 operand
   for the distance, thus requiring 3 bytes.
 
-  IMPORTANT NOTE : in the code some length checks are missing because certain
-  instructions are called under the assumption that a certain number of bytes
-  follow because it has already been guaranteed before parsing the instructions.
-  They just have to "refill" this credit if they consume extra bytes. This is
-  an implementation design choice independent on the algorithm or encoding.
+  .. important::
+
+     In the code some length checks are missing because certain instructions
+     are called under the assumption that a certain number of bytes follow
+     because it has already been guaranteed before parsing the instructions.
+     They just have to "refill" this credit if they consume extra bytes. This
+     is an implementation design choice independent on the algorithm or
+     encoding.
 
 Byte sequences
+==============
 
-  First byte encoding :
+  First byte encoding::
 
       0..17   : follow regular instruction encoding, see below. It is worth
                 noting that codes 16 and 17 will represent a block copy from
@@ -91,7 +97,7 @@ Byte sequences
                 state = 4 [ don't copy extra literals ]
                 skip byte
 
-  Instruction encoding :
+  Instruction encoding::
 
       0 0 0 0 X X X X  (0..15)
         Depends on the number of literals copied by the last instruction.
@@ -156,6 +162,7 @@ Byte sequences
            distance = (H << 3) + D + 1
 
 Authors
+=======
 
   This document was written by Willy Tarreau <w@1wt.eu> on 2014/07/19 during an
   analysis of the decompression code available in Linux 3.16-rc5. The code is
index 7ed371c..0ed9500 100644 (file)
@@ -1,7 +1,10 @@
-               The Common Mailbox Framework
-               Jassi Brar <jaswinder.singh@linaro.org>
+============================
+The Common Mailbox Framework
+============================
 
- This document aims to help developers write client and controller
+:Author: Jassi Brar <jaswinder.singh@linaro.org>
+
+This document aims to help developers write client and controller
 drivers for the API. But before we start, let us note that the
 client (especially) and controller drivers are likely going to be
 very platform specific because the remote firmware is likely to be
@@ -13,14 +16,17 @@ similar copies of code written for each platform. Having said that,
 nothing prevents the remote f/w to also be Linux based and use the
 same api there. However none of that helps us locally because we only
 ever deal at client's protocol level.
- Some of the choices made during implementation are the result of this
+
+Some of the choices made during implementation are the result of this
 peculiarity of this "common" framework.
 
 
 
-       Part 1 - Controller Driver (See include/linux/mailbox_controller.h)
+Controller Driver (See include/linux/mailbox_controller.h)
+==========================================================
+
 
- Allocate mbox_controller and the array of mbox_chan.
+Allocate mbox_controller and the array of mbox_chan.
 Populate mbox_chan_ops, except peek_data() all are mandatory.
 The controller driver might know a message has been consumed
 by the remote by getting an IRQ or polling some hardware flag
@@ -30,91 +36,94 @@ the controller driver should set via 'txdone_irq' or 'txdone_poll'
 or neither.
 
 
-       Part 2 - Client Driver (See include/linux/mailbox_client.h)
+Client Driver (See include/linux/mailbox_client.h)
+==================================================
 
- The client might want to operate in blocking mode (synchronously
+
+The client might want to operate in blocking mode (synchronously
 send a message through before returning) or non-blocking/async mode (submit
 a message and a callback function to the API and return immediately).
 
-
-struct demo_client {
-       struct mbox_client cl;
-       struct mbox_chan *mbox;
-       struct completion c;
-       bool async;
-       /* ... */
-};
-
-/*
- * This is the handler for data received from remote. The behaviour is purely
- * dependent upon the protocol. This is just an example.
- */
-static void message_from_remote(struct mbox_client *cl, void *mssg)
-{
-       struct demo_client *dc = container_of(cl, struct demo_client, cl);
-       if (dc->async) {
-               if (is_an_ack(mssg)) {
-                       /* An ACK to our last sample sent */
-                       return; /* Or do something else here */
-               } else { /* A new message from remote */
-                       queue_req(mssg);
+::
+
+       struct demo_client {
+               struct mbox_client cl;
+               struct mbox_chan *mbox;
+               struct completion c;
+               bool async;
+               /* ... */
+       };
+
+       /*
+       * This is the handler for data received from remote. The behaviour is purely
+       * dependent upon the protocol. This is just an example.
+       */
+       static void message_from_remote(struct mbox_client *cl, void *mssg)
+       {
+               struct demo_client *dc = container_of(cl, struct demo_client, cl);
+               if (dc->async) {
+                       if (is_an_ack(mssg)) {
+                               /* An ACK to our last sample sent */
+                               return; /* Or do something else here */
+                       } else { /* A new message from remote */
+                               queue_req(mssg);
+                       }
+               } else {
+                       /* Remote f/w sends only ACK packets on this channel */
+                       return;
                }
-       } else {
-               /* Remote f/w sends only ACK packets on this channel */
-               return;
        }
-}
-
-static void sample_sent(struct mbox_client *cl, void *mssg, int r)
-{
-       struct demo_client *dc = container_of(cl, struct demo_client, cl);
-       complete(&dc->c);
-}
-
-static void client_demo(struct platform_device *pdev)
-{
-       struct demo_client *dc_sync, *dc_async;
-       /* The controller already knows async_pkt and sync_pkt */
-       struct async_pkt ap;
-       struct sync_pkt sp;
-
-       dc_sync = kzalloc(sizeof(*dc_sync), GFP_KERNEL);
-       dc_async = kzalloc(sizeof(*dc_async), GFP_KERNEL);
-
-       /* Populate non-blocking mode client */
-       dc_async->cl.dev = &pdev->dev;
-       dc_async->cl.rx_callback = message_from_remote;
-       dc_async->cl.tx_done = sample_sent;
-       dc_async->cl.tx_block = false;
-       dc_async->cl.tx_tout = 0; /* doesn't matter here */
-       dc_async->cl.knows_txdone = false; /* depending upon protocol */
-       dc_async->async = true;
-       init_completion(&dc_async->c);
-
-       /* Populate blocking mode client */
-       dc_sync->cl.dev = &pdev->dev;
-       dc_sync->cl.rx_callback = message_from_remote;
-       dc_sync->cl.tx_done = NULL; /* operate in blocking mode */
-       dc_sync->cl.tx_block = true;
-       dc_sync->cl.tx_tout = 500; /* by half a second */
-       dc_sync->cl.knows_txdone = false; /* depending upon protocol */
-       dc_sync->async = false;
-
-       /* ASync mailbox is listed second in 'mboxes' property */
-       dc_async->mbox = mbox_request_channel(&dc_async->cl, 1);
-       /* Populate data packet */
-       /* ap.xxx = 123; etc */
-       /* Send async message to remote */
-       mbox_send_message(dc_async->mbox, &ap);
-
-       /* Sync mailbox is listed first in 'mboxes' property */
-       dc_sync->mbox = mbox_request_channel(&dc_sync->cl, 0);
-       /* Populate data packet */
-       /* sp.abc = 123; etc */
-       /* Send message to remote in blocking mode */
-       mbox_send_message(dc_sync->mbox, &sp);
-       /* At this point 'sp' has been sent */
-
-       /* Now wait for async chan to be done */
-       wait_for_completion(&dc_async->c);
-}
+
+       static void sample_sent(struct mbox_client *cl, void *mssg, int r)
+       {
+               struct demo_client *dc = container_of(cl, struct demo_client, cl);
+               complete(&dc->c);
+       }
+
+       static void client_demo(struct platform_device *pdev)
+       {
+               struct demo_client *dc_sync, *dc_async;
+               /* The controller already knows async_pkt and sync_pkt */
+               struct async_pkt ap;
+               struct sync_pkt sp;
+
+               dc_sync = kzalloc(sizeof(*dc_sync), GFP_KERNEL);
+               dc_async = kzalloc(sizeof(*dc_async), GFP_KERNEL);
+
+               /* Populate non-blocking mode client */
+               dc_async->cl.dev = &pdev->dev;
+               dc_async->cl.rx_callback = message_from_remote;
+               dc_async->cl.tx_done = sample_sent;
+               dc_async->cl.tx_block = false;
+               dc_async->cl.tx_tout = 0; /* doesn't matter here */
+               dc_async->cl.knows_txdone = false; /* depending upon protocol */
+               dc_async->async = true;
+               init_completion(&dc_async->c);
+
+               /* Populate blocking mode client */
+               dc_sync->cl.dev = &pdev->dev;
+               dc_sync->cl.rx_callback = message_from_remote;
+               dc_sync->cl.tx_done = NULL; /* operate in blocking mode */
+               dc_sync->cl.tx_block = true;
+               dc_sync->cl.tx_tout = 500; /* by half a second */
+               dc_sync->cl.knows_txdone = false; /* depending upon protocol */
+               dc_sync->async = false;
+
+               /* ASync mailbox is listed second in 'mboxes' property */
+               dc_async->mbox = mbox_request_channel(&dc_async->cl, 1);
+               /* Populate data packet */
+               /* ap.xxx = 123; etc */
+               /* Send async message to remote */
+               mbox_send_message(dc_async->mbox, &ap);
+
+               /* Sync mailbox is listed first in 'mboxes' property */
+               dc_sync->mbox = mbox_request_channel(&dc_sync->cl, 0);
+               /* Populate data packet */
+               /* sp.abc = 123; etc */
+               /* Send message to remote in blocking mode */
+               mbox_send_message(dc_sync->mbox, &sp);
+               /* At this point 'sp' has been sent */
+
+               /* Now wait for async chan to be done */
+               wait_for_completion(&dc_async->c);
+       }
index c239a0c..c4ddfcd 100644 (file)
@@ -1876,8 +1876,8 @@ There are some more advanced barrier functions:
      This makes sure that the death mark on the object is perceived to be set
      *before* the reference counter is decremented.
 
-     See Documentation/atomic_ops.txt for more information.  See the "Atomic
-     operations" subsection for information on where to use these.
+     See Documentation/core-api/atomic_ops.rst for more information.  See the
+     "Atomic operations" subsection for information on where to use these.
 
 
  (*) lockless_dereference();
@@ -2584,7 +2584,7 @@ situations because on some CPUs the atomic instructions used imply full memory
 barriers, and so barrier instructions are superfluous in conjunction with them,
 and in such cases the special barrier primitives will be no-ops.
 
-See Documentation/atomic_ops.txt for more information.
+See Documentation/core-api/atomic_ops.rst for more information.
 
 
 ACCESSING DEVICES
index 5c628e1..7f49ebf 100644 (file)
@@ -2,43 +2,48 @@
 Memory Hotplug
 ==============
 
-Created:                                       Jul 28 2007
-Add description of notifier of memory hotplug  Oct 11 2007
+:Created:                                                      Jul 28 2007
+:Updated: Add description of notifier of memory hotplug:       Oct 11 2007
 
 This document is about memory hotplug including how-to-use and current status.
 Because Memory Hotplug is still under development, contents of this text will
 be changed often.
 
-1. Introduction
-  1.1 purpose of memory hotplug
-  1.2. Phases of memory hotplug
-  1.3. Unit of Memory online/offline operation
-2. Kernel Configuration
-3. sysfs files for memory hotplug
-4. Physical memory hot-add phase
-  4.1 Hardware(Firmware) Support
-  4.2 Notify memory hot-add event by hand
-5. Logical Memory hot-add phase
-  5.1. State of memory
-  5.2. How to online memory
-6. Logical memory remove
-  6.1 Memory offline and ZONE_MOVABLE
-  6.2. How to offline memory
-7. Physical memory remove
-8. Memory hotplug event notifier
-9. Future Work List
-
-Note(1): x86_64's has special implementation for memory hotplug.
-         This text does not describe it.
-Note(2): This text assumes that sysfs is mounted at /sys.
+.. CONTENTS
 
+  1. Introduction
+    1.1 purpose of memory hotplug
+    1.2. Phases of memory hotplug
+    1.3. Unit of Memory online/offline operation
+  2. Kernel Configuration
+  3. sysfs files for memory hotplug
+  4. Physical memory hot-add phase
+    4.1 Hardware(Firmware) Support
+    4.2 Notify memory hot-add event by hand
+  5. Logical Memory hot-add phase
+    5.1. State of memory
+    5.2. How to online memory
+  6. Logical memory remove
+    6.1 Memory offline and ZONE_MOVABLE
+    6.2. How to offline memory
+  7. Physical memory remove
+  8. Memory hotplug event notifier
+  9. Future Work List
 
----------------
-1. Introduction
----------------
 
-1.1 purpose of memory hotplug
-------------
+.. note::
+
+    (1) x86_64's has special implementation for memory hotplug.
+        This text does not describe it.
+    (2) This text assumes that sysfs is mounted at /sys.
+
+
+Introduction
+============
+
+purpose of memory hotplug
+-------------------------
+
 Memory Hotplug allows users to increase/decrease the amount of memory.
 Generally, there are two purposes.
 
@@ -53,9 +58,11 @@ hardware which supports memory power management.
 Linux memory hotplug is designed for both purpose.
 
 
-1.2. Phases of memory hotplug
----------------
-There are 2 phases in Memory Hotplug.
+Phases of memory hotplug
+------------------------
+
+There are 2 phases in Memory Hotplug:
+
   1) Physical Memory Hotplug phase
   2) Logical Memory Hotplug phase.
 
@@ -70,7 +77,7 @@ management tables, and makes sysfs files for new memory's operation.
 If firmware supports notification of connection of new memory to OS,
 this phase is triggered automatically. ACPI can notify this event. If not,
 "probe" operation by system administration is used instead.
-(see Section 4.).
+(see :ref:`memory_hotplug_physical_mem`).
 
 Logical Memory Hotplug phase is to change memory state into
 available/unavailable for users. Amount of memory from user's view is
@@ -83,11 +90,12 @@ Logical Memory Hotplug phase is triggered by write of sysfs file by system
 administrator. For the hot-add case, it must be executed after Physical Hotplug
 phase by hand.
 (However, if you writes udev's hotplug scripts for memory hotplug, these
- phases can be execute in seamless way.)
+phases can be execute in seamless way.)
+
 
+Unit of Memory online/offline operation
+---------------------------------------
 
-1.3. Unit of Memory online/offline operation
-------------
 Memory hotplug uses SPARSEMEM memory model which allows memory to be divided
 into chunks of the same size. These chunks are called "sections". The size of
 a memory section is architecture dependent. For example, power uses 16MiB, ia64
@@ -97,46 +105,50 @@ Memory sections are combined into chunks referred to as "memory blocks". The
 size of a memory block is architecture dependent and represents the logical
 unit upon which memory online/offline operations are to be performed. The
 default size of a memory block is the same as memory section size unless an
-architecture specifies otherwise. (see Section 3.)
+architecture specifies otherwise. (see :ref:`memory_hotplug_sysfs_files`.)
 
 To determine the size (in bytes) of a memory block please read this file:
 
 /sys/devices/system/memory/block_size_bytes
 
 
------------------------
-2. Kernel Configuration
------------------------
+Kernel Configuration
+====================
+
 To use memory hotplug feature, kernel must be compiled with following
 config options.
 
-- For all memory hotplug
-    Memory model -> Sparse Memory  (CONFIG_SPARSEMEM)
-    Allow for memory hot-add       (CONFIG_MEMORY_HOTPLUG)
+- For all memory hotplug:
+    Memory model -> Sparse Memory  (CONFIG_SPARSEMEM)
+    Allow for memory hot-add       (CONFIG_MEMORY_HOTPLUG)
 
-- To enable memory removal, the following are also necessary
-    Allow for memory hot remove    (CONFIG_MEMORY_HOTREMOVE)
-    Page Migration                 (CONFIG_MIGRATION)
+- To enable memory removal, the following are also necessary:
+    Allow for memory hot remove    (CONFIG_MEMORY_HOTREMOVE)
+    Page Migration                 (CONFIG_MIGRATION)
 
-- For ACPI memory hotplug, the following are also necessary
-    Memory hotplug (under ACPI Support menu) (CONFIG_ACPI_HOTPLUG_MEMORY)
-    This option can be kernel module.
+- For ACPI memory hotplug, the following are also necessary:
+    Memory hotplug (under ACPI Support menu) (CONFIG_ACPI_HOTPLUG_MEMORY)
+    This option can be kernel module.
 
 - As a related configuration, if your box has a feature of NUMA-node hotplug
   via ACPI, then this option is necessary too.
-    ACPI0004,PNP0A05 and PNP0A06 Container Driver (under ACPI Support menu)
-    (CONFIG_ACPI_CONTAINER).
-    This option can be kernel module too.
 
+    - ACPI0004,PNP0A05 and PNP0A06 Container Driver (under ACPI Support menu)
+      (CONFIG_ACPI_CONTAINER).
+
+     This option can be kernel module too.
+
+
+.. _memory_hotplug_sysfs_files:
+
+sysfs files for memory hotplug
+==============================
 
---------------------------------
-3 sysfs files for memory hotplug
---------------------------------
 All memory blocks have their device information in sysfs.  Each memory block
-is described under /sys/devices/system/memory as
+is described under /sys/devices/system/memory as:
 
-/sys/devices/system/memory/memoryXXX
-(XXX is the memory block id.)
+       /sys/devices/system/memory/memoryXXX
+       (XXX is the memory block id.)
 
 For the memory block covered by the sysfs directory.  It is expected that all
 memory sections in this range are present and no memory holes exist in the
@@ -145,43 +157,53 @@ the existence of one should not affect the hotplug capabilities of the memory
 block.
 
 For example, assume 1GiB memory block size. A device for a memory starting at
-0x100000000 is /sys/device/system/memory/memory4
-(0x100000000 / 1Gib = 4)
+0x100000000 is /sys/device/system/memory/memory4::
+
+       (0x100000000 / 1Gib = 4)
+
 This device covers address range [0x100000000 ... 0x140000000)
 
 Under each memory block, you can see 5 files:
 
-/sys/devices/system/memory/memoryXXX/phys_index
-/sys/devices/system/memory/memoryXXX/phys_device
-/sys/devices/system/memory/memoryXXX/state
-/sys/devices/system/memory/memoryXXX/removable
-/sys/devices/system/memory/memoryXXX/valid_zones
+- /sys/devices/system/memory/memoryXXX/phys_index
+- /sys/devices/system/memory/memoryXXX/phys_device
+- /sys/devices/system/memory/memoryXXX/state
+- /sys/devices/system/memory/memoryXXX/removable
+- /sys/devices/system/memory/memoryXXX/valid_zones
+
+=================== ============================================================
+``phys_index``      read-only and contains memory block id, same as XXX.
+``state``           read-write
+
+                    - at read:  contains online/offline state of memory.
+                    - at write: user can specify "online_kernel",
 
-'phys_index'      : read-only and contains memory block id, same as XXX.
-'state'           : read-write
-                    at read:  contains online/offline state of memory.
-                    at write: user can specify "online_kernel",
                     "online_movable", "online", "offline" command
                     which will be performed on all sections in the block.
-'phys_device'     : read-only: designed to show the name of physical memory
+``phys_device``     read-only: designed to show the name of physical memory
                     device.  This is not well implemented now.
-'removable'       : read-only: contains an integer value indicating
+``removable``       read-only: contains an integer value indicating
                     whether the memory block is removable or not
                     removable.  A value of 1 indicates that the memory
                     block is removable and a value of 0 indicates that
                     it is not removable. A memory block is removable only if
                     every section in the block is removable.
-'valid_zones'     : read-only: designed to show which zones this memory block
+``valid_zones``     read-only: designed to show which zones this memory block
                    can be onlined to.
-                   The first column shows it's default zone.
+
+                   The first column shows it`s default zone.
+
                    "memory6/valid_zones: Normal Movable" shows this memoryblock
                    can be onlined to ZONE_NORMAL by default and to ZONE_MOVABLE
                    by online_movable.
+
                    "memory7/valid_zones: Movable Normal" shows this memoryblock
                    can be onlined to ZONE_MOVABLE by default and to ZONE_NORMAL
                    by online_kernel.
+=================== ============================================================
+
+.. note::
 
-NOTE:
   These directories/files appear after physical memory hotplug phase.
 
 If CONFIG_NUMA is enabled the memoryXXX/ directories can also be accessed
@@ -193,13 +215,14 @@ For example:
 A backlink will also be created:
 /sys/devices/system/memory/memory9/node0 -> ../../node/node0
 
+.. _memory_hotplug_physical_mem:
+
+Physical memory hot-add phase
+=============================
 
---------------------------------
-4. Physical memory hot-add phase
---------------------------------
+Hardware(Firmware) Support
+--------------------------
 
-4.1 Hardware(Firmware) Support
-------------
 On x86_64/ia64 platform, memory hotplug by ACPI is supported.
 
 In general, the firmware (ACPI) which supports memory hotplug defines
@@ -209,7 +232,8 @@ script. This will be done automatically.
 
 But scripts for memory hotplug are not contained in generic udev package(now).
 You may have to write it by yourself or online/offline memory by hand.
-Please see "How to online memory", "How to offline memory" in this text.
+Please see :ref:`memory_hotplug_how_to_online_memory` and
+:ref:`memory_hotplug_how_to_offline_memory`.
 
 If firmware supports NUMA-node hotplug, and defines an object _HID "ACPI0004",
 "PNP0A05", or "PNP0A06", notification is asserted to it, and ACPI handler
@@ -217,8 +241,9 @@ calls hotplug code for all of objects which are defined in it.
 If memory device is found, memory hotplug code will be called.
 
 
-4.2 Notify memory hot-add event by hand
-------------
+Notify memory hot-add event by hand
+-----------------------------------
+
 On some architectures, the firmware may not notify the kernel of a memory
 hotplug event.  Therefore, the memory "probe" interface is supported to
 explicitly notify the kernel.  This interface depends on
@@ -229,45 +254,48 @@ notification.
 Probe interface is located at
 /sys/devices/system/memory/probe
 
-You can tell the physical address of new memory to the kernel by
+You can tell the physical address of new memory to the kernel by::
 
-% echo start_address_of_new_memory > /sys/devices/system/memory/probe
+       % echo start_address_of_new_memory > /sys/devices/system/memory/probe
 
 Then, [start_address_of_new_memory, start_address_of_new_memory +
 memory_block_size] memory range is hot-added. In this case, hotplug script is
 not called (in current implementation). You'll have to online memory by
-yourself.  Please see "How to online memory" in this text.
+yourself.  Please see :ref:`memory_hotplug_how_to_online_memory`.
 
 
-------------------------------
-5. Logical Memory hot-add phase
-------------------------------
+Logical Memory hot-add phase
+============================
 
-5.1. State of memory
-------------
-To see (online/offline) state of a memory block, read 'state' file.
+State of memory
+---------------
+
+To see (online/offline) state of a memory block, read 'state' file::
+
+       % cat /sys/device/system/memory/memoryXXX/state
 
-% cat /sys/device/system/memory/memoryXXX/state
 
+- If the memory block is online, you'll read "online".
+- If the memory block is offline, you'll read "offline".
 
-If the memory block is online, you'll read "online".
-If the memory block is offline, you'll read "offline".
 
+.. _memory_hotplug_how_to_online_memory:
+
+How to online memory
+--------------------
 
-5.2. How to online memory
-------------
 When the memory is hot-added, the kernel decides whether or not to "online"
-it according to the policy which can be read from "auto_online_blocks" file:
+it according to the policy which can be read from "auto_online_blocks" file::
 
-% cat /sys/devices/system/memory/auto_online_blocks
+       % cat /sys/devices/system/memory/auto_online_blocks
 
 The default depends on the CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE kernel config
 option. If it is disabled the default is "offline" which means the newly added
 memory is not in a ready-to-use state and you have to "online" the newly added
 memory blocks manually. Automatic onlining can be requested by writing "online"
-to "auto_online_blocks" file:
+to "auto_online_blocks" file::
 
-% echo online > /sys/devices/system/memory/auto_online_blocks
+       % echo online > /sys/devices/system/memory/auto_online_blocks
 
 This sets a global policy and impacts all memory blocks that will subsequently
 be hotplugged. Currently offline blocks keep their state. It is possible, under
@@ -277,24 +305,26 @@ online. User space tools can check their "state" files
 
 If the automatic onlining wasn't requested, failed, or some memory block was
 offlined it is possible to change the individual block's state by writing to the
-"state" file:
+"state" file::
 
-% echo online > /sys/devices/system/memory/memoryXXX/state
+       % echo online > /sys/devices/system/memory/memoryXXX/state
 
 This onlining will not change the ZONE type of the target memory block,
 If the memory block doesn't belong to any zone an appropriate kernel zone
 (usually ZONE_NORMAL) will be used unless movable_node kernel command line
 option is specified when ZONE_MOVABLE will be used.
 
-You can explicitly request to associate it with ZONE_MOVABLE by
+You can explicitly request to associate it with ZONE_MOVABLE by::
+
+       % echo online_movable > /sys/devices/system/memory/memoryXXX/state
 
-% echo online_movable > /sys/devices/system/memory/memoryXXX/state
-(NOTE: current limit: this memory block must be adjacent to ZONE_MOVABLE)
+.. note:: current limit: this memory block must be adjacent to ZONE_MOVABLE
 
-Or you can explicitly request a kernel zone (usually ZONE_NORMAL) by:
+Or you can explicitly request a kernel zone (usually ZONE_NORMAL) by::
 
-% echo online_kernel > /sys/devices/system/memory/memoryXXX/state
-(NOTE: current limit: this memory block must be adjacent to ZONE_NORMAL)
+       % echo online_kernel > /sys/devices/system/memory/memoryXXX/state
+
+.. note:: current limit: this memory block must be adjacent to ZONE_NORMAL
 
 An explicit zone onlining can fail (e.g. when the range is already within
 and existing and incompatible zone already).
@@ -306,12 +336,12 @@ This may be changed in future.
 
 
 
-------------------------
-6. Logical memory remove
-------------------------
+Logical memory remove
+=====================
+
+Memory offline and ZONE_MOVABLE
+-------------------------------
 
-6.1 Memory offline and ZONE_MOVABLE
-------------
 Memory offlining is more complicated than memory online. Because memory offline
 has to make the whole memory block be unused, memory offline can fail if
 the memory block includes memory which cannot be freed.
@@ -336,24 +366,27 @@ Assume the system has "TOTAL" amount of memory at boot time, this boot option
 creates ZONE_MOVABLE as following.
 
 1) When kernelcore=YYYY boot option is used,
-  Size of memory not for movable pages (not for offline) is YYYY.
-  Size of memory for movable pages (for offline) is TOTAL-YYYY.
+   Size of memory not for movable pages (not for offline) is YYYY.
+   Size of memory for movable pages (for offline) is TOTAL-YYYY.
 
 2) When movablecore=ZZZZ boot option is used,
-  Size of memory not for movable pages (not for offline) is TOTAL - ZZZZ.
-  Size of memory for movable pages (for offline) is ZZZZ.
+   Size of memory not for movable pages (not for offline) is TOTAL - ZZZZ.
+   Size of memory for movable pages (for offline) is ZZZZ.
+
+.. note::
 
+   Unfortunately, there is no information to show which memory block belongs
+   to ZONE_MOVABLE. This is TBD.
 
-Note: Unfortunately, there is no information to show which memory block belongs
-to ZONE_MOVABLE. This is TBD.
+.. _memory_hotplug_how_to_offline_memory:
 
+How to offline memory
+---------------------
 
-6.2. How to offline memory
-------------
 You can offline a memory block by using the same sysfs interface that was used
-in memory onlining.
+in memory onlining::
 
-% echo offline > /sys/devices/system/memory/memoryXXX/state
+       % echo offline > /sys/devices/system/memory/memoryXXX/state
 
 If offline succeeds, the state of the memory block is changed to be "offline".
 If it fails, some error core (like -EBUSY) will be returned by the kernel.
@@ -367,22 +400,22 @@ able to offline it (or not). (For example, a page is referred to by some kernel
 internal call and released soon.)
 
 Consideration:
-Memory hotplug's design direction is to make the possibility of memory offlining
-higher and to guarantee unplugging memory under any situation. But it needs
-more work. Returning -EBUSY under some situation may be good because the user
-can decide to retry more or not by himself. Currently, memory offlining code
-does some amount of retry with 120 seconds timeout.
+  Memory hotplug's design direction is to make the possibility of memory
+  offlining higher and to guarantee unplugging memory under any situation. But
+  it needs more work. Returning -EBUSY under some situation may be good because
+  the user can decide to retry more or not by himself. Currently, memory
+  offlining code does some amount of retry with 120 seconds timeout.
+
+Physical memory remove
+======================
 
--------------------------
-7. Physical memory remove
--------------------------
 Need more implementation yet....
  - Notification completion of remove works by OS to firmware.
  - Guard from remove if not yet.
 
---------------------------------
-8. Memory hotplug event notifier
---------------------------------
+Memory hotplug event notifier
+=============================
+
 Hotplugging events are sent to a notification queue.
 
 There are six types of notification defined in include/linux/memory.h:
@@ -412,14 +445,14 @@ MEM_CANCEL_OFFLINE
 MEM_OFFLINE
   Generated after offlining memory is complete.
 
-A callback routine can be registered by calling
+A callback routine can be registered by calling::
 
   hotplug_memory_notifier(callback_func, priority)
 
 Callback functions with higher values of priority are called before callback
 functions with lower values.
 
-A callback function must have the following prototype:
+A callback function must have the following prototype::
 
   int callback_func(
     struct notifier_block *self, unsigned long action, void *arg);
@@ -427,27 +460,28 @@ A callback function must have the following prototype:
 The first argument of the callback function (self) is a pointer to the block
 of the notifier chain that points to the callback function itself.
 The second argument (action) is one of the event types described above.
-The third argument (arg) passes a pointer of struct memory_notify.
-
-struct memory_notify {
-       unsigned long start_pfn;
-       unsigned long nr_pages;
-       int status_change_nid_normal;
-       int status_change_nid_high;
-       int status_change_nid;
-}
-
-start_pfn is start_pfn of online/offline memory.
-nr_pages is # of pages of online/offline memory.
-status_change_nid_normal is set node id when N_NORMAL_MEMORY of nodemask
-is (will be) set/clear, if this is -1, then nodemask status is not changed.
-status_change_nid_high is set node id when N_HIGH_MEMORY of nodemask
-is (will be) set/clear, if this is -1, then nodemask status is not changed.
-status_change_nid is set node id when N_MEMORY of nodemask is (will be)
-set/clear. It means a new(memoryless) node gets new memory by online and a
-node loses all memory. If this is -1, then nodemask status is not changed.
-If status_changed_nid* >= 0, callback should create/discard structures for the
-node if necessary.
+The third argument (arg) passes a pointer of struct memory_notify::
+
+       struct memory_notify {
+               unsigned long start_pfn;
+               unsigned long nr_pages;
+               int status_change_nid_normal;
+               int status_change_nid_high;
+               int status_change_nid;
+       }
+
+- start_pfn is start_pfn of online/offline memory.
+- nr_pages is # of pages of online/offline memory.
+- status_change_nid_normal is set node id when N_NORMAL_MEMORY of nodemask
+  is (will be) set/clear, if this is -1, then nodemask status is not changed.
+- status_change_nid_high is set node id when N_HIGH_MEMORY of nodemask
+  is (will be) set/clear, if this is -1, then nodemask status is not changed.
+- status_change_nid is set node id when N_MEMORY of nodemask is (will be)
+  set/clear. It means a new(memoryless) node gets new memory by online and a
+  node loses all memory. If this is -1, then nodemask status is not changed.
+
+  If status_changed_nid* >= 0, callback should create/discard structures for the
+  node if necessary.
 
 The callback routine shall return one of the values
 NOTIFY_DONE, NOTIFY_OK, NOTIFY_BAD, NOTIFY_STOP
@@ -461,9 +495,9 @@ further processing of the notification queue.
 
 NOTIFY_STOP stops further processing of the notification queue.
 
---------------
-9. Future Work
---------------
+Future Work
+===========
+
   - allowing memory hot-add to ZONE_MOVABLE. maybe we need some switch like
     sysctl or new control file.
   - showing memory block and physical device relationship.
@@ -471,4 +505,3 @@ NOTIFY_STOP stops further processing of the notification queue.
   - support HugeTLB page migration and offlining.
   - memmap removing at memory offline.
   - physical remove memory.
-
index 30ded73..1b1f048 100644 (file)
-                               MEN Chameleon Bus
-                               =================
-
-Table of Contents
 =================
-1 Introduction
-    1.1 Scope of this Document
-    1.2 Limitations of the current implementation
-2 Architecture
-    2.1 MEN Chameleon Bus
-    2.2 Carrier Devices
-    2.3 Parser
-3 Resource handling
-    3.1 Memory Resources
-    3.2 IRQs
-4 Writing an MCB driver
-    4.1 The driver structure
-    4.2 Probing and attaching
-    4.3 Initializing the driver
-
-
-1 Introduction
-===============
-  This document describes the architecture and implementation of the MEN
-  Chameleon Bus (called MCB throughout this document).
-
-1.1 Scope of this Document
----------------------------
-  This document is intended to be a short overview of the current
-  implementation and does by no means describe the complete possibilities of MCB
-  based devices.
-
-1.2 Limitations of the current implementation
-----------------------------------------------
-  The current implementation is limited to PCI and PCIe based carrier devices
-  that only use a single memory resource and share the PCI legacy IRQ.  Not
-  implemented are:
-  - Multi-resource MCB devices like the VME Controller or M-Module carrier.
-  - MCB devices that need another MCB device, like SRAM for a DMA Controller's
-    buffer descriptors or a video controller's video memory.
-  - A per-carrier IRQ domain for carrier devices that have one (or more) IRQs
-    per MCB device like PCIe based carriers with MSI or MSI-X support.
-
-2 Architecture
-===============
-  MCB is divided into 3 functional blocks:
-  - The MEN Chameleon Bus itself,
-  - drivers for MCB Carrier Devices and
-  - the parser for the Chameleon table.
-
-2.1 MEN Chameleon Bus
+MEN Chameleon Bus
+=================
+
+.. Table of Contents
+   =================
+   1 Introduction
+       1.1 Scope of this Document
+       1.2 Limitations of the current implementation
+   2 Architecture
+       2.1 MEN Chameleon Bus
+       2.2 Carrier Devices
+       2.3 Parser
+   3 Resource handling
+       3.1 Memory Resources
+       3.2 IRQs
+   4 Writing an MCB driver
+       4.1 The driver structure
+       4.2 Probing and attaching
+       4.3 Initializing the driver
+
+
+Introduction
+============
+
+This document describes the architecture and implementation of the MEN
+Chameleon Bus (called MCB throughout this document).
+
+Scope of this Document
 ----------------------
-   The MEN Chameleon Bus is an artificial bus system that attaches to a so
-   called Chameleon FPGA device found on some hardware produced my MEN Mikro
-   Elektronik GmbH. These devices are multi-function devices implemented in a
-   single FPGA and usually attached via some sort of PCI or PCIe link. Each
-   FPGA contains a header section describing the content of the FPGA. The
-   header lists the device id, PCI BAR, offset from the beginning of the PCI
-   BAR, size in the FPGA, interrupt number and some other properties currently
-   not handled by the MCB implementation.
-
-2.2 Carrier Devices
+
+This document is intended to be a short overview of the current
+implementation and does by no means describe the complete possibilities of MCB
+based devices.
+
+Limitations of the current implementation
+-----------------------------------------
+
+The current implementation is limited to PCI and PCIe based carrier devices
+that only use a single memory resource and share the PCI legacy IRQ.  Not
+implemented are:
+
+- Multi-resource MCB devices like the VME Controller or M-Module carrier.
+- MCB devices that need another MCB device, like SRAM for a DMA Controller's
+  buffer descriptors or a video controller's video memory.
+- A per-carrier IRQ domain for carrier devices that have one (or more) IRQs
+  per MCB device like PCIe based carriers with MSI or MSI-X support.
+
+Architecture
+============
+
+MCB is divided into 3 functional blocks:
+
+- The MEN Chameleon Bus itself,
+- drivers for MCB Carrier Devices and
+- the parser for the Chameleon table.
+
+MEN Chameleon Bus
+-----------------
+
+The MEN Chameleon Bus is an artificial bus system that attaches to a so
+called Chameleon FPGA device found on some hardware produced my MEN Mikro
+Elektronik GmbH. These devices are multi-function devices implemented in a
+single FPGA and usually attached via some sort of PCI or PCIe link. Each
+FPGA contains a header section describing the content of the FPGA. The
+header lists the device id, PCI BAR, offset from the beginning of the PCI
+BAR, size in the FPGA, interrupt number and some other properties currently
+not handled by the MCB implementation.
+
+Carrier Devices
+---------------
+
+A carrier device is just an abstraction for the real world physical bus the
+Chameleon FPGA is attached to. Some IP Core drivers may need to interact with
+properties of the carrier device (like querying the IRQ number of a PCI
+device). To provide abstraction from the real hardware bus, an MCB carrier
+device provides callback methods to translate the driver's MCB function calls
+to hardware related function calls. For example a carrier device may
+implement the get_irq() method which can be translated into a hardware bus
+query for the IRQ number the device should use.
+
+Parser
+------
+
+The parser reads the first 512 bytes of a Chameleon device and parses the
+Chameleon table. Currently the parser only supports the Chameleon v2 variant
+of the Chameleon table but can easily be adopted to support an older or
+possible future variant. While parsing the table's entries new MCB devices
+are allocated and their resources are assigned according to the resource
+assignment in the Chameleon table. After resource assignment is finished, the
+MCB devices are registered at the MCB and thus at the driver core of the
+Linux kernel.
+
+Resource handling
+=================
+
+The current implementation assigns exactly one memory and one IRQ resource
+per MCB device. But this is likely going to change in the future.
+
+Memory Resources
+----------------
+
+Each MCB device has exactly one memory resource, which can be requested from
+the MCB bus. This memory resource is the physical address of the MCB device
+inside the carrier and is intended to be passed to ioremap() and friends. It
+is already requested from the kernel by calling request_mem_region().
+
+IRQs
+----
+
+Each MCB device has exactly one IRQ resource, which can be requested from the
+MCB bus. If a carrier device driver implements the ->get_irq() callback
+method, the IRQ number assigned by the carrier device will be returned,
+otherwise the IRQ number inside the Chameleon table will be returned. This
+number is suitable to be passed to request_irq().
+
+Writing an MCB driver
+=====================
+
+The driver structure
 --------------------
-   A carrier device is just an abstraction for the real world physical bus the
-   Chameleon FPGA is attached to. Some IP Core drivers may need to interact with
-   properties of the carrier device (like querying the IRQ number of a PCI
-   device). To provide abstraction from the real hardware bus, an MCB carrier
-   device provides callback methods to translate the driver's MCB function calls
-   to hardware related function calls. For example a carrier device may
-   implement the get_irq() method which can be translated into a hardware bus
-   query for the IRQ number the device should use.
-
-2.3 Parser
------------
-   The parser reads the first 512 bytes of a Chameleon device and parses the
-   Chameleon table. Currently the parser only supports the Chameleon v2 variant
-   of the Chameleon table but can easily be adopted to support an older or
-   possible future variant. While parsing the table's entries new MCB devices
-   are allocated and their resources are assigned according to the resource
-   assignment in the Chameleon table. After resource assignment is finished, the
-   MCB devices are registered at the MCB and thus at the driver core of the
-   Linux kernel.
-
-3 Resource handling
-====================
-  The current implementation assigns exactly one memory and one IRQ resource
-  per MCB device. But this is likely going to change in the future.
-
-3.1 Memory Resources
+
+Each MCB driver has a structure to identify the device driver as well as
+device ids which identify the IP Core inside the FPGA. The driver structure
+also contains callback methods which get executed on driver probe and
+removal from the system::
+
+       static const struct mcb_device_id foo_ids[] = {
+               { .device = 0x123 },
+               { }
+       };
+       MODULE_DEVICE_TABLE(mcb, foo_ids);
+
+       static struct mcb_driver foo_driver = {
+       driver = {
+               .name = "foo-bar",
+               .owner = THIS_MODULE,
+       },
+               .probe = foo_probe,
+               .remove = foo_remove,
+               .id_table = foo_ids,
+       };
+
+Probing and attaching
 ---------------------
-   Each MCB device has exactly one memory resource, which can be requested from
-   the MCB bus. This memory resource is the physical address of the MCB device
-   inside the carrier and is intended to be passed to ioremap() and friends. It
-   is already requested from the kernel by calling request_mem_region().
-
-3.2 IRQs
----------
-   Each MCB device has exactly one IRQ resource, which can be requested from the
-   MCB bus. If a carrier device driver implements the ->get_irq() callback
-   method, the IRQ number assigned by the carrier device will be returned,
-   otherwise the IRQ number inside the Chameleon table will be returned. This
-   number is suitable to be passed to request_irq().
-
-4 Writing an MCB driver
-=======================
-
-4.1 The driver structure
--------------------------
-    Each MCB driver has a structure to identify the device driver as well as
-    device ids which identify the IP Core inside the FPGA. The driver structure
-    also contains callback methods which get executed on driver probe and
-    removal from the system.
-
-
-  static const struct mcb_device_id foo_ids[] = {
-          { .device = 0x123 },
-          { }
-  };
-  MODULE_DEVICE_TABLE(mcb, foo_ids);
-
-  static struct mcb_driver foo_driver = {
-          driver = {
-                  .name = "foo-bar",
-                  .owner = THIS_MODULE,
-          },
-          .probe = foo_probe,
-          .remove = foo_remove,
-          .id_table = foo_ids,
-  };
-
-4.2 Probing and attaching
---------------------------
-   When a driver is loaded and the MCB devices it services are found, the MCB
-   core will call the driver's probe callback method. When the driver is removed
-   from the system, the MCB core will call the driver's remove callback method.
-
-
-  static init foo_probe(struct mcb_device *mdev, const struct mcb_device_id *id);
-  static void foo_remove(struct mcb_device *mdev);
-
-4.3 Initializing the driver
-----------------------------
-   When the kernel is booted or your foo driver module is inserted, you have to
-   perform driver initialization. Usually it is enough to register your driver
-   module at the MCB core.
-
-
-  static int __init foo_init(void)
-  {
-          return mcb_register_driver(&foo_driver);
-  }
-  module_init(foo_init);
-
-  static void __exit foo_exit(void)
-  {
-          mcb_unregister_driver(&foo_driver);
-  }
-  module_exit(foo_exit);
-
-   The module_mcb_driver() macro can be used to reduce the above code.
-
-
-  module_mcb_driver(foo_driver);
+
+When a driver is loaded and the MCB devices it services are found, the MCB
+core will call the driver's probe callback method. When the driver is removed
+from the system, the MCB core will call the driver's remove callback method::
+
+       static init foo_probe(struct mcb_device *mdev, const struct mcb_device_id *id);
+       static void foo_remove(struct mcb_device *mdev);
+
+Initializing the driver
+-----------------------
+
+When the kernel is booted or your foo driver module is inserted, you have to
+perform driver initialization. Usually it is enough to register your driver
+module at the MCB core::
+
+       static int __init foo_init(void)
+       {
+               return mcb_register_driver(&foo_driver);
+       }
+       module_init(foo_init);
+
+       static void __exit foo_exit(void)
+       {
+               mcb_unregister_driver(&foo_driver);
+       }
+       module_exit(foo_exit);
+
+The module_mcb_driver() macro can be used to reduce the above code::
+
+       module_mcb_driver(foo_driver);
index f485d55..84c9b8c 100644 (file)
@@ -353,12 +353,7 @@ tcp_l3mdev_accept - BOOLEAN
        compiled with CONFIG_NET_L3_MASTER_DEV.
 
 tcp_low_latency - BOOLEAN
-       If set, the TCP stack makes decisions that prefer lower
-       latency as opposed to higher throughput.  By default, this
-       option is not set meaning that higher throughput is preferred.
-       An example of an application where this default should be
-       changed would be a Beowulf compute cluster.
-       Default: 0
+       This is a legacy option, it has no effect anymore.
 
 tcp_max_orphans - INTEGER
        Maximal number of TCP sockets not attached to any user file handle,
index a0bf573..fe01302 100644 (file)
-Stream Parser
--------------
+Stream Parser (strparser)
+
+Introduction
+============
 
 The stream parser (strparser) is a utility that parses messages of an
-application layer protocol running over a TCP connection. The stream
+application layer protocol running over a data stream. The stream
 parser works in conjunction with an upper layer in the kernel to provide
 kernel support for application layer messages. For instance, Kernel
 Connection Multiplexor (KCM) uses the Stream Parser to parse messages
 using a BPF program.
 
+The strparser works in one of two modes: receive callback or general
+mode.
+
+In receive callback mode, the strparser is called from the data_ready
+callback of a TCP socket. Messages are parsed and delivered as they are
+received on the socket.
+
+In general mode, a sequence of skbs are fed to strparser from an
+outside source. Message are parsed and delivered as the sequence is
+processed. This modes allows strparser to be applied to arbitrary
+streams of data.
+
 Interface
----------
+=========
 
 The API includes a context structure, a set of callbacks, utility
-functions, and a data_ready function. The callbacks include
-a parse_msg function that is called to perform parsing (e.g.
-BPF parsing in case of KCM), and a rcv_msg function that is called
-when a full message has been completed.
+functions, and a data_ready function for receive callback mode. The
+callbacks include a parse_msg function that is called to perform
+parsing (e.g.  BPF parsing in case of KCM), and a rcv_msg function
+that is called when a full message has been completed.
 
-A stream parser can be instantiated for a TCP connection. This is done
-by:
+Functions
+=========
 
-strp_init(struct strparser *strp, struct sock *csk,
+strp_init(struct strparser *strp, struct sock *sk,
          struct strp_callbacks *cb)
 
-strp is a struct of type strparser that is allocated by the upper layer.
-csk is the TCP socket associated with the stream parser. Callbacks are
-called by the stream parser.
+     Called to initialize a stream parser. strp is a struct of type
+     strparser that is allocated by the upper layer. sk is the TCP
+     socket associated with the stream parser for use with receive
+     callback mode; in general mode this is set to NULL. Callbacks
+     are called by the stream parser (the callbacks are listed below).
+
+void strp_pause(struct strparser *strp)
+
+     Temporarily pause a stream parser. Message parsing is suspended
+     and no new messages are delivered to the upper layer.
+
+void strp_pause(struct strparser *strp)
+
+     Unpause a paused stream parser.
+
+void strp_stop(struct strparser *strp);
+
+     strp_stop is called to completely stop stream parser operations.
+     This is called internally when the stream parser encounters an
+     error, and it is called from the upper layer to stop parsing
+     operations.
+
+void strp_done(struct strparser *strp);
+
+     strp_done is called to release any resources held by the stream
+     parser instance. This must be called after the stream processor
+     has been stopped.
+
+int strp_process(struct strparser *strp, struct sk_buff *orig_skb,
+                unsigned int orig_offset, size_t orig_len,
+                size_t max_msg_size, long timeo)
+
+    strp_process is called in general mode for a stream parser to
+    parse an sk_buff. The number of bytes processed or a negative
+    error number is returned. Note that strp_process does not
+    consume the sk_buff. max_msg_size is maximum size the stream
+    parser will parse. timeo is timeout for completing a message.
+
+void strp_data_ready(struct strparser *strp);
+
+    The upper layer calls strp_tcp_data_ready when data is ready on
+    the lower socket for strparser to process. This should be called
+    from a data_ready callback that is set on the socket. Note that
+    maximum messages size is the limit of the receive socket
+    buffer and message timeout is the receive timeout for the socket.
+
+void strp_check_rcv(struct strparser *strp);
+
+    strp_check_rcv is called to check for new messages on the socket.
+    This is normally called at initialization of a stream parser
+    instance or after strp_unpause.
 
 Callbacks
----------
+=========
 
-There are four callbacks:
+There are six callbacks:
 
 int (*parse_msg)(struct strparser *strp, struct sk_buff *skb);
 
     parse_msg is called to determine the length of the next message
     in the stream. The upper layer must implement this function. It
     should parse the sk_buff as containing the headers for the
-    next application layer messages in the stream.
+    next application layer message in the stream.
 
-    The skb->cb in the input skb is a struct strp_rx_msg. Only
+    The skb->cb in the input skb is a struct strp_msg. Only
     the offset field is relevant in parse_msg and gives the offset
     where the message starts in the skb.
 
@@ -50,26 +112,41 @@ int (*parse_msg)(struct strparser *strp, struct sk_buff *skb);
     -ESTRPIPE : current message should not be processed by the
           kernel, return control of the socket to userspace which
           can proceed to read the messages itself
-    other < 0 : Error is parsing, give control back to userspace
+    other < 0 : Error in parsing, give control back to userspace
           assuming that synchronization is lost and the stream
           is unrecoverable (application expected to close TCP socket)
 
     In the case that an error is returned (return value is less than
-    zero) the stream parser will set the error on TCP socket and wake
-    it up. If parse_msg returned -ESTRPIPE and the stream parser had
-    previously read some bytes for the current message, then the error
-    set on the attached socket is ENODATA since the stream is
-    unrecoverable in that case.
+    zero) and the parser is in receive callback mode, then it will set
+    the error on TCP socket and wake it up. If parse_msg returned
+    -ESTRPIPE and the stream parser had previously read some bytes for
+    the current message, then the error set on the attached socket is
+    ENODATA since the stream is unrecoverable in that case.
+
+void (*lock)(struct strparser *strp)
+
+    The lock callback is called to lock the strp structure when
+    the strparser is performing an asynchronous operation (such as
+    processing a timeout). In receive callback mode the default
+    function is to lock_sock for the associated socket. In general
+    mode the callback must be set appropriately.
+
+void (*unlock)(struct strparser *strp)
+
+    The unlock callback is called to release the lock obtained
+    by the lock callback. In receive callback mode the default
+    function is release_sock for the associated socket. In general
+    mode the callback must be set appropriately.
 
 void (*rcv_msg)(struct strparser *strp, struct sk_buff *skb);
 
     rcv_msg is called when a full message has been received and
     is queued. The callee must consume the sk_buff; it can
     call strp_pause to prevent any further messages from being
-    received in rcv_msg (see strp_pause below). This callback
+    received in rcv_msg (see strp_pause above). This callback
     must be set.
 
-    The skb->cb in the input skb is a struct strp_rx_msg. This
+    The skb->cb in the input skb is a struct strp_msg. This
     struct contains two fields: offset and full_len. Offset is
     where the message starts in the skb, and full_len is the
     the length of the message. skb->len - offset may be greater
@@ -78,59 +155,53 @@ void (*rcv_msg)(struct strparser *strp, struct sk_buff *skb);
 int (*read_sock_done)(struct strparser *strp, int err);
 
      read_sock_done is called when the stream parser is done reading
-     the TCP socket. The stream parser may read multiple messages
-     in a loop and this function allows cleanup to occur when existing
-     the loop. If the callback is not set (NULL in strp_init) a
-     default function is used.
+     the TCP socket in receive callback mode. The stream parser may
+     read multiple messages in a loop and this function allows cleanup
+     to occur when exiting the loop. If the callback is not set (NULL
+     in strp_init) a default function is used.
 
 void (*abort_parser)(struct strparser *strp, int err);
 
      This function is called when stream parser encounters an error
-     in parsing. The default function stops the stream parser for the
-     TCP socket and sets the error in the socket. The default function
-     can be changed by setting the callback to non-NULL in strp_init.
+     in parsing. The default function stops the stream parser and
+     sets the error in the socket if the parser is in receive callback
+     mode. The default function can be changed by setting the callback
+     to non-NULL in strp_init.
 
-Functions
----------
+Statistics
+==========
 
-The upper layer calls strp_tcp_data_ready when data is ready on the lower
-socket for strparser to process. This should be called from a data_ready
-callback that is set on the socket.
+Various counters are kept for each stream parser instance. These are in
+the strp_stats structure. strp_aggr_stats is a convenience structure for
+accumulating statistics for multiple stream parser instances.
+save_strp_stats and aggregate_strp_stats are helper functions to save
+and aggregate statistics.
 
-strp_stop is called to completely stop stream parser operations. This
-is called internally when the stream parser encounters an error, and
-it is called from the upper layer when unattaching a TCP socket.
+Message assembly limits
+=======================
 
-strp_done is called to unattach the stream parser from the TCP socket.
-This must be called after the stream processor has be stopped.
+The stream parser provide mechanisms to limit the resources consumed by
+message assembly.
 
-strp_check_rcv is called to check for new messages on the socket. This
-is normally called at initialization of the a stream parser instance
-of after strp_unpause.
+A timer is set when assembly starts for a new message. In receive
+callback mode the message timeout is taken from rcvtime for the
+associated TCP socket. In general mode, the timeout is passed as an
+argument in strp_process. If the timer fires before assembly completes
+the stream parser is aborted and the ETIMEDOUT error is set on the TCP
+socket if in receive callback mode.
 
-Statistics
-----------
+In receive callback mode, message length is limited to the receive
+buffer size of the associated TCP socket. If the length returned by
+parse_msg is greater than the socket buffer size then the stream parser
+is aborted with EMSGSIZE error set on the TCP socket. Note that this
+makes the maximum size of receive skbuffs for a socket with a stream
+parser to be 2*sk_rcvbuf of the TCP socket.
 
-Various counters are kept for each stream parser for a TCP socket.
-These are in the strp_stats structure. strp_aggr_stats is a convenience
-structure for accumulating statistics for multiple stream parser
-instances. save_strp_stats and aggregate_strp_stats are helper functions
-to save and aggregate statistics.
+In general mode the message length limit is passed in as an argument
+to strp_process.
 
-Message assembly limits
------------------------
+Author
+======
 
-The stream parser provide mechanisms to limit the resources consumed by
-message assembly.
+Tom Herbert (tom@quantonium.net)
 
-A timer is set when assembly starts for a new message. The message
-timeout is taken from rcvtime for the associated TCP socket. If the
-timer fires before assembly completes the stream parser is aborted
-and the ETIMEDOUT error is set on the TCP socket.
-
-Message length is limited to the receive buffer size of the associated
-TCP socket. If the length returned by parse_msg is greater than
-the socket buffer size then the stream parser is aborted with
-EMSGSIZE error set on the TCP socket. Note that this makes the
-maximum size of receive skbuffs for a socket with a stream parser
-to be 2*sk_rcvbuf of the TCP socket.
index ae57b9e..69556f0 100644 (file)
@@ -1,6 +1,6 @@
-                        =============================
-                        NO-MMU MEMORY MAPPING SUPPORT
-                        =============================
+=============================
+No-MMU memory mapping support
+=============================
 
 The kernel has limited support for memory mapping under no-MMU conditions, such
 as are used in uClinux environments. From the userspace point of view, memory
@@ -16,7 +16,7 @@ the CLONE_VM flag.
 The behaviour is similar between the MMU and no-MMU cases, but not identical;
 and it's also much more restricted in the latter case:
 
- (*) Anonymous mapping, MAP_PRIVATE
+ (#) Anonymous mapping, MAP_PRIVATE
 
        In the MMU case: VM regions backed by arbitrary pages; copy-on-write
        across fork.
@@ -24,14 +24,14 @@ and it's also much more restricted in the latter case:
        In the no-MMU case: VM regions backed by arbitrary contiguous runs of
        pages.
 
- (*) Anonymous mapping, MAP_SHARED
+ (#) Anonymous mapping, MAP_SHARED
 
        These behave very much like private mappings, except that they're
        shared across fork() or clone() without CLONE_VM in the MMU case. Since
        the no-MMU case doesn't support these, behaviour is identical to
        MAP_PRIVATE there.
 
- (*) File, MAP_PRIVATE, PROT_READ / PROT_EXEC, !PROT_WRITE
+ (#) File, MAP_PRIVATE, PROT_READ / PROT_EXEC, !PROT_WRITE
 
        In the MMU case: VM regions backed by pages read from file; changes to
        the underlying file are reflected in the mapping; copied across fork.
@@ -56,7 +56,7 @@ and it's also much more restricted in the latter case:
           are visible in other processes (no MMU protection), but should not
           happen.
 
- (*) File, MAP_PRIVATE, PROT_READ / PROT_EXEC, PROT_WRITE
+ (#) File, MAP_PRIVATE, PROT_READ / PROT_EXEC, PROT_WRITE
 
        In the MMU case: like the non-PROT_WRITE case, except that the pages in
        question get copied before the write actually happens. From that point
@@ -66,7 +66,7 @@ and it's also much more restricted in the latter case:
        In the no-MMU case: works much like the non-PROT_WRITE case, except
        that a copy is always taken and never shared.
 
- (*) Regular file / blockdev, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE
+ (#) Regular file / blockdev, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE
 
        In the MMU case: VM regions backed by pages read from file; changes to
        pages written back to file; writes to file reflected into pages backing
@@ -74,7 +74,7 @@ and it's also much more restricted in the latter case:
 
        In the no-MMU case: not supported.
 
- (*) Memory backed regular file, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE
+ (#) Memory backed regular file, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE
 
        In the MMU case: As for ordinary regular files.
 
@@ -85,7 +85,7 @@ and it's also much more restricted in the latter case:
        as for the MMU case. If the filesystem does not provide any such
        support, then the mapping request will be denied.
 
- (*) Memory backed blockdev, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE
+ (#) Memory backed blockdev, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE
 
        In the MMU case: As for ordinary regular files.
 
@@ -94,7 +94,7 @@ and it's also much more restricted in the latter case:
        truncate being called. The ramdisk driver could do this if it allocated
        all its memory as a contiguous array upfront.
 
- (*) Memory backed chardev, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE
+ (#) Memory backed chardev, MAP_SHARED, PROT_READ / PROT_EXEC / PROT_WRITE
 
        In the MMU case: As for ordinary regular files.
 
@@ -105,21 +105,20 @@ and it's also much more restricted in the latter case:
        provide any such support, then the mapping request will be denied.
 
 
-============================
-FURTHER NOTES ON NO-MMU MMAP
+Further notes on no-MMU MMAP
 ============================
 
- (*) A request for a private mapping of a file may return a buffer that is not
+ (#) A request for a private mapping of a file may return a buffer that is not
      page-aligned.  This is because XIP may take place, and the data may not be
      paged aligned in the backing store.
 
- (*) A request for an anonymous mapping will always be page aligned.  If
+ (#) A request for an anonymous mapping will always be page aligned.  If
      possible the size of the request should be a power of two otherwise some
      of the space may be wasted as the kernel must allocate a power-of-2
      granule but will only discard the excess if appropriately configured as
      this has an effect on fragmentation.
 
- (*) The memory allocated by a request for an anonymous mapping will normally
+ (#) The memory allocated by a request for an anonymous mapping will normally
      be cleared by the kernel before being returned in accordance with the
      Linux man pages (ver 2.22 or later).
 
@@ -145,24 +144,23 @@ FURTHER NOTES ON NO-MMU MMAP
      uClibc uses this to speed up malloc(), and the ELF-FDPIC binfmt uses this
      to allocate the brk and stack region.
 
- (*) A list of all the private copy and anonymous mappings on the system is
+ (#) A list of all the private copy and anonymous mappings on the system is
      visible through /proc/maps in no-MMU mode.
 
- (*) A list of all the mappings in use by a process is visible through
+ (#) A list of all the mappings in use by a process is visible through
      /proc/<pid>/maps in no-MMU mode.
 
- (*) Supplying MAP_FIXED or a requesting a particular mapping address will
+ (#) Supplying MAP_FIXED or a requesting a particular mapping address will
      result in an error.
 
- (*) Files mapped privately usually have to have a read method provided by the
+ (#) Files mapped privately usually have to have a read method provided by the
      driver or filesystem so that the contents can be read into the memory
      allocated if mmap() chooses not to map the backing device directly. An
      error will result if they don't. This is most likely to be encountered
      with character device files, pipes, fifos and sockets.
 
 
-==========================
-INTERPROCESS SHARED MEMORY
+Interprocess shared memory
 ==========================
 
 Both SYSV IPC SHM shared memory and POSIX shared memory is supported in NOMMU
@@ -170,8 +168,7 @@ mode.  The former through the usual mechanism, the latter through files created
 on ramfs or tmpfs mounts.
 
 
-=======
-FUTEXES
+Futexes
 =======
 
 Futexes are supported in NOMMU mode if the arch supports them.  An error will
@@ -180,12 +177,11 @@ mappings made by a process or if the mapping in which the address lies does not
 support futexes (such as an I/O chardev mapping).
 
 
-=============
-NO-MMU MREMAP
+No-MMU mremap
 =============
 
 The mremap() function is partially supported.  It may change the size of a
-mapping, and may move it[*] if MREMAP_MAYMOVE is specified and if the new size
+mapping, and may move it [#]_ if MREMAP_MAYMOVE is specified and if the new size
 of the mapping exceeds the size of the slab object currently occupied by the
 memory to which the mapping refers, or if a smaller slab object could be used.
 
@@ -200,11 +196,10 @@ a previously mapped object.  It may not be used to create holes in existing
 mappings, move parts of existing mappings or resize parts of mappings.  It must
 act on a complete mapping.
 
-[*] Not currently supported.
+.. [#] Not currently supported.
 
 
-============================================
-PROVIDING SHAREABLE CHARACTER DEVICE SUPPORT
+Providing shareable character device support
 ============================================
 
 To provide shareable character device support, a driver must provide a
@@ -235,7 +230,7 @@ direct the call to the device-specific driver. Under such circumstances, the
 mapping request will be rejected if NOMMU_MAP_COPY is not specified, and a
 copy mapped otherwise.
 
-IMPORTANT NOTE:
+.. important::
 
        Some types of device may present a different appearance to anyone
        looking at them in certain modes. Flash chips can be like this; for
@@ -249,8 +244,7 @@ IMPORTANT NOTE:
        circumstances!
 
 
-==============================================
-PROVIDING SHAREABLE MEMORY-BACKED FILE SUPPORT
+Providing shareable memory-backed file support
 ==============================================
 
 Provision of shared mappings on memory backed files is similar to the provision
@@ -267,8 +261,7 @@ Memory backed devices are indicated by the mapping's backing device info having
 the memory_backed flag set.
 
 
-========================================
-PROVIDING SHAREABLE BLOCK DEVICE SUPPORT
+Providing shareable block device support
 ========================================
 
 Provision of shared mappings on block device files is exactly the same as for
@@ -276,8 +269,7 @@ character devices. If there isn't a real device underneath, then the driver
 should allocate sufficient contiguous memory to honour any supported mapping.
 
 
-=================================
-ADJUSTING PAGE TRIMMING BEHAVIOUR
+Adjusting page trimming behaviour
 =================================
 
 NOMMU mmap automatically rounds up to the nearest power-of-2 number of pages
@@ -288,4 +280,4 @@ allocator.  In order to retain finer-grained control over fragmentation, this
 behaviour can either be disabled completely, or bumped up to a higher page
 watermark where trimming begins.
 
-Page trimming behaviour is configurable via the sysctl `vm.nr_trim_pages'.
+Page trimming behaviour is configurable via the sysctl ``vm.nr_trim_pages``.
index 1d9bbab..a043854 100644 (file)
@@ -1,16 +1,21 @@
-# NTB Drivers
+===========
+NTB Drivers
+===========
 
 NTB (Non-Transparent Bridge) is a type of PCI-Express bridge chip that connects
-the separate memory systems of two computers to the same PCI-Express fabric.
-Existing NTB hardware supports a common feature set, including scratchpad
-registers, doorbell registers, and memory translation windows.  Scratchpad
-registers are read-and-writable registers that are accessible from either side
-of the device, so that peers can exchange a small amount of information at a
-fixed address.  Doorbell registers provide a way for peers to send interrupt
-events.  Memory windows allow translated read and write access to the peer
-memory.
-
-## NTB Core Driver (ntb)
+the separate memory systems of two or more computers to the same PCI-Express
+fabric. Existing NTB hardware supports a common feature set: doorbell
+registers and memory translation windows, as well as non common features like
+scratchpad and message registers. Scratchpad registers are read-and-writable
+registers that are accessible from either side of the device, so that peers can
+exchange a small amount of information at a fixed address. Message registers can
+be utilized for the same purpose. Additionally they are provided with with
+special status bits to make sure the information isn't rewritten by another
+peer. Doorbell registers provide a way for peers to send interrupt events.
+Memory windows allow translated read and write access to the peer memory.
+
+NTB Core Driver (ntb)
+=====================
 
 The NTB core driver defines an api wrapping the common feature set, and allows
 clients interested in NTB features to discover NTB the devices supported by
@@ -18,7 +23,8 @@ hardware drivers.  The term "client" is used here to mean an upper layer
 component making use of the NTB api.  The term "driver," or "hardware driver,"
 is used here to mean a driver for a specific vendor and model of NTB hardware.
 
-## NTB Client Drivers
+NTB Client Drivers
+==================
 
 NTB client drivers should register with the NTB core driver.  After
 registering, the client probe and remove functions will be called appropriately
@@ -26,7 +32,90 @@ as ntb hardware, or hardware drivers, are inserted and removed.  The
 registration uses the Linux Device framework, so it should feel familiar to
 anyone who has written a pci driver.
 
-### NTB Transport Client (ntb\_transport) and NTB Netdev (ntb\_netdev)
+NTB Typical client driver implementation
+----------------------------------------
+
+Primary purpose of NTB is to share some peace of memory between at least two
+systems. So the NTB device features like Scratchpad/Message registers are
+mainly used to perform the proper memory window initialization. Typically
+there are two types of memory window interfaces supported by the NTB API:
+inbound translation configured on the local ntb port and outbound translation
+configured by the peer, on the peer ntb port. The first type is
+depicted on the next figure
+
+Inbound translation:
+ Memory:              Local NTB Port:      Peer NTB Port:      Peer MMIO:
+  ____________
+ | dma-mapped |-ntb_mw_set_trans(addr)  |
+ | memory     |        _v____________   |   ______________
+ | (addr)     |<======| MW xlat addr |<====| MW base addr |<== memory-mapped IO
+ |------------|       |--------------|  |  |--------------|
+
+So typical scenario of the first type memory window initialization looks:
+1) allocate a memory region, 2) put translated address to NTB config,
+3) somehow notify a peer device of performed initialization, 4) peer device
+maps corresponding outbound memory window so to have access to the shared
+memory region.
+
+The second type of interface, that implies the shared windows being
+initialized by a peer device, is depicted on the figure:
+
+Outbound translation:
+ Memory:        Local NTB Port:    Peer NTB Port:      Peer MMIO:
+  ____________                      ______________
+ | dma-mapped |                |   | MW base addr |<== memory-mapped IO
+ | memory     |                |   |--------------|
+ | (addr)     |<===================| MW xlat addr |<-ntb_peer_mw_set_trans(addr)
+ |------------|                |   |--------------|
+
+Typical scenario of the second type interface initialization would be:
+1) allocate a memory region, 2) somehow deliver a translated address to a peer
+device, 3) peer puts the translated address to NTB config, 4) peer device maps
+outbound memory window so to have access to the shared memory region.
+
+As one can see the described scenarios can be combined in one portable
+algorithm.
+ Local device:
+  1) Allocate memory for a shared window
+  2) Initialize memory window by translated address of the allocated region
+     (it may fail if local memory window initialization is unsupported)
+  3) Send the translated address and memory window index to a peer device
+ Peer device:
+  1) Initialize memory window with retrieved address of the allocated
+     by another device memory region (it may fail if peer memory window
+     initialization is unsupported)
+  2) Map outbound memory window
+
+In accordance with this scenario, the NTB Memory Window API can be used as
+follows:
+ Local device:
+  1) ntb_mw_count(pidx) - retrieve number of memory ranges, which can
+     be allocated for memory windows between local device and peer device
+     of port with specified index.
+  2) ntb_get_align(pidx, midx) - retrieve parameters restricting the
+     shared memory region alignment and size. Then memory can be properly
+     allocated.
+  3) Allocate physically contiguous memory region in compliance with
+     restrictions retrieved in 2).
+  4) ntb_mw_set_trans(pidx, midx) - try to set translation address of
+     the memory window with specified index for the defined peer device
+     (it may fail if local translated address setting is not supported)
+  5) Send translated base address (usually together with memory window
+     number) to the peer device using, for instance, scratchpad or message
+     registers.
+ Peer device:
+  1) ntb_peer_mw_set_trans(pidx, midx) - try to set received from other
+     device (related to pidx) translated address for specified memory
+     window. It may fail if retrieved address, for instance, exceeds
+     maximum possible address or isn't properly aligned.
+  2) ntb_peer_mw_get_addr(widx) - retrieve MMIO address to map the memory
+     window so to have an access to the shared memory.
+
+Also it is worth to note, that method ntb_mw_count(pidx) should return the
+same value as ntb_peer_mw_count() on the peer with port index - pidx.
+
+NTB Transport Client (ntb\_transport) and NTB Netdev (ntb\_netdev)
+------------------------------------------------------------------
 
 The primary client for NTB is the Transport client, used in tandem with NTB
 Netdev.  These drivers function together to create a logical link to the peer,
@@ -37,7 +126,8 @@ Transport queue pair.  Network data is copied between socket buffers and the
 Transport queue pair buffer.  The Transport client may be used for other things
 besides Netdev, however no other applications have yet been written.
 
-### NTB Ping Pong Test Client (ntb\_pingpong)
+NTB Ping Pong Test Client (ntb\_pingpong)
+-----------------------------------------
 
 The Ping Pong test client serves as a demonstration to exercise the doorbell
 and scratchpad registers of NTB hardware, and as an example simple NTB client.
@@ -64,7 +154,8 @@ Module Parameters:
 * dyndbg - It is suggested to specify dyndbg=+p when loading this module, and
        then to observe debugging output on the console.
 
-### NTB Tool Test Client (ntb\_tool)
+NTB Tool Test Client (ntb\_tool)
+--------------------------------
 
 The Tool test client serves for debugging, primarily, ntb hardware and drivers.
 The Tool provides access through debugfs for reading, setting, and clearing the
@@ -74,48 +165,60 @@ The Tool does not currently have any module parameters.
 
 Debugfs Files:
 
-* *debugfs*/ntb\_tool/*hw*/ - A directory in debugfs will be created for each
+* *debugfs*/ntb\_tool/*hw*/
+       A directory in debugfs will be created for each
        NTB device probed by the tool.  This directory is shortened to *hw*
        below.
-* *hw*/db - This file is used to read, set, and clear the local doorbell.  Not
+* *hw*/db
+       This file is used to read, set, and clear the local doorbell.  Not
        all operations may be supported by all hardware.  To read the doorbell,
        read the file.  To set the doorbell, write `s` followed by the bits to
        set (eg: `echo 's 0x0101' > db`).  To clear the doorbell, write `c`
        followed by the bits to clear.
-* *hw*/mask - This file is used to read, set, and clear the local doorbell mask.
+* *hw*/mask
+       This file is used to read, set, and clear the local doorbell mask.
        See *db* for details.
-* *hw*/peer\_db - This file is used to read, set, and clear the peer doorbell.
+* *hw*/peer\_db
+       This file is used to read, set, and clear the peer doorbell.
        See *db* for details.
-* *hw*/peer\_mask - This file is used to read, set, and clear the peer doorbell
+* *hw*/peer\_mask
+       This file is used to read, set, and clear the peer doorbell
        mask.  See *db* for details.
-* *hw*/spad - This file is used to read and write local scratchpads.  To read
+* *hw*/spad
+       This file is used to read and write local scratchpads.  To read
        the values of all scratchpads, read the file.  To write values, write a
        series of pairs of scratchpad number and value
        (eg: `echo '4 0x123 7 0xabc' > spad`
        # to set scratchpads `4` and `7` to `0x123` and `0xabc`, respectively).
-* *hw*/peer\_spad - This file is used to read and write peer scratchpads.  See
+* *hw*/peer\_spad
+       This file is used to read and write peer scratchpads.  See
        *spad* for details.
 
-## NTB Hardware Drivers
+NTB Hardware Drivers
+====================
 
 NTB hardware drivers should register devices with the NTB core driver.  After
 registering, clients probe and remove functions will be called.
 
-### NTB Intel Hardware Driver (ntb\_hw\_intel)
+NTB Intel Hardware Driver (ntb\_hw\_intel)
+------------------------------------------
 
 The Intel hardware driver supports NTB on Xeon and Atom CPUs.
 
 Module Parameters:
 
-* b2b\_mw\_idx - If the peer ntb is to be accessed via a memory window, then use
+* b2b\_mw\_idx
+       If the peer ntb is to be accessed via a memory window, then use
        this memory window to access the peer ntb.  A value of zero or positive
        starts from the first mw idx, and a negative value starts from the last
        mw idx.  Both sides MUST set the same value here!  The default value is
        `-1`.
-* b2b\_mw\_share - If the peer ntb is to be accessed via a memory window, and if
+* b2b\_mw\_share
+       If the peer ntb is to be accessed via a memory window, and if
        the memory window is large enough, still allow the client to use the
        second half of the memory window for address translation to the peer.
-* xeon\_b2b\_usd\_bar2\_addr64 - If using B2B topology on Xeon hardware, use
+* xeon\_b2b\_usd\_bar2\_addr64
+       If using B2B topology on Xeon hardware, use
        this 64 bit address on the bus between the NTB devices for the window
        at BAR2, on the upstream side of the link.
 * xeon\_b2b\_usd\_bar4\_addr64 - See *xeon\_b2b\_bar2\_addr64*.
index 5203277..aaf1667 100644 (file)
@@ -1,10 +1,12 @@
-
+===============================
 Numa policy hit/miss statistics
+===============================
 
 /sys/devices/system/node/node*/numastat
 
 All units are pages. Hugepages have separate counters.
 
+=============== ============================================================
 numa_hit       A process wanted to allocate memory from this node,
                and succeeded.
 
@@ -20,6 +22,7 @@ other_node    A process ran on this node and got memory from another node.
 
 interleave_hit         Interleaving wanted to allocate from this node
                and succeeded.
+=============== ============================================================
 
 For easier reading you can use the numastat utility from the numactl package
 (http://oss.sgi.com/projects/libnuma/). Note that it only works
index 7ddfe21..b103d0c 100644 (file)
@@ -1,5 +1,8 @@
+=======================================
 The padata parallel execution mechanism
-Last updated for 2.6.36
+=======================================
+
+:Last updated: for 2.6.36
 
 Padata is a mechanism by which the kernel can farm work out to be done in
 parallel on multiple CPUs while retaining the ordering of tasks.  It was
@@ -9,7 +12,7 @@ those packets.  The crypto developers made a point of writing padata in a
 sufficiently general fashion that it could be put to other uses as well.
 
 The first step in using padata is to set up a padata_instance structure for
-overall control of how tasks are to be run:
+overall control of how tasks are to be run::
 
     #include <linux/padata.h>
 
@@ -24,7 +27,7 @@ The workqueue wq is where the work will actually be done; it should be
 a multithreaded queue, naturally.
 
 To allocate a padata instance with the cpu_possible_mask for both
-cpumasks this helper function can be used:
+cpumasks this helper function can be used::
 
     struct padata_instance *padata_alloc_possible(struct workqueue_struct *wq);
 
@@ -36,7 +39,7 @@ it is legal to supply a cpumask to padata that contains offline CPUs.
 Once an offline CPU in the user supplied cpumask comes online, padata
 is going to use it.
 
-There are functions for enabling and disabling the instance:
+There are functions for enabling and disabling the instance::
 
     int padata_start(struct padata_instance *pinst);
     void padata_stop(struct padata_instance *pinst);
@@ -48,7 +51,7 @@ padata cpumask contains no active CPU (flag not set).
 padata_stop clears the flag and blocks until the padata instance
 is unused.
 
-The list of CPUs to be used can be adjusted with these functions:
+The list of CPUs to be used can be adjusted with these functions::
 
     int padata_set_cpumasks(struct padata_instance *pinst,
                            cpumask_var_t pcpumask,
@@ -71,12 +74,12 @@ padata_add_cpu/padata_remove_cpu are used. cpu specifies the CPU to add or
 remove and mask is one of PADATA_CPU_SERIAL, PADATA_CPU_PARALLEL.
 
 If a user is interested in padata cpumask changes, he can register to
-the padata cpumask change notifier:
+the padata cpumask change notifier::
 
     int padata_register_cpumask_notifier(struct padata_instance *pinst,
                                         struct notifier_block *nblock);
 
-To unregister from that notifier:
+To unregister from that notifier::
 
     int padata_unregister_cpumask_notifier(struct padata_instance *pinst,
                                           struct notifier_block *nblock);
@@ -84,7 +87,7 @@ To unregister from that notifier:
 The padata cpumask change notifier notifies about changes of the usable
 cpumasks, i.e. the subset of active CPUs in the user supplied cpumask.
 
-Padata calls the notifier chain with:
+Padata calls the notifier chain with::
 
     blocking_notifier_call_chain(&pinst->cpumask_change_notifier,
                                 notification_mask,
@@ -95,7 +98,7 @@ is one of PADATA_CPU_SERIAL, PADATA_CPU_PARALLEL and cpumask is a pointer
 to a struct padata_cpumask that contains the new cpumask information.
 
 Actually submitting work to the padata instance requires the creation of a
-padata_priv structure:
+padata_priv structure::
 
     struct padata_priv {
         /* Other stuff here... */
@@ -110,7 +113,7 @@ parallel() and serial() functions should be provided.  Those functions will
 be called in the process of getting the work done as we will see
 momentarily.
 
-The submission of work is done with:
+The submission of work is done with::
 
     int padata_do_parallel(struct padata_instance *pinst,
                           struct padata_priv *padata, int cb_cpu);
@@ -138,7 +141,7 @@ need not be completed during this call, but, if parallel() leaves work
 outstanding, it should be prepared to be called again with a new job before
 the previous one completes.  When a task does complete, parallel() (or
 whatever function actually finishes the job) should inform padata of the
-fact with a call to:
+fact with a call to::
 
     void padata_do_serial(struct padata_priv *padata);
 
@@ -151,7 +154,7 @@ pains to ensure that tasks are completed in the order in which they were
 submitted.
 
 The one remaining function in the padata API should be called to clean up
-when a padata instance is no longer needed:
+when a padata instance is no longer needed::
 
     void padata_free(struct padata_instance *pinst);
 
index 120eb20..0633d70 100644 (file)
@@ -1,11 +1,12 @@
+===============================
 PARPORT interface documentation
--------------------------------
+===============================
 
-Time-stamp: <2000-02-24 13:30:20 twaugh>
+:Time-stamp: <2000-02-24 13:30:20 twaugh>
 
 Described here are the following functions:
 
-Global functions:
+Global functions::
   parport_register_driver
   parport_unregister_driver
   parport_enumerate
@@ -31,7 +32,8 @@ Global functions:
   parport_set_timeout
 
 Port functions (can be overridden by low-level drivers):
-  SPP:
+
+  SPP::
     port->ops->read_data
     port->ops->write_data
     port->ops->read_status
@@ -43,23 +45,23 @@ Port functions (can be overridden by low-level drivers):
     port->ops->data_forward
     port->ops->data_reverse
 
-  EPP:
+  EPP::
     port->ops->epp_write_data
     port->ops->epp_read_data
     port->ops->epp_write_addr
     port->ops->epp_read_addr
 
-  ECP:
+  ECP::
     port->ops->ecp_write_data
     port->ops->ecp_read_data
     port->ops->ecp_write_addr
 
-  Other:
+  Other::
     port->ops->nibble_read_data
     port->ops->byte_read_data
     port->ops->compat_write_data
 
-The parport subsystem comprises 'parport' (the core port-sharing
+The parport subsystem comprises ``parport`` (the core port-sharing
 code), and a variety of low-level drivers that actually do the port
 accesses.  Each low-level driver handles a particular style of port
 (PC, Amiga, and so on).
@@ -70,14 +72,14 @@ into global functions and port functions.
 The global functions are mostly for communicating between the device
 driver and the parport subsystem: acquiring a list of available ports,
 claiming a port for exclusive use, and so on.  They also include
-'generic' functions for doing standard things that will work on any
+``generic`` functions for doing standard things that will work on any
 IEEE 1284-capable architecture.
 
 The port functions are provided by the low-level drivers, although the
-core parport module provides generic 'defaults' for some routines.
+core parport module provides generic ``defaults`` for some routines.
 The port functions can be split into three groups: SPP, EPP, and ECP.
 
-SPP (Standard Parallel Port) functions modify so-called 'SPP'
+SPP (Standard Parallel Port) functions modify so-called ``SPP``
 registers: data, status, and control.  The hardware may not actually
 have registers exactly like that, but the PC does and this interface is
 modelled after common PC implementations.  Other low-level drivers may
@@ -95,58 +97,63 @@ to cope with peripherals that only tenuously support IEEE 1284, a
 low-level driver specific function is provided, for altering 'fudge
 factors'.
 \f
-GLOBAL FUNCTIONS
-----------------
+Global functions
+================
 
 parport_register_driver - register a device driver with parport
------------------------
+---------------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-struct parport_driver {
-       const char *name;
-       void (*attach) (struct parport *);
-       void (*detach) (struct parport *);
-       struct parport_driver *next;
-};
-int parport_register_driver (struct parport_driver *driver);
+       struct parport_driver {
+               const char *name;
+               void (*attach) (struct parport *);
+               void (*detach) (struct parport *);
+               struct parport_driver *next;
+       };
+       int parport_register_driver (struct parport_driver *driver);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 In order to be notified about parallel ports when they are detected,
 parport_register_driver should be called.  Your driver will
 immediately be notified of all ports that have already been detected,
 and of each new port as low-level drivers are loaded.
 
-A 'struct parport_driver' contains the textual name of your driver,
+A ``struct parport_driver`` contains the textual name of your driver,
 a pointer to a function to handle new ports, and a pointer to a
 function to handle ports going away due to a low-level driver
 unloading.  Ports will only be detached if they are not being used
 (i.e. there are no devices registered on them).
 
-The visible parts of the 'struct parport *' argument given to
-attach/detach are:
-
-struct parport
-{
-       struct parport *next; /* next parport in list */
-       const char *name;     /* port's name */
-       unsigned int modes;   /* bitfield of hardware modes */
-       struct parport_device_info probe_info;
-                             /* IEEE1284 info */
-       int number;           /* parport index */
-       struct parport_operations *ops;
-       ...
-};
+The visible parts of the ``struct parport *`` argument given to
+attach/detach are::
+
+       struct parport
+       {
+               struct parport *next; /* next parport in list */
+               const char *name;     /* port's name */
+               unsigned int modes;   /* bitfield of hardware modes */
+               struct parport_device_info probe_info;
+                               /* IEEE1284 info */
+               int number;           /* parport index */
+               struct parport_operations *ops;
+               ...
+       };
 
 There are other members of the structure, but they should not be
 touched.
 
-The 'modes' member summarises the capabilities of the underlying
+The ``modes`` member summarises the capabilities of the underlying
 hardware.  It consists of flags which may be bitwise-ored together:
 
+  ============================= ===============================================
   PARPORT_MODE_PCSPP           IBM PC registers are available,
                                i.e. functions that act on data,
                                control and status registers are
@@ -169,297 +176,351 @@ hardware.  It consists of flags which may be bitwise-ored together:
                                GFP_DMA flag with kmalloc) to the
                                low-level driver in order to take
                                advantage of it.
+  ============================= ===============================================
 
-There may be other flags in 'modes' as well.
+There may be other flags in ``modes`` as well.
 
-The contents of 'modes' is advisory only.  For example, if the
-hardware is capable of DMA, and PARPORT_MODE_DMA is in 'modes', it
+The contents of ``modes`` is advisory only.  For example, if the
+hardware is capable of DMA, and PARPORT_MODE_DMA is in ``modes``, it
 doesn't necessarily mean that DMA will always be used when possible.
 Similarly, hardware that is capable of assisting ECP transfers won't
 necessarily be used.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 Zero on success, otherwise an error code.
 
 ERRORS
+^^^^^^
 
 None. (Can it fail? Why return int?)
 
 EXAMPLE
+^^^^^^^
 
-static void lp_attach (struct parport *port)
-{
-       ...
-       private = kmalloc (...);
-       dev[count++] = parport_register_device (...);
-       ...
-}
+::
 
-static void lp_detach (struct parport *port)
-{
-       ...
-}
+       static void lp_attach (struct parport *port)
+       {
+               ...
+               private = kmalloc (...);
+               dev[count++] = parport_register_device (...);
+               ...
+       }
 
-static struct parport_driver lp_driver = {
-       "lp",
-       lp_attach,
-       lp_detach,
-       NULL /* always put NULL here */
-};
+       static void lp_detach (struct parport *port)
+       {
+               ...
+       }
 
-int lp_init (void)
-{
-       ...
-       if (parport_register_driver (&lp_driver)) {
-               /* Failed; nothing we can do. */
-               return -EIO;
+       static struct parport_driver lp_driver = {
+               "lp",
+               lp_attach,
+               lp_detach,
+               NULL /* always put NULL here */
+       };
+
+       int lp_init (void)
+       {
+               ...
+               if (parport_register_driver (&lp_driver)) {
+                       /* Failed; nothing we can do. */
+                       return -EIO;
+               }
+               ...
        }
-       ...
-}
+
 
 SEE ALSO
+^^^^^^^^
 
 parport_unregister_driver, parport_register_device, parport_enumerate
-\f
+
+
+
 parport_unregister_driver - tell parport to forget about this driver
--------------------------
+--------------------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_driver {
-       const char *name;
-       void (*attach) (struct parport *);
-       void (*detach) (struct parport *);
-       struct parport_driver *next;
-};
-void parport_unregister_driver (struct parport_driver *driver);
+       #include <linux/parport.h>
+
+       struct parport_driver {
+               const char *name;
+               void (*attach) (struct parport *);
+               void (*detach) (struct parport *);
+               struct parport_driver *next;
+       };
+       void parport_unregister_driver (struct parport_driver *driver);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 This tells parport not to notify the device driver of new ports or of
 ports going away.  Registered devices belonging to that driver are NOT
 unregistered: parport_unregister_device must be used for each one.
 
 EXAMPLE
+^^^^^^^
 
-void cleanup_module (void)
-{
-       ...
-       /* Stop notifications. */
-       parport_unregister_driver (&lp_driver);
+::
 
-       /* Unregister devices. */
-       for (i = 0; i < NUM_DEVS; i++)
-               parport_unregister_device (dev[i]);
-       ...
-}
+       void cleanup_module (void)
+       {
+               ...
+               /* Stop notifications. */
+               parport_unregister_driver (&lp_driver);
+
+               /* Unregister devices. */
+               for (i = 0; i < NUM_DEVS; i++)
+                       parport_unregister_device (dev[i]);
+               ...
+       }
 
 SEE ALSO
+^^^^^^^^
 
 parport_register_driver, parport_enumerate
-\f
+
+
+
 parport_enumerate - retrieve a list of parallel ports (DEPRECATED)
------------------
+------------------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport *parport_enumerate (void);
+       #include <linux/parport.h>
+
+       struct parport *parport_enumerate (void);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Retrieve the first of a list of valid parallel ports for this machine.
-Successive parallel ports can be found using the 'struct parport
-*next' element of the 'struct parport *' that is returned.  If 'next'
+Successive parallel ports can be found using the ``struct parport
+*next`` element of the ``struct parport *`` that is returned.  If ``next``
 is NULL, there are no more parallel ports in the list.  The number of
 ports in the list will not exceed PARPORT_MAX.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
-A 'struct parport *' describing a valid parallel port for the machine,
+A ``struct parport *`` describing a valid parallel port for the machine,
 or NULL if there are none.
 
 ERRORS
+^^^^^^
 
 This function can return NULL to indicate that there are no parallel
 ports to use.
 
 EXAMPLE
+^^^^^^^
+
+::
 
-int detect_device (void)
-{
-       struct parport *port;
+       int detect_device (void)
+       {
+               struct parport *port;
+
+               for (port = parport_enumerate ();
+               port != NULL;
+               port = port->next) {
+                       /* Try to detect a device on the port... */
+                       ...
+               }
+               }
 
-       for (port = parport_enumerate ();
-            port != NULL;
-            port = port->next) {
-               /* Try to detect a device on the port... */
                ...
-             }
        }
 
-       ...
-}
-
 NOTES
+^^^^^
 
 parport_enumerate is deprecated; parport_register_driver should be
 used instead.
 
 SEE ALSO
+^^^^^^^^
 
 parport_register_driver, parport_unregister_driver
-\f
+
+
+
 parport_register_device - register to use a port
------------------------
+------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-typedef int (*preempt_func) (void *handle);
-typedef void (*wakeup_func) (void *handle);
-typedef int (*irq_func) (int irq, void *handle, struct pt_regs *);
+       #include <linux/parport.h>
 
-struct pardevice *parport_register_device(struct parport *port,
-                                          const char *name,
-                                          preempt_func preempt,
-                                          wakeup_func wakeup,
-                                          irq_func irq,
-                                          int flags,
-                                          void *handle);
+       typedef int (*preempt_func) (void *handle);
+       typedef void (*wakeup_func) (void *handle);
+       typedef int (*irq_func) (int irq, void *handle, struct pt_regs *);
+
+       struct pardevice *parport_register_device(struct parport *port,
+                                                 const char *name,
+                                                 preempt_func preempt,
+                                                 wakeup_func wakeup,
+                                                 irq_func irq,
+                                                 int flags,
+                                                 void *handle);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Use this function to register your device driver on a parallel port
-('port').  Once you have done that, you will be able to use
+(``port``).  Once you have done that, you will be able to use
 parport_claim and parport_release in order to use the port.
 
-The ('name') argument is the name of the device that appears in /proc
+The (``name``) argument is the name of the device that appears in /proc
 filesystem. The string must be valid for the whole lifetime of the
 device (until parport_unregister_device is called).
 
 This function will register three callbacks into your driver:
-'preempt', 'wakeup' and 'irq'.  Each of these may be NULL in order to
+``preempt``, ``wakeup`` and ``irq``.  Each of these may be NULL in order to
 indicate that you do not want a callback.
 
-When the 'preempt' function is called, it is because another driver
-wishes to use the parallel port.  The 'preempt' function should return
+When the ``preempt`` function is called, it is because another driver
+wishes to use the parallel port.  The ``preempt`` function should return
 non-zero if the parallel port cannot be released yet -- if zero is
 returned, the port is lost to another driver and the port must be
 re-claimed before use.
 
-The 'wakeup' function is called once another driver has released the
+The ``wakeup`` function is called once another driver has released the
 port and no other driver has yet claimed it.  You can claim the
-parallel port from within the 'wakeup' function (in which case the
+parallel port from within the ``wakeup`` function (in which case the
 claim is guaranteed to succeed), or choose not to if you don't need it
 now.
 
 If an interrupt occurs on the parallel port your driver has claimed,
-the 'irq' function will be called. (Write something about shared
+the ``irq`` function will be called. (Write something about shared
 interrupts here.)
 
-The 'handle' is a pointer to driver-specific data, and is passed to
+The ``handle`` is a pointer to driver-specific data, and is passed to
 the callback functions.
 
-'flags' may be a bitwise combination of the following flags:
+``flags`` may be a bitwise combination of the following flags:
 
+  ===================== =================================================
         Flag            Meaning
+  ===================== =================================================
   PARPORT_DEV_EXCL     The device cannot share the parallel port at all.
                        Use this only when absolutely necessary.
+  ===================== =================================================
 
 The typedefs are not actually defined -- they are only shown in order
 to make the function prototype more readable.
 
-The visible parts of the returned 'struct pardevice' are:
+The visible parts of the returned ``struct pardevice`` are::
 
-struct pardevice {
-       struct parport *port;   /* Associated port */
-       void *private;          /* Device driver's 'handle' */
-       ...
-};
+       struct pardevice {
+               struct parport *port;   /* Associated port */
+               void *private;          /* Device driver's 'handle' */
+               ...
+       };
 
 RETURN VALUE
+^^^^^^^^^^^^
 
-A 'struct pardevice *': a handle to the registered parallel port
+A ``struct pardevice *``: a handle to the registered parallel port
 device that can be used for parport_claim, parport_release, etc.
 
 ERRORS
+^^^^^^
 
 A return value of NULL indicates that there was a problem registering
 a device on that port.
 
 EXAMPLE
+^^^^^^^
+
+::
+
+       static int preempt (void *handle)
+       {
+               if (busy_right_now)
+                       return 1;
+
+               must_reclaim_port = 1;
+               return 0;
+       }
+
+       static void wakeup (void *handle)
+       {
+               struct toaster *private = handle;
+               struct pardevice *dev = private->dev;
+               if (!dev) return; /* avoid races */
+
+               if (want_port)
+                       parport_claim (dev);
+       }
+
+       static int toaster_detect (struct toaster *private, struct parport *port)
+       {
+               private->dev = parport_register_device (port, "toaster", preempt,
+                                                       wakeup, NULL, 0,
+                                                       private);
+               if (!private->dev)
+                       /* Couldn't register with parport. */
+                       return -EIO;
 
-static int preempt (void *handle)
-{
-       if (busy_right_now)
-               return 1;
-
-       must_reclaim_port = 1;
-       return 0;
-}
-
-static void wakeup (void *handle)
-{
-       struct toaster *private = handle;
-       struct pardevice *dev = private->dev;
-       if (!dev) return; /* avoid races */
-
-       if (want_port)
-               parport_claim (dev);
-}
-
-static int toaster_detect (struct toaster *private, struct parport *port)
-{
-       private->dev = parport_register_device (port, "toaster", preempt,
-                                               wakeup, NULL, 0,
-                                               private);
-       if (!private->dev)
-               /* Couldn't register with parport. */
-               return -EIO;
-
-       must_reclaim_port = 0;
-       busy_right_now = 1;
-       parport_claim_or_block (private->dev);
-       ...
-       /* Don't need the port while the toaster warms up. */
-       busy_right_now = 0;
-       ...
-       busy_right_now = 1;
-       if (must_reclaim_port) {
-               parport_claim_or_block (private->dev);
                must_reclaim_port = 0;
+               busy_right_now = 1;
+               parport_claim_or_block (private->dev);
+               ...
+               /* Don't need the port while the toaster warms up. */
+               busy_right_now = 0;
+               ...
+               busy_right_now = 1;
+               if (must_reclaim_port) {
+                       parport_claim_or_block (private->dev);
+                       must_reclaim_port = 0;
+               }
+               ...
        }
-       ...
-}
 
 SEE ALSO
+^^^^^^^^
 
 parport_unregister_device, parport_claim
+
+
 \f
 parport_unregister_device - finish using a port
--------------------------
+-----------------------------------------------
 
 SYNPOPSIS
 
-#include <linux/parport.h>
+::
+
+       #include <linux/parport.h>
 
-void parport_unregister_device (struct pardevice *dev);
+       void parport_unregister_device (struct pardevice *dev);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 This function is the opposite of parport_register_device.  After using
-parport_unregister_device, 'dev' is no longer a valid device handle.
+parport_unregister_device, ``dev`` is no longer a valid device handle.
 
 You should not unregister a device that is currently claimed, although
 if you do it will be released automatically.
 
 EXAMPLE
+^^^^^^^
+
+::
 
        ...
        kfree (dev->private); /* before we lose the pointer */
@@ -467,460 +528,602 @@ EXAMPLE
        ...
 
 SEE ALSO
+^^^^^^^^
+
 
 parport_unregister_driver
 \f
 parport_claim, parport_claim_or_block - claim the parallel port for a device
--------------------------------------
+----------------------------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-int parport_claim (struct pardevice *dev);
-int parport_claim_or_block (struct pardevice *dev);
+       int parport_claim (struct pardevice *dev);
+       int parport_claim_or_block (struct pardevice *dev);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 These functions attempt to gain control of the parallel port on which
-'dev' is registered.  'parport_claim' does not block, but
-'parport_claim_or_block' may do. (Put something here about blocking
+``dev`` is registered.  ``parport_claim`` does not block, but
+``parport_claim_or_block`` may do. (Put something here about blocking
 interruptibly or non-interruptibly.)
 
 You should not try to claim a port that you have already claimed.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 A return value of zero indicates that the port was successfully
 claimed, and the caller now has possession of the parallel port.
 
-If 'parport_claim_or_block' blocks before returning successfully, the
+If ``parport_claim_or_block`` blocks before returning successfully, the
 return value is positive.
 
 ERRORS
+^^^^^^
 
+========== ==========================================================
   -EAGAIN  The port is unavailable at the moment, but another attempt
            to claim it may succeed.
+========== ==========================================================
 
 SEE ALSO
+^^^^^^^^
+
 
 parport_release
 \f
 parport_release - release the parallel port
----------------
+-------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-void parport_release (struct pardevice *dev);
+       void parport_release (struct pardevice *dev);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Once a parallel port device has been claimed, it can be released using
-'parport_release'.  It cannot fail, but you should not release a
+``parport_release``.  It cannot fail, but you should not release a
 device that you do not have possession of.
 
 EXAMPLE
+^^^^^^^
 
-static size_t write (struct pardevice *dev, const void *buf,
-                    size_t len)
-{
-       ...
-       written = dev->port->ops->write_ecp_data (dev->port, buf,
-                                                 len);
-       parport_release (dev);
-       ...
-}
+::
+
+       static size_t write (struct pardevice *dev, const void *buf,
+                       size_t len)
+       {
+               ...
+               written = dev->port->ops->write_ecp_data (dev->port, buf,
+                                                       len);
+               parport_release (dev);
+               ...
+       }
 
 
 SEE ALSO
+^^^^^^^^
 
 change_mode, parport_claim, parport_claim_or_block, parport_yield
-\f
+
+
+
 parport_yield, parport_yield_blocking - temporarily release a parallel port
--------------------------------------
+---------------------------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-int parport_yield (struct pardevice *dev)
-int parport_yield_blocking (struct pardevice *dev);
+       int parport_yield (struct pardevice *dev)
+       int parport_yield_blocking (struct pardevice *dev);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 When a driver has control of a parallel port, it may allow another
-driver to temporarily 'borrow' it.  'parport_yield' does not block;
-'parport_yield_blocking' may do.
+driver to temporarily ``borrow`` it.  ``parport_yield`` does not block;
+``parport_yield_blocking`` may do.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 A return value of zero indicates that the caller still owns the port
 and the call did not block.
 
-A positive return value from 'parport_yield_blocking' indicates that
+A positive return value from ``parport_yield_blocking`` indicates that
 the caller still owns the port and the call blocked.
 
 A return value of -EAGAIN indicates that the caller no longer owns the
 port, and it must be re-claimed before use.
 
 ERRORS
+^^^^^^
 
+========= ==========================================================
   -EAGAIN  Ownership of the parallel port was given away.
+========= ==========================================================
 
 SEE ALSO
+^^^^^^^^
 
 parport_release
+
+
 \f
 parport_wait_peripheral - wait for status lines, up to 35ms
------------------------
+-----------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-int parport_wait_peripheral (struct parport *port,
-                            unsigned char mask,
-                            unsigned char val);
+       int parport_wait_peripheral (struct parport *port,
+                                    unsigned char mask,
+                                    unsigned char val);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Wait for the status lines in mask to match the values in val.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
+======== ==========================================================
  -EINTR  a signal is pending
       0  the status lines in mask have values in val
       1  timed out while waiting (35ms elapsed)
+======== ==========================================================
 
 SEE ALSO
+^^^^^^^^
 
 parport_poll_peripheral
+
+
 \f
 parport_poll_peripheral - wait for status lines, in usec
------------------------
+--------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-int parport_poll_peripheral (struct parport *port,
-                            unsigned char mask,
-                            unsigned char val,
-                            int usec);
+       int parport_poll_peripheral (struct parport *port,
+                                    unsigned char mask,
+                                    unsigned char val,
+                                    int usec);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Wait for the status lines in mask to match the values in val.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
+======== ==========================================================
  -EINTR  a signal is pending
       0  the status lines in mask have values in val
       1  timed out while waiting (usec microseconds have elapsed)
+======== ==========================================================
 
 SEE ALSO
+^^^^^^^^
 
 parport_wait_peripheral
-\f
+
+
+
 parport_wait_event - wait for an event on a port
-------------------
+------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-int parport_wait_event (struct parport *port, signed long timeout)
+       #include <linux/parport.h>
+
+       int parport_wait_event (struct parport *port, signed long timeout)
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Wait for an event (e.g. interrupt) on a port.  The timeout is in
 jiffies.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
+======= ==========================================================
       0  success
      <0  error (exit as soon as possible)
      >0  timed out
-\f
+======= ==========================================================
+
 parport_negotiate - perform IEEE 1284 negotiation
------------------
+-------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-int parport_negotiate (struct parport *, int mode);
+       int parport_negotiate (struct parport *, int mode);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Perform IEEE 1284 negotiation.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
+======= ==========================================================
      0  handshake OK; IEEE 1284 peripheral and mode available
     -1  handshake failed; peripheral not compliant (or none present)
      1  handshake OK; IEEE 1284 peripheral present but mode not
         available
+======= ==========================================================
 
 SEE ALSO
+^^^^^^^^
 
 parport_read, parport_write
-\f
+
+
+
 parport_read - read data from device
-------------
+------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-ssize_t parport_read (struct parport *, void *buf, size_t len);
+       ssize_t parport_read (struct parport *, void *buf, size_t len);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Read data from device in current IEEE 1284 transfer mode.  This only
 works for modes that support reverse data transfer.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 If negative, an error code; otherwise the number of bytes transferred.
 
 SEE ALSO
+^^^^^^^^
 
 parport_write, parport_negotiate
-\f
+
+
+
 parport_write - write data to device
--------------
+------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-ssize_t parport_write (struct parport *, const void *buf, size_t len);
+       ssize_t parport_write (struct parport *, const void *buf, size_t len);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Write data to device in current IEEE 1284 transfer mode.  This only
 works for modes that support forward data transfer.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 If negative, an error code; otherwise the number of bytes transferred.
 
 SEE ALSO
+^^^^^^^^
 
 parport_read, parport_negotiate
+
+
 \f
 parport_open - register device for particular device number
-------------
+-----------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct pardevice *parport_open (int devnum, const char *name,
-                               int (*pf) (void *),
-                               void (*kf) (void *),
-                               void (*irqf) (int, void *,
-                                             struct pt_regs *),
-                               int flags, void *handle);
+       #include <linux/parport.h>
+
+       struct pardevice *parport_open (int devnum, const char *name,
+                                       int (*pf) (void *),
+                                       void (*kf) (void *),
+                                       void (*irqf) (int, void *,
+                                                     struct pt_regs *),
+                                       int flags, void *handle);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 This is like parport_register_device but takes a device number instead
 of a pointer to a struct parport.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 See parport_register_device.  If no device is associated with devnum,
 NULL is returned.
 
 SEE ALSO
+^^^^^^^^
 
 parport_register_device
-\f
+
+
+
 parport_close - unregister device for particular device number
--------------
+--------------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-void parport_close (struct pardevice *dev);
+       void parport_close (struct pardevice *dev);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 This is the equivalent of parport_unregister_device for parport_open.
 
 SEE ALSO
+^^^^^^^^
 
 parport_unregister_device, parport_open
-\f
+
+
+
 parport_device_id - obtain IEEE 1284 Device ID
------------------
+----------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-ssize_t parport_device_id (int devnum, char *buffer, size_t len);
+       ssize_t parport_device_id (int devnum, char *buffer, size_t len);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Obtains the IEEE 1284 Device ID associated with a given device.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 If negative, an error code; otherwise, the number of bytes of buffer
 that contain the device ID.  The format of the device ID is as
-follows:
+follows::
 
-[length][ID]
+       [length][ID]
 
 The first two bytes indicate the inclusive length of the entire Device
 ID, and are in big-endian order.  The ID is a sequence of pairs of the
-form:
+form::
 
-key:value;
+       key:value;
 
 NOTES
+^^^^^
 
 Many devices have ill-formed IEEE 1284 Device IDs.
 
 SEE ALSO
+^^^^^^^^
 
 parport_find_class, parport_find_device
-\f
+
+
+
 parport_device_coords - convert device number to device coordinates
-------------------
+-------------------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-int parport_device_coords (int devnum, int *parport, int *mux,
-                          int *daisy);
+       int parport_device_coords (int devnum, int *parport, int *mux,
+                                  int *daisy);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Convert between device number (zero-based) and device coordinates
 (port, multiplexor, daisy chain address).
 
 RETURN VALUE
+^^^^^^^^^^^^
 
-Zero on success, in which case the coordinates are (*parport, *mux,
-*daisy).
+Zero on success, in which case the coordinates are (``*parport``, ``*mux``,
+``*daisy``).
 
 SEE ALSO
+^^^^^^^^
 
 parport_open, parport_device_id
-\f
+
+
+
 parport_find_class - find a device by its class
-------------------
+-----------------------------------------------
 
 SYNOPSIS
-
-#include <linux/parport.h>
-
-typedef enum {
-       PARPORT_CLASS_LEGACY = 0,       /* Non-IEEE1284 device */
-       PARPORT_CLASS_PRINTER,
-       PARPORT_CLASS_MODEM,
-       PARPORT_CLASS_NET,
-       PARPORT_CLASS_HDC,              /* Hard disk controller */
-       PARPORT_CLASS_PCMCIA,
-       PARPORT_CLASS_MEDIA,            /* Multimedia device */
-       PARPORT_CLASS_FDC,              /* Floppy disk controller */
-       PARPORT_CLASS_PORTS,
-       PARPORT_CLASS_SCANNER,
-       PARPORT_CLASS_DIGCAM,
-       PARPORT_CLASS_OTHER,            /* Anything else */
-       PARPORT_CLASS_UNSPEC,           /* No CLS field in ID */
-       PARPORT_CLASS_SCSIADAPTER
-} parport_device_class;
-
-int parport_find_class (parport_device_class cls, int from);
+^^^^^^^^
+
+::
+
+       #include <linux/parport.h>
+
+       typedef enum {
+               PARPORT_CLASS_LEGACY = 0,       /* Non-IEEE1284 device */
+               PARPORT_CLASS_PRINTER,
+               PARPORT_CLASS_MODEM,
+               PARPORT_CLASS_NET,
+               PARPORT_CLASS_HDC,              /* Hard disk controller */
+               PARPORT_CLASS_PCMCIA,
+               PARPORT_CLASS_MEDIA,            /* Multimedia device */
+               PARPORT_CLASS_FDC,              /* Floppy disk controller */
+               PARPORT_CLASS_PORTS,
+               PARPORT_CLASS_SCANNER,
+               PARPORT_CLASS_DIGCAM,
+               PARPORT_CLASS_OTHER,            /* Anything else */
+               PARPORT_CLASS_UNSPEC,           /* No CLS field in ID */
+               PARPORT_CLASS_SCSIADAPTER
+       } parport_device_class;
+
+       int parport_find_class (parport_device_class cls, int from);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Find a device by class.  The search starts from device number from+1.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 The device number of the next device in that class, or -1 if no such
 device exists.
 
 NOTES
+^^^^^
 
-Example usage:
+Example usage::
 
-int devnum = -1;
-while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM, devnum)) != -1) {
-    struct pardevice *dev = parport_open (devnum, ...);
-    ...
-}
+       int devnum = -1;
+       while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM, devnum)) != -1) {
+               struct pardevice *dev = parport_open (devnum, ...);
+               ...
+       }
 
 SEE ALSO
+^^^^^^^^
 
 parport_find_device, parport_open, parport_device_id
-\f
+
+
+
 parport_find_device - find a device by its class
-------------------
+------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-int parport_find_device (const char *mfg, const char *mdl, int from);
+       #include <linux/parport.h>
+
+       int parport_find_device (const char *mfg, const char *mdl, int from);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Find a device by vendor and model.  The search starts from device
 number from+1.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 The device number of the next device matching the specifications, or
 -1 if no such device exists.
 
 NOTES
+^^^^^
 
-Example usage:
+Example usage::
 
-int devnum = -1;
-while ((devnum = parport_find_device ("IOMEGA", "ZIP+", devnum)) != -1) {
-    struct pardevice *dev = parport_open (devnum, ...);
-    ...
-}
+       int devnum = -1;
+       while ((devnum = parport_find_device ("IOMEGA", "ZIP+", devnum)) != -1) {
+               struct pardevice *dev = parport_open (devnum, ...);
+               ...
+       }
 
 SEE ALSO
+^^^^^^^^
 
 parport_find_class, parport_open, parport_device_id
+
+
 \f
 parport_set_timeout - set the inactivity timeout
--------------------
+------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
+
+::
 
-#include <linux/parport.h>
+       #include <linux/parport.h>
 
-long parport_set_timeout (struct pardevice *dev, long inactivity);
+       long parport_set_timeout (struct pardevice *dev, long inactivity);
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Set the inactivity timeout, in jiffies, for a registered device.  The
 previous timeout is returned.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 The previous timeout, in jiffies.
 
 NOTES
+^^^^^
 
 Some of the port->ops functions for a parport may take time, owing to
 delays at the peripheral.  After the peripheral has not responded for
-'inactivity' jiffies, a timeout will occur and the blocking function
+``inactivity`` jiffies, a timeout will occur and the blocking function
 will return.
 
 A timeout of 0 jiffies is a special case: the function must do as much
@@ -932,29 +1135,37 @@ Once set for a registered device, the timeout will remain at the set
 value until set again.
 
 SEE ALSO
+^^^^^^^^
 
 port->ops->xxx_read/write_yyy
-\f
+
+
+
+
 PORT FUNCTIONS
---------------
+==============
 
 The functions in the port->ops structure (struct parport_operations)
 are provided by the low-level driver responsible for that port.
 
 port->ops->read_data - read the data register
---------------------
+---------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       unsigned char (*read_data) (struct parport *port);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               unsigned char (*read_data) (struct parport *port);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 If port->modes contains the PARPORT_MODE_TRISTATE flag and the
 PARPORT_CONTROL_DIRECTION bit in the control register is set, this
@@ -964,45 +1175,59 @@ not set, the return value _may_ be the last value written to the data
 register.  Otherwise the return value is undefined.
 
 SEE ALSO
+^^^^^^^^
 
 write_data, read_status, write_control
+
+
 \f
 port->ops->write_data - write the data register
----------------------
+-----------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       void (*write_data) (struct parport *port, unsigned char d);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               void (*write_data) (struct parport *port, unsigned char d);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Writes to the data register.  May have side-effects (a STROBE pulse,
 for instance).
 
 SEE ALSO
+^^^^^^^^
 
 read_data, read_status, write_control
+
+
 \f
 port->ops->read_status - read the status register
-----------------------
+-------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       unsigned char (*read_status) (struct parport *port);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               unsigned char (*read_status) (struct parport *port);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Reads from the status register.  This is a bitmask:
 
@@ -1015,76 +1240,98 @@ Reads from the status register.  This is a bitmask:
 There may be other bits set.
 
 SEE ALSO
+^^^^^^^^
 
 read_data, write_data, write_control
+
+
 \f
 port->ops->read_control - read the control register
------------------------
+---------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       unsigned char (*read_control) (struct parport *port);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               unsigned char (*read_control) (struct parport *port);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Returns the last value written to the control register (either from
 write_control or frob_control).  No port access is performed.
 
 SEE ALSO
+^^^^^^^^
 
 read_data, write_data, read_status, write_control
+
+
 \f
 port->ops->write_control - write the control register
-------------------------
+-----------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       void (*write_control) (struct parport *port, unsigned char s);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               void (*write_control) (struct parport *port, unsigned char s);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
-Writes to the control register. This is a bitmask:
-                          _______
-- PARPORT_CONTROL_STROBE (nStrobe)
-                          _______
-- PARPORT_CONTROL_AUTOFD (nAutoFd)
-                        _____
-- PARPORT_CONTROL_INIT (nInit)
-                          _________
-- PARPORT_CONTROL_SELECT (nSelectIn)
+Writes to the control register. This is a bitmask::
+
+                                 _______
+       - PARPORT_CONTROL_STROBE (nStrobe)
+                                 _______
+       - PARPORT_CONTROL_AUTOFD (nAutoFd)
+                               _____
+       - PARPORT_CONTROL_INIT (nInit)
+                                 _________
+       - PARPORT_CONTROL_SELECT (nSelectIn)
 
 SEE ALSO
+^^^^^^^^
 
 read_data, write_data, read_status, frob_control
+
+
 \f
 port->ops->frob_control - write control register bits
------------------------
+-----------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       unsigned char (*frob_control) (struct parport *port,
-                                      unsigned char mask,
-                                      unsigned char val);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               unsigned char (*frob_control) (struct parport *port,
+                                       unsigned char mask,
+                                       unsigned char val);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 This is equivalent to reading from the control register, masking out
 the bits in mask, exclusive-or'ing with the bits in val, and writing
@@ -1095,23 +1342,30 @@ of its contents is maintained, so frob_control is in fact only one
 port access.
 
 SEE ALSO
+^^^^^^^^
 
 read_data, write_data, read_status, write_control
+
+
 \f
 port->ops->enable_irq - enable interrupt generation
----------------------
+---------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       void (*enable_irq) (struct parport *port);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               void (*enable_irq) (struct parport *port);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 The parallel port hardware is instructed to generate interrupts at
 appropriate moments, although those moments are
@@ -1119,353 +1373,460 @@ architecture-specific.  For the PC architecture, interrupts are
 commonly generated on the rising edge of nAck.
 
 SEE ALSO
+^^^^^^^^
 
 disable_irq
+
+
 \f
 port->ops->disable_irq - disable interrupt generation
-----------------------
+-----------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       void (*disable_irq) (struct parport *port);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               void (*disable_irq) (struct parport *port);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 The parallel port hardware is instructed not to generate interrupts.
 The interrupt itself is not masked.
 
 SEE ALSO
+^^^^^^^^
 
 enable_irq
 \f
+
+
 port->ops->data_forward - enable data drivers
------------------------
+---------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       void (*data_forward) (struct parport *port);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               void (*data_forward) (struct parport *port);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Enables the data line drivers, for 8-bit host-to-peripheral
 communications.
 
 SEE ALSO
+^^^^^^^^
 
 data_reverse
+
+
 \f
 port->ops->data_reverse - tristate the buffer
------------------------
+---------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       void (*data_reverse) (struct parport *port);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               void (*data_reverse) (struct parport *port);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Places the data bus in a high impedance state, if port->modes has the
 PARPORT_MODE_TRISTATE bit set.
 
 SEE ALSO
+^^^^^^^^
 
 data_forward
-\f
+
+
+
 port->ops->epp_write_data - write EPP data
--------------------------
+------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       size_t (*epp_write_data) (struct parport *port, const void *buf,
-                                 size_t len, int flags);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               size_t (*epp_write_data) (struct parport *port, const void *buf,
+                                       size_t len, int flags);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Writes data in EPP mode, and returns the number of bytes written.
 
-The 'flags' parameter may be one or more of the following,
+The ``flags`` parameter may be one or more of the following,
 bitwise-or'ed together:
 
+======================= =================================================
 PARPORT_EPP_FAST       Use fast transfers. Some chips provide 16-bit and
                        32-bit registers.  However, if a transfer
                        times out, the return value may be unreliable.
+======================= =================================================
 
 SEE ALSO
+^^^^^^^^
 
 epp_read_data, epp_write_addr, epp_read_addr
+
+
 \f
 port->ops->epp_read_data - read EPP data
-------------------------
+----------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       size_t (*epp_read_data) (struct parport *port, void *buf,
-                                size_t len, int flags);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               size_t (*epp_read_data) (struct parport *port, void *buf,
+                                       size_t len, int flags);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Reads data in EPP mode, and returns the number of bytes read.
 
-The 'flags' parameter may be one or more of the following,
+The ``flags`` parameter may be one or more of the following,
 bitwise-or'ed together:
 
+======================= =================================================
 PARPORT_EPP_FAST       Use fast transfers. Some chips provide 16-bit and
                        32-bit registers.  However, if a transfer
                        times out, the return value may be unreliable.
+======================= =================================================
 
 SEE ALSO
+^^^^^^^^
 
 epp_write_data, epp_write_addr, epp_read_addr
-\f
+
+
+
 port->ops->epp_write_addr - write EPP address
--------------------------
+---------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       size_t (*epp_write_addr) (struct parport *port,
-                                 const void *buf, size_t len, int flags);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               size_t (*epp_write_addr) (struct parport *port,
+                                       const void *buf, size_t len, int flags);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Writes EPP addresses (8 bits each), and returns the number written.
 
-The 'flags' parameter may be one or more of the following,
+The ``flags`` parameter may be one or more of the following,
 bitwise-or'ed together:
 
+======================= =================================================
 PARPORT_EPP_FAST       Use fast transfers. Some chips provide 16-bit and
                        32-bit registers.  However, if a transfer
                        times out, the return value may be unreliable.
+======================= =================================================
 
 (Does PARPORT_EPP_FAST make sense for this function?)
 
 SEE ALSO
+^^^^^^^^
 
 epp_write_data, epp_read_data, epp_read_addr
+
+
 \f
 port->ops->epp_read_addr - read EPP address
-------------------------
+-------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       size_t (*epp_read_addr) (struct parport *port, void *buf,
-                                size_t len, int flags);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               size_t (*epp_read_addr) (struct parport *port, void *buf,
+                                       size_t len, int flags);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
 Reads EPP addresses (8 bits each), and returns the number read.
 
-The 'flags' parameter may be one or more of the following,
+The ``flags`` parameter may be one or more of the following,
 bitwise-or'ed together:
 
+======================= =================================================
 PARPORT_EPP_FAST       Use fast transfers. Some chips provide 16-bit and
                        32-bit registers.  However, if a transfer
                        times out, the return value may be unreliable.
+======================= =================================================
 
 (Does PARPORT_EPP_FAST make sense for this function?)
 
 SEE ALSO
+^^^^^^^^
 
 epp_write_data, epp_read_data, epp_write_addr
+
+
 \f
 port->ops->ecp_write_data - write a block of ECP data
--------------------------
+-----------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       size_t (*ecp_write_data) (struct parport *port,
-                                 const void *buf, size_t len, int flags);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               size_t (*ecp_write_data) (struct parport *port,
+                                       const void *buf, size_t len, int flags);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
-Writes a block of ECP data.  The 'flags' parameter is ignored.
+Writes a block of ECP data.  The ``flags`` parameter is ignored.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 The number of bytes written.
 
 SEE ALSO
+^^^^^^^^
 
 ecp_read_data, ecp_write_addr
 \f
+
+
 port->ops->ecp_read_data - read a block of ECP data
-------------------------
+---------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       size_t (*ecp_read_data) (struct parport *port,
-                                void *buf, size_t len, int flags);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               size_t (*ecp_read_data) (struct parport *port,
+                                       void *buf, size_t len, int flags);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
-Reads a block of ECP data.  The 'flags' parameter is ignored.
+Reads a block of ECP data.  The ``flags`` parameter is ignored.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 The number of bytes read.  NB. There may be more unread data in a
 FIFO.  Is there a way of stunning the FIFO to prevent this?
 
 SEE ALSO
+^^^^^^^^
 
 ecp_write_block, ecp_write_addr
-\f
+
+
+
 port->ops->ecp_write_addr - write a block of ECP addresses
--------------------------
+----------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       size_t (*ecp_write_addr) (struct parport *port,
-                                 const void *buf, size_t len, int flags);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               size_t (*ecp_write_addr) (struct parport *port,
+                                       const void *buf, size_t len, int flags);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
-Writes a block of ECP addresses.  The 'flags' parameter is ignored.
+Writes a block of ECP addresses.  The ``flags`` parameter is ignored.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 The number of bytes written.
 
 NOTES
+^^^^^
 
 This may use a FIFO, and if so shall not return until the FIFO is empty.
 
 SEE ALSO
+^^^^^^^^
 
 ecp_read_data, ecp_write_data
-\f
+
+
+
 port->ops->nibble_read_data - read a block of data in nibble mode
----------------------------
+-----------------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       size_t (*nibble_read_data) (struct parport *port,
-                                   void *buf, size_t len, int flags);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               size_t (*nibble_read_data) (struct parport *port,
+                                       void *buf, size_t len, int flags);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
-Reads a block of data in nibble mode.  The 'flags' parameter is ignored.
+Reads a block of data in nibble mode.  The ``flags`` parameter is ignored.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 The number of whole bytes read.
 
 SEE ALSO
+^^^^^^^^
 
 byte_read_data, compat_write_data
+
+
 \f
 port->ops->byte_read_data - read a block of data in byte mode
--------------------------
+-------------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       size_t (*byte_read_data) (struct parport *port,
-                                 void *buf, size_t len, int flags);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               size_t (*byte_read_data) (struct parport *port,
+                                       void *buf, size_t len, int flags);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
-Reads a block of data in byte mode.  The 'flags' parameter is ignored.
+Reads a block of data in byte mode.  The ``flags`` parameter is ignored.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 The number of bytes read.
 
 SEE ALSO
+^^^^^^^^
 
 nibble_read_data, compat_write_data
+
+
 \f
 port->ops->compat_write_data - write a block of data in compatibility mode
-----------------------------
+--------------------------------------------------------------------------
 
 SYNOPSIS
+^^^^^^^^
 
-#include <linux/parport.h>
+::
 
-struct parport_operations {
-       ...
-       size_t (*compat_write_data) (struct parport *port,
-                                    const void *buf, size_t len, int flags);
-       ...
-};
+       #include <linux/parport.h>
+
+       struct parport_operations {
+               ...
+               size_t (*compat_write_data) (struct parport *port,
+                                       const void *buf, size_t len, int flags);
+               ...
+       };
 
 DESCRIPTION
+^^^^^^^^^^^
 
-Writes a block of data in compatibility mode.  The 'flags' parameter
+Writes a block of data in compatibility mode.  The ``flags`` parameter
 is ignored.
 
 RETURN VALUE
+^^^^^^^^^^^^
 
 The number of bytes written.
 
 SEE ALSO
+^^^^^^^^
 
 nibble_read_data, byte_read_data
index 7d3c824..247de64 100644 (file)
@@ -1,5 +1,6 @@
+====================
 Percpu rw semaphores
---------------------
+====================
 
 Percpu rw semaphores is a new read-write semaphore design that is
 optimized for locking for reading.
index 383cdd8..457c3e0 100644 (file)
@@ -1,10 +1,14 @@
-                           PHY SUBSYSTEM
-                 Kishon Vijay Abraham I <kishon@ti.com>
+=============
+PHY subsystem
+=============
+
+:Author: Kishon Vijay Abraham I <kishon@ti.com>
 
 This document explains the Generic PHY Framework along with the APIs provided,
 and how-to-use.
 
-1. Introduction
+Introduction
+============
 
 *PHY* is the abbreviation for physical layer. It is used to connect a device
 to the physical medium e.g., the USB controller has a PHY to provide functions
@@ -21,7 +25,8 @@ better code maintainability.
 This framework will be of use only to devices that use external PHY (PHY
 functionality is not embedded within the controller).
 
-2. Registering/Unregistering the PHY provider
+Registering/Unregistering the PHY provider
+==========================================
 
 PHY provider refers to an entity that implements one or more PHY instances.
 For the simple case where the PHY provider implements only a single instance of
@@ -30,11 +35,14 @@ of_phy_simple_xlate. If the PHY provider implements multiple instances, it
 should provide its own implementation of of_xlate. of_xlate is used only for
 dt boot case.
 
-#define of_phy_provider_register(dev, xlate)    \
-        __of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate))
+::
+
+       #define of_phy_provider_register(dev, xlate)    \
+               __of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate))
 
-#define devm_of_phy_provider_register(dev, xlate)       \
-        __devm_of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate))
+       #define devm_of_phy_provider_register(dev, xlate)       \
+               __devm_of_phy_provider_register((dev), NULL, THIS_MODULE,
+                                               (xlate))
 
 of_phy_provider_register and devm_of_phy_provider_register macros can be used to
 register the phy_provider and it takes device and of_xlate as
@@ -47,28 +55,35 @@ nodes within extra levels for context and extensibility, in which case the low
 level of_phy_provider_register_full() and devm_of_phy_provider_register_full()
 macros can be used to override the node containing the children.
 
-#define of_phy_provider_register_full(dev, children, xlate) \
-       __of_phy_provider_register(dev, children, THIS_MODULE, xlate)
+::
+
+       #define of_phy_provider_register_full(dev, children, xlate) \
+               __of_phy_provider_register(dev, children, THIS_MODULE, xlate)
 
-#define devm_of_phy_provider_register_full(dev, children, xlate) \
-       __devm_of_phy_provider_register_full(dev, children, THIS_MODULE, xlate)
+       #define devm_of_phy_provider_register_full(dev, children, xlate) \
+               __devm_of_phy_provider_register_full(dev, children,
+                                                    THIS_MODULE, xlate)
 
-void devm_of_phy_provider_unregister(struct device *dev,
-       struct phy_provider *phy_provider);
-void of_phy_provider_unregister(struct phy_provider *phy_provider);
+       void devm_of_phy_provider_unregister(struct device *dev,
+               struct phy_provider *phy_provider);
+       void of_phy_provider_unregister(struct phy_provider *phy_provider);
 
 devm_of_phy_provider_unregister and of_phy_provider_unregister can be used to
 unregister the PHY.
 
-3. Creating the PHY
+Creating the PHY
+================
 
 The PHY driver should create the PHY in order for other peripheral controllers
 to make use of it. The PHY framework provides 2 APIs to create the PHY.
 
-struct phy *phy_create(struct device *dev, struct device_node *node,
-                      const struct phy_ops *ops);
-struct phy *devm_phy_create(struct device *dev, struct device_node *node,
-                           const struct phy_ops *ops);
+::
+
+       struct phy *phy_create(struct device *dev, struct device_node *node,
+                              const struct phy_ops *ops);
+       struct phy *devm_phy_create(struct device *dev,
+                                   struct device_node *node,
+                                   const struct phy_ops *ops);
 
 The PHY drivers can use one of the above 2 APIs to create the PHY by passing
 the device pointer and phy ops.
@@ -84,12 +99,16 @@ phy_ops to get back the private data.
 Before the controller can make use of the PHY, it has to get a reference to
 it. This framework provides the following APIs to get a reference to the PHY.
 
-struct phy *phy_get(struct device *dev, const char *string);
-struct phy *phy_optional_get(struct device *dev, const char *string);
-struct phy *devm_phy_get(struct device *dev, const char *string);
-struct phy *devm_phy_optional_get(struct device *dev, const char *string);
-struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
-                                    int index);
+::
+
+       struct phy *phy_get(struct device *dev, const char *string);
+       struct phy *phy_optional_get(struct device *dev, const char *string);
+       struct phy *devm_phy_get(struct device *dev, const char *string);
+       struct phy *devm_phy_optional_get(struct device *dev,
+                                         const char *string);
+       struct phy *devm_of_phy_get_by_index(struct device *dev,
+                                            struct device_node *np,
+                                            int index);
 
 phy_get, phy_optional_get, devm_phy_get and devm_phy_optional_get can
 be used to get the PHY. In the case of dt boot, the string arguments
@@ -111,30 +130,35 @@ the phy_init() and phy_exit() calls, and phy_power_on() and
 phy_power_off() calls are all NOP when applied to a NULL phy. The NULL
 phy is useful in devices for handling optional phy devices.
 
-5. Releasing a reference to the PHY
+Releasing a reference to the PHY
+================================
 
 When the controller no longer needs the PHY, it has to release the reference
 to the PHY it has obtained using the APIs mentioned in the above section. The
 PHY framework provides 2 APIs to release a reference to the PHY.
 
-void phy_put(struct phy *phy);
-void devm_phy_put(struct device *dev, struct phy *phy);
+::
+
+       void phy_put(struct phy *phy);
+       void devm_phy_put(struct device *dev, struct phy *phy);
 
 Both these APIs are used to release a reference to the PHY and devm_phy_put
 destroys the devres associated with this PHY.
 
-6. Destroying the PHY
+Destroying the PHY
+==================
 
 When the driver that created the PHY is unloaded, it should destroy the PHY it
-created using one of the following 2 APIs.
+created using one of the following 2 APIs::
 
-void phy_destroy(struct phy *phy);
-void devm_phy_destroy(struct device *dev, struct phy *phy);
+       void phy_destroy(struct phy *phy);
+       void devm_phy_destroy(struct device *dev, struct phy *phy);
 
 Both these APIs destroy the PHY and devm_phy_destroy destroys the devres
 associated with this PHY.
 
-7. PM Runtime
+PM Runtime
+==========
 
 This subsystem is pm runtime enabled. So while creating the PHY,
 pm_runtime_enable of the phy device created by this subsystem is called and
@@ -150,7 +174,8 @@ There are exported APIs like phy_pm_runtime_get, phy_pm_runtime_get_sync,
 phy_pm_runtime_put, phy_pm_runtime_put_sync, phy_pm_runtime_allow and
 phy_pm_runtime_forbid for performing PM operations.
 
-8. PHY Mappings
+PHY Mappings
+============
 
 In order to get reference to a PHY without help from DeviceTree, the framework
 offers lookups which can be compared to clkdev that allow clk structures to be
@@ -158,12 +183,15 @@ bound to devices. A lookup can be made be made during runtime when a handle to
 the struct phy already exists.
 
 The framework offers the following API for registering and unregistering the
-lookups.
+lookups::
 
-int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id);
-void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id);
+       int phy_create_lookup(struct phy *phy, const char *con_id,
+                             const char *dev_id);
+       void phy_remove_lookup(struct phy *phy, const char *con_id,
+                              const char *dev_id);
 
-9. DeviceTree Binding
+DeviceTree Binding
+==================
 
 The documentation for PHY dt binding can be found @
 Documentation/devicetree/bindings/phy/phy-bindings.txt
index 9a5bc86..aafddbe 100644 (file)
@@ -1,5 +1,6 @@
+======================
 Lightweight PI-futexes
-----------------------
+======================
 
 We are calling them lightweight for 3 reasons:
 
@@ -25,8 +26,8 @@ determinism and well-bound latencies. Even in the worst-case, PI will
 improve the statistical distribution of locking related application
 delays.
 
-The longer reply:
------------------
+The longer reply
+----------------
 
 Firstly, sharing locks between multiple tasks is a common programming
 technique that often cannot be replaced with lockless algorithms. As we
@@ -71,8 +72,8 @@ deterministic execution of the high-prio task: any medium-priority task
 could preempt the low-prio task while it holds the shared lock and
 executes the critical section, and could delay it indefinitely.
 
-Implementation:
----------------
+Implementation
+--------------
 
 As mentioned before, the userspace fastpath of PI-enabled pthread
 mutexes involves no kernel work at all - they behave quite similarly to
@@ -83,8 +84,8 @@ entering the kernel.
 
 To handle the slowpath, we have added two new futex ops:
 
-  FUTEX_LOCK_PI
-  FUTEX_UNLOCK_PI
+  FUTEX_LOCK_PI
+  FUTEX_UNLOCK_PI
 
 If the lock-acquire fastpath fails, [i.e. an atomic transition from 0 to
 TID fails], then FUTEX_LOCK_PI is called. The kernel does all the
index 763e465..bab2d10 100644 (file)
+=================================
 Linux Plug and Play Documentation
-by Adam Belay <ambx1@neo.rr.com>
-last updated: Oct. 16, 2002
----------------------------------------------------------------------------------------
+=================================
 
+:Author: Adam Belay <ambx1@neo.rr.com>
+:Last updated: Oct. 16, 2002
 
 
 Overview
 --------
-       Plug and Play provides a means of detecting and setting resources for legacy or
+
+Plug and Play provides a means of detecting and setting resources for legacy or
 otherwise unconfigurable devices.  The Linux Plug and Play Layer provides these 
 services to compatible drivers.
 
 
-
 The User Interface
 ------------------
-       The Linux Plug and Play user interface provides a means to activate PnP devices
+
+The Linux Plug and Play user interface provides a means to activate PnP devices
 for legacy and user level drivers that do not support Linux Plug and Play.  The 
 user interface is integrated into sysfs.
 
 In addition to the standard sysfs file the following are created in each
 device's directory:
-id - displays a list of support EISA IDs
-options - displays possible resource configurations
-resources - displays currently allocated resources and allows resource changes
+id - displays a list of support EISA IDs
+options - displays possible resource configurations
+resources - displays currently allocated resources and allows resource changes
 
--activating a device
+activating a device
+^^^^^^^^^^^^^^^^^^^
 
-#echo "auto" > resources
+::
+
+       # echo "auto" > resources
 
 this will invoke the automatic resource config system to activate the device
 
--manually activating a device
+manually activating a device
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+       # echo "manual <depnum> <mode>" > resources
 
-#echo "manual <depnum> <mode>" > resources
-<depnum> - the configuration number
-<mode> - static or dynamic
-               static = for next boot
-               dynamic = now
+       <depnum> - the configuration number
+       <mode> - static or dynamic
+                static = for next boot
+                dynamic = now
 
--disabling a device
+disabling a device
+^^^^^^^^^^^^^^^^^^
 
-#echo "disable" > resources
+::
+
+       # echo "disable" > resources
 
 
 EXAMPLE:
 
 Suppose you need to activate the floppy disk controller.
-1.) change to the proper directory, in my case it is 
-/driver/bus/pnp/devices/00:0f
-# cd /driver/bus/pnp/devices/00:0f
-# cat name
-PC standard floppy disk controller
-
-2.) check if the device is already active
-# cat resources
-DISABLED
-
-- Notice the string "DISABLED".  This means the device is not active.
-
-3.) check the device's possible configurations (optional)
-# cat options
-Dependent: 01 - Priority acceptable
-    port 0x3f0-0x3f0, align 0x7, size 0x6, 16-bit address decoding
-    port 0x3f7-0x3f7, align 0x0, size 0x1, 16-bit address decoding
-    irq 6
-    dma 2 8-bit compatible
-Dependent: 02 - Priority acceptable
-    port 0x370-0x370, align 0x7, size 0x6, 16-bit address decoding
-    port 0x377-0x377, align 0x0, size 0x1, 16-bit address decoding
-    irq 6
-    dma 2 8-bit compatible
-
-4.) now activate the device
-# echo "auto" > resources
-
-5.) finally check if the device is active
-# cat resources
-io 0x3f0-0x3f5
-io 0x3f7-0x3f7
-irq 6
-dma 2
-
-also there are a series of kernel parameters:
-pnp_reserve_irq=irq1[,irq2] ....
-pnp_reserve_dma=dma1[,dma2] ....
-pnp_reserve_io=io1,size1[,io2,size2] ....
-pnp_reserve_mem=mem1,size1[,mem2,size2] ....
+
+1. change to the proper directory, in my case it is
+   /driver/bus/pnp/devices/00:0f::
+
+       # cd /driver/bus/pnp/devices/00:0f
+       # cat name
+       PC standard floppy disk controller
+
+2. check if the device is already active::
+
+       # cat resources
+       DISABLED
+
+  - Notice the string "DISABLED".  This means the device is not active.
+
+3. check the device's possible configurations (optional)::
+
+       # cat options
+       Dependent: 01 - Priority acceptable
+           port 0x3f0-0x3f0, align 0x7, size 0x6, 16-bit address decoding
+           port 0x3f7-0x3f7, align 0x0, size 0x1, 16-bit address decoding
+           irq 6
+           dma 2 8-bit compatible
+       Dependent: 02 - Priority acceptable
+           port 0x370-0x370, align 0x7, size 0x6, 16-bit address decoding
+           port 0x377-0x377, align 0x0, size 0x1, 16-bit address decoding
+           irq 6
+           dma 2 8-bit compatible
+
+4. now activate the device::
+
+       # echo "auto" > resources
+
+5. finally check if the device is active::
+
+       # cat resources
+       io 0x3f0-0x3f5
+       io 0x3f7-0x3f7
+       irq 6
+       dma 2
+
+also there are a series of kernel parameters::
+
+       pnp_reserve_irq=irq1[,irq2] ....
+       pnp_reserve_dma=dma1[,dma2] ....
+       pnp_reserve_io=io1,size1[,io2,size2] ....
+       pnp_reserve_mem=mem1,size1[,mem2,size2] ....
 
 
 
 The Unified Plug and Play Layer
 -------------------------------
-       All Plug and Play drivers, protocols, and services meet at a central location 
+
+All Plug and Play drivers, protocols, and services meet at a central location
 called the Plug and Play Layer.  This layer is responsible for the exchange of 
 information between PnP drivers and PnP protocols.  Thus it automatically 
 forwards commands to the proper protocol.  This makes writing PnP drivers 
@@ -101,64 +121,73 @@ significantly easier.
 The following functions are available from the Plug and Play Layer:
 
 pnp_get_protocol
-- increments the number of uses by one
+  increments the number of uses by one
 
 pnp_put_protocol
-- deincrements the number of uses by one
+  deincrements the number of uses by one
 
 pnp_register_protocol
-- use this to register a new PnP protocol
+  use this to register a new PnP protocol
 
 pnp_unregister_protocol
-- use this function to remove a PnP protocol from the Plug and Play Layer
+  use this function to remove a PnP protocol from the Plug and Play Layer
 
 pnp_register_driver
-- adds a PnP driver to the Plug and Play Layer
-- this includes driver model integration
-- returns zero for success or a negative error number for failure; count
+  adds a PnP driver to the Plug and Play Layer
+
+  this includes driver model integration
+  returns zero for success or a negative error number for failure; count
   calls to the .add() method if you need to know how many devices bind to
   the driver
 
 pnp_unregister_driver
-- removes a PnP driver from the Plug and Play Layer
+  removes a PnP driver from the Plug and Play Layer
 
 
 
 Plug and Play Protocols
 -----------------------
-       This section contains information for PnP protocol developers.
+
+This section contains information for PnP protocol developers.
 
 The following Protocols are currently available in the computing world:
-- PNPBIOS: used for system devices such as serial and parallel ports.
-- ISAPNP: provides PnP support for the ISA bus
-- ACPI: among its many uses, ACPI provides information about system level 
-devices.
+
+- PNPBIOS:
+    used for system devices such as serial and parallel ports.
+- ISAPNP:
+    provides PnP support for the ISA bus
+- ACPI:
+    among its many uses, ACPI provides information about system level
+    devices.
+
 It is meant to replace the PNPBIOS.  It is not currently supported by Linux
 Plug and Play but it is planned to be in the near future.
 
 
 Requirements for a Linux PnP protocol:
-1.) the protocol must use EISA IDs
-2.) the protocol must inform the PnP Layer of a device's current configuration
+1. the protocol must use EISA IDs
+2. the protocol must inform the PnP Layer of a device's current configuration
+
 - the ability to set resources is optional but preferred.
 
 The following are PnP protocol related functions:
 
 pnp_add_device
-- use this function to add a PnP device to the PnP layer
-- only call this function when all wanted values are set in the pnp_dev 
-structure
+  use this function to add a PnP device to the PnP layer
+
+  only call this function when all wanted values are set in the pnp_dev
+  structure
 
 pnp_init_device
-- call this to initialize the PnP structure
+  call this to initialize the PnP structure
 
 pnp_remove_device
-- call this to remove a device from the Plug and Play Layer.
-- it will fail if the device is still in use.
-- automatically will free mem used by the device and related structures
+  call this to remove a device from the Plug and Play Layer.
+  it will fail if the device is still in use.
+  automatically will free mem used by the device and related structures
 
 pnp_add_id
-- adds an EISA ID to the list of supported IDs for the specified device
+  adds an EISA ID to the list of supported IDs for the specified device
 
 For more information consult the source of a protocol such as
 /drivers/pnp/pnpbios/core.c.
@@ -167,85 +196,97 @@ For more information consult the source of a protocol such as
 
 Linux Plug and Play Drivers
 ---------------------------
-       This section contains information for Linux PnP driver developers.
+
+This section contains information for Linux PnP driver developers.
 
 The New Way
-...........
-1.) first make a list of supported EISA IDS
-ex:
-static const struct pnp_id pnp_dev_table[] = {
-       /* Standard LPT Printer Port */
-       {.id = "PNP0400", .driver_data = 0},
-       /* ECP Printer Port */
-       {.id = "PNP0401", .driver_data = 0},
-       {.id = ""}
-};
-
-Please note that the character 'X' can be used as a wild card in the function
-portion (last four characters).
-ex:
+^^^^^^^^^^^
+
+1. first make a list of supported EISA IDS
+
+   ex::
+
+       static const struct pnp_id pnp_dev_table[] = {
+               /* Standard LPT Printer Port */
+               {.id = "PNP0400", .driver_data = 0},
+               /* ECP Printer Port */
+               {.id = "PNP0401", .driver_data = 0},
+               {.id = ""}
+       };
+
+   Please note that the character 'X' can be used as a wild card in the function
+   portion (last four characters).
+
+   ex::
+
        /* Unknown PnP modems */
        {       "PNPCXXX",              UNKNOWN_DEV     },
 
-Supported PnP card IDs can optionally be defined.
-ex:
-static const struct pnp_id pnp_card_table[] = {
-       {       "ANYDEVS",              0       },
-       {       "",                     0       }
-};
-
-2.) Optionally define probe and remove functions.  It may make sense not to 
-define these functions if the driver already has a reliable method of detecting
-the resources, such as the parport_pc driver.
-ex:
-static int
-serial_pnp_probe(struct pnp_dev * dev, const struct pnp_id *card_id, const 
-                 struct pnp_id *dev_id)
-{
-. . .
-
-ex:
-static void serial_pnp_remove(struct pnp_dev * dev)
-{
-. . .
-
-consult /drivers/serial/8250_pnp.c for more information.
-
-3.) create a driver structure
-ex:
-
-static struct pnp_driver serial_pnp_driver = {
-       .name           = "serial",
-       .card_id_table  = pnp_card_table,
-       .id_table       = pnp_dev_table,
-       .probe          = serial_pnp_probe,
-       .remove         = serial_pnp_remove,
-};
-
-* name and id_table cannot be NULL.
-
-4.) register the driver
-ex:
-
-static int __init serial8250_pnp_init(void)
-{
-       return pnp_register_driver(&serial_pnp_driver);
-}
+   Supported PnP card IDs can optionally be defined.
+   ex::
+
+       static const struct pnp_id pnp_card_table[] = {
+               {       "ANYDEVS",              0       },
+               {       "",                     0       }
+       };
+
+2. Optionally define probe and remove functions.  It may make sense not to
+   define these functions if the driver already has a reliable method of detecting
+   the resources, such as the parport_pc driver.
+
+   ex::
+
+       static int
+       serial_pnp_probe(struct pnp_dev * dev, const struct pnp_id *card_id, const
+                       struct pnp_id *dev_id)
+       {
+       . . .
+
+   ex::
+
+       static void serial_pnp_remove(struct pnp_dev * dev)
+       {
+       . . .
+
+   consult /drivers/serial/8250_pnp.c for more information.
+
+3. create a driver structure
+
+   ex::
+
+       static struct pnp_driver serial_pnp_driver = {
+               .name           = "serial",
+               .card_id_table  = pnp_card_table,
+               .id_table       = pnp_dev_table,
+               .probe          = serial_pnp_probe,
+               .remove         = serial_pnp_remove,
+       };
+
+   * name and id_table cannot be NULL.
+
+4. register the driver
+
+   ex::
+
+       static int __init serial8250_pnp_init(void)
+       {
+               return pnp_register_driver(&serial_pnp_driver);
+       }
 
 The Old Way
-...........
+^^^^^^^^^^^
 
 A series of compatibility functions have been created to make it easy to convert
 ISAPNP drivers.  They should serve as a temporary solution only.
 
-They are as follows:
+They are as follows::
 
-struct pnp_card *pnp_find_card(unsigned short vendor,
-                                unsigned short device,
-                                struct pnp_card *from)
+       struct pnp_card *pnp_find_card(unsigned short vendor,
+                                      unsigned short device,
+                                      struct pnp_card *from)
 
-struct pnp_dev *pnp_find_dev(struct pnp_card *card,
-                               unsigned short vendor,
-                               unsigned short function,
-                               struct pnp_dev *from)
+       struct pnp_dev *pnp_find_dev(struct pnp_card *card,
+                                    unsigned short vendor,
+                                    unsigned short function,
+                                    struct pnp_dev *from)
 
index e89ce66..c945062 100644 (file)
@@ -1,10 +1,13 @@
-                 Proper Locking Under a Preemptible Kernel:
-                      Keeping Kernel Code Preempt-Safe
-                        Robert Love <rml@tech9.net>
-                         Last Updated: 28 Aug 2002
+===========================================================================
+Proper Locking Under a Preemptible Kernel: Keeping Kernel Code Preempt-Safe
+===========================================================================
 
+:Author: Robert Love <rml@tech9.net>
+:Last Updated: 28 Aug 2002
 
-INTRODUCTION
+
+Introduction
+============
 
 
 A preemptible kernel creates new locking issues.  The issues are the same as
@@ -17,9 +20,10 @@ requires protecting these situations.
  
 
 RULE #1: Per-CPU data structures need explicit protection
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 
-Two similar problems arise. An example code snippet:
+Two similar problems arise. An example code snippet::
 
        struct this_needs_locking tux[NR_CPUS];
        tux[smp_processor_id()] = some_value;
@@ -35,6 +39,7 @@ You can also use put_cpu() and get_cpu(), which will disable preemption.
 
 
 RULE #2: CPU state must be protected.
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 
 Under preemption, the state of the CPU must be protected.  This is arch-
@@ -52,6 +57,7 @@ However, fpu__restore() must be called with preemption disabled.
 
 
 RULE #3: Lock acquire and release must be performed by same task
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 
 A lock acquired in one task must be released by the same task.  This
@@ -61,17 +67,20 @@ like this, acquire and release the task in the same code path and
 have the caller wait on an event by the other task.
 
 
-SOLUTION
+Solution
+========
 
 
 Data protection under preemption is achieved by disabling preemption for the
 duration of the critical region.
 
-preempt_enable()               decrement the preempt counter
-preempt_disable()              increment the preempt counter
-preempt_enable_no_resched()    decrement, but do not immediately preempt
-preempt_check_resched()                if needed, reschedule
-preempt_count()                        return the preempt counter
+::
+
+  preempt_enable()             decrement the preempt counter
+  preempt_disable()            increment the preempt counter
+  preempt_enable_no_resched()  decrement, but do not immediately preempt
+  preempt_check_resched()      if needed, reschedule
+  preempt_count()              return the preempt counter
 
 The functions are nestable.  In other words, you can call preempt_disable
 n-times in a code path, and preemption will not be reenabled until the n-th
@@ -89,7 +98,7 @@ So use this implicit preemption-disabling property only if you know that the
 affected codepath does not do any of this. Best policy is to use this only for
 small, atomic code that you wrote and which calls no complex functions.
 
-Example:
+Example::
 
        cpucache_t *cc; /* this is per-CPU */
        preempt_disable();
@@ -102,7 +111,7 @@ Example:
        return 0;
 
 Notice how the preemption statements must encompass every reference of the
-critical variables.  Another example:
+critical variables.  Another example::
 
        int buf[NR_CPUS];
        set_cpu_val(buf);
@@ -114,7 +123,8 @@ This code is not preempt-safe, but see how easily we can fix it by simply
 moving the spin_lock up two lines.
 
 
-PREVENTING PREEMPTION USING INTERRUPT DISABLING
+Preventing preemption using interrupt disabling
+===============================================
 
 
 It is possible to prevent a preemption event using local_irq_disable and
index 619cdff..65ea591 100644 (file)
@@ -1,5 +1,18 @@
-If variable is of Type,                use printk format specifier:
----------------------------------------------------------
+=========================================
+How to get printk format specifiers right
+=========================================
+
+:Author: Randy Dunlap <rdunlap@infradead.org>
+:Author: Andrew Murray <amurray@mpc-data.co.uk>
+
+
+Integer types
+=============
+
+::
+
+       If variable is of Type,         use printk format specifier:
+       ------------------------------------------------------------
                int                     %d or %x
                unsigned int            %u or %x
                long                    %ld or %lx
@@ -13,25 +26,29 @@ If variable is of Type,             use printk format specifier:
                s64                     %lld or %llx
                u64                     %llu or %llx
 
-If <type> is dependent on a config option for its size (e.g., sector_t,
-blkcnt_t) or is architecture-dependent for its size (e.g., tcflag_t), use a
-format specifier of its largest possible type and explicitly cast to it.
-Example:
+If <type> is dependent on a config option for its size (e.g., ``sector_t``,
+``blkcnt_t``) or is architecture-dependent for its size (e.g., ``tcflag_t``),
+use a format specifier of its largest possible type and explicitly cast to it.
+
+Example::
 
        printk("test: sector number/total blocks: %llu/%llu\n",
                (unsigned long long)sector, (unsigned long long)blockcount);
 
-Reminder: sizeof() result is of type size_t.
+Reminder: ``sizeof()`` result is of type ``size_t``.
 
-The kernel's printf does not support %n. For obvious reasons, floating
-point formats (%e, %f, %g, %a) are also not recognized. Use of any
+The kernel's printf does not support ``%n``. For obvious reasons, floating
+point formats (``%e, %f, %g, %a``) are also not recognized. Use of any
 unsupported specifier or length qualifier results in a WARN and early
 return from vsnprintf.
 
 Raw pointer value SHOULD be printed with %p. The kernel supports
 the following extended format specifiers for pointer types:
 
-Symbols/Function Pointers:
+Symbols/Function Pointers
+=========================
+
+::
 
        %pF     versatile_init+0x0/0x110
        %pf     versatile_init
@@ -41,99 +58,122 @@ Symbols/Function Pointers:
        %ps     versatile_init
        %pB     prev_fn_of_versatile_init+0x88/0x88
 
-       For printing symbols and function pointers. The 'S' and 's' specifiers
-       result in the symbol name with ('S') or without ('s') offsets. Where
-       this is used on a kernel without KALLSYMS - the symbol address is
-       printed instead.
+For printing symbols and function pointers. The ``S`` and ``s`` specifiers
+result in the symbol name with (``S``) or without (``s``) offsets. Where
+this is used on a kernel without KALLSYMS - the symbol address is
+printed instead.
+
+The ``B`` specifier results in the symbol name with offsets and should be
+used when printing stack backtraces. The specifier takes into
+consideration the effect of compiler optimisations which may occur
+when tail-call``s are used and marked with the noreturn GCC attribute.
 
-       The 'B' specifier results in the symbol name with offsets and should be
-       used when printing stack backtraces. The specifier takes into
-       consideration the effect of compiler optimisations which may occur
-       when tail-call's are used and marked with the noreturn GCC attribute.
+On ia64, ppc64 and parisc64 architectures function pointers are
+actually function descriptors which must first be resolved. The ``F`` and
+``f`` specifiers perform this resolution and then provide the same
+functionality as the ``S`` and ``s`` specifiers.
 
-       On ia64, ppc64 and parisc64 architectures function pointers are
-       actually function descriptors which must first be resolved. The 'F' and
-       'f' specifiers perform this resolution and then provide the same
-       functionality as the 'S' and 's' specifiers.
+Kernel Pointers
+===============
 
-Kernel Pointers:
+::
 
        %pK     0x01234567 or 0x0123456789abcdef
 
-       For printing kernel pointers which should be hidden from unprivileged
-       users. The behaviour of %pK depends on the kptr_restrict sysctl - see
-       Documentation/sysctl/kernel.txt for more details.
+For printing kernel pointers which should be hidden from unprivileged
+users. The behaviour of ``%pK`` depends on the ``kptr_restrict sysctl`` - see
+Documentation/sysctl/kernel.txt for more details.
+
+Struct Resources
+================
 
-Struct Resources:
+::
 
        %pr     [mem 0x60000000-0x6fffffff flags 0x2200] or
                [mem 0x0000000060000000-0x000000006fffffff flags 0x2200]
        %pR     [mem 0x60000000-0x6fffffff pref] or
                [mem 0x0000000060000000-0x000000006fffffff pref]
 
-       For printing struct resources. The 'R' and 'r' specifiers result in a
-       printed resource with ('R') or without ('r') a decoded flags member.
-       Passed by reference.
+For printing struct resources. The ``R`` and ``r`` specifiers result in a
+printed resource with (``R``) or without (``r``) a decoded flags member.
+Passed by reference.
+
+Physical addresses types ``phys_addr_t``
+========================================
 
-Physical addresses types phys_addr_t:
+::
 
        %pa[p]  0x01234567 or 0x0123456789abcdef
 
-       For printing a phys_addr_t type (and its derivatives, such as
-       resource_size_t) which can vary based on build options, regardless of
-       the width of the CPU data path. Passed by reference.
+For printing a ``phys_addr_t`` type (and its derivatives, such as
+``resource_size_t``) which can vary based on build options, regardless of
+the width of the CPU data path. Passed by reference.
 
-DMA addresses types dma_addr_t:
+DMA addresses types ``dma_addr_t``
+==================================
+
+::
 
        %pad    0x01234567 or 0x0123456789abcdef
 
-       For printing a dma_addr_t type which can vary based on build options,
-       regardless of the width of the CPU data path. Passed by reference.
+For printing a ``dma_addr_t`` type which can vary based on build options,
+regardless of the width of the CPU data path. Passed by reference.
+
+Raw buffer as an escaped string
+===============================
 
-Raw buffer as an escaped string:
+::
 
        %*pE[achnops]
 
-       For printing raw buffer as an escaped string. For the following buffer
+For printing raw buffer as an escaped string. For the following buffer::
 
                1b 62 20 5c 43 07 22 90 0d 5d
 
-       few examples show how the conversion would be done (the result string
-       without surrounding quotes):
+few examples show how the conversion would be done (the result string
+without surrounding quotes)::
 
                %*pE            "\eb \C\a"\220\r]"
                %*pEhp          "\x1bb \C\x07"\x90\x0d]"
                %*pEa           "\e\142\040\\\103\a\042\220\r\135"
 
-       The conversion rules are applied according to an optional combination
-       of flags (see string_escape_mem() kernel documentation for the
-       details):
-               a - ESCAPE_ANY
-               c - ESCAPE_SPECIAL
-               h - ESCAPE_HEX
-               n - ESCAPE_NULL
-               o - ESCAPE_OCTAL
-               p - ESCAPE_NP
-               s - ESCAPE_SPACE
-       By default ESCAPE_ANY_NP is used.
+The conversion rules are applied according to an optional combination
+of flags (see :c:func:`string_escape_mem` kernel documentation for the
+details):
+
+       - ``a`` - ESCAPE_ANY
+       - ``c`` - ESCAPE_SPECIAL
+       - ``h`` - ESCAPE_HEX
+       - ``n`` - ESCAPE_NULL
+       - ``o`` - ESCAPE_OCTAL
+       - ``p`` - ESCAPE_NP
+       - ``s`` - ESCAPE_SPACE
 
-       ESCAPE_ANY_NP is the sane choice for many cases, in particularly for
-       printing SSIDs.
+By default ESCAPE_ANY_NP is used.
 
-       If field width is omitted the 1 byte only will be escaped.
+ESCAPE_ANY_NP is the sane choice for many cases, in particularly for
+printing SSIDs.
 
-Raw buffer as a hex string:
+If field width is omitted the 1 byte only will be escaped.
+
+Raw buffer as a hex string
+==========================
+
+::
 
        %*ph    00 01 02  ...  3f
        %*phC   00:01:02: ... :3f
        %*phD   00-01-02- ... -3f
        %*phN   000102 ... 3f
 
-       For printing a small buffers (up to 64 bytes long) as a hex string with
-       certain separator. For the larger buffers consider to use
-       print_hex_dump().
+For printing a small buffers (up to 64 bytes long) as a hex string with
+certain separator. For the larger buffers consider to use
+:c:func:`print_hex_dump`.
+
+MAC/FDDI addresses
+==================
 
-MAC/FDDI addresses:
+::
 
        %pM     00:01:02:03:04:05
        %pMR    05:04:03:02:01:00
@@ -141,53 +181,62 @@ MAC/FDDI addresses:
        %pm     000102030405
        %pmR    050403020100
 
-       For printing 6-byte MAC/FDDI addresses in hex notation. The 'M' and 'm'
-       specifiers result in a printed address with ('M') or without ('m') byte
-       separators. The default byte separator is the colon (':').
+For printing 6-byte MAC/FDDI addresses in hex notation. The ``M`` and ``m``
+specifiers result in a printed address with (``M``) or without (``m``) byte
+separators. The default byte separator is the colon (``:``).
 
-       Where FDDI addresses are concerned the 'F' specifier can be used after
-       the 'M' specifier to use dash ('-') separators instead of the default
-       separator.
+Where FDDI addresses are concerned the ``F`` specifier can be used after
+the ``M`` specifier to use dash (``-``) separators instead of the default
+separator.
 
-       For Bluetooth addresses the 'R' specifier shall be used after the 'M'
-       specifier to use reversed byte order suitable for visual interpretation
-       of Bluetooth addresses which are in the little endian order.
+For Bluetooth addresses the ``R`` specifier shall be used after the ``M``
+specifier to use reversed byte order suitable for visual interpretation
+of Bluetooth addresses which are in the little endian order.
 
-       Passed by reference.
+Passed by reference.
+
+IPv4 addresses
+==============
 
-IPv4 addresses:
+::
 
        %pI4    1.2.3.4
        %pi4    001.002.003.004
        %p[Ii]4[hnbl]
 
-       For printing IPv4 dot-separated decimal addresses. The 'I4' and 'i4'
-       specifiers result in a printed address with ('i4') or without ('I4')
-       leading zeros.
+For printing IPv4 dot-separated decimal addresses. The ``I4`` and ``i4``
+specifiers result in a printed address with (``i4``) or without (``I4``)
+leading zeros.
 
-       The additional 'h', 'n', 'b', and 'l' specifiers are used to specify
-       host, network, big or little endian order addresses respectively. Where
-       no specifier is provided the default network/big endian order is used.
+The additional ``h``, ``n``, ``b``, and ``l`` specifiers are used to specify
+host, network, big or little endian order addresses respectively. Where
+no specifier is provided the default network/big endian order is used.
 
-       Passed by reference.
+Passed by reference.
 
-IPv6 addresses:
+IPv6 addresses
+==============
+
+::
 
        %pI6    0001:0002:0003:0004:0005:0006:0007:0008
        %pi6    00010002000300040005000600070008
        %pI6c   1:2:3:4:5:6:7:8
 
-       For printing IPv6 network-order 16-bit hex addresses. The 'I6' and 'i6'
-       specifiers result in a printed address with ('I6') or without ('i6')
-       colon-separators. Leading zeros are always used.
+For printing IPv6 network-order 16-bit hex addresses. The ``I6`` and ``i6``
+specifiers result in a printed address with (``I6``) or without (``i6``)
+colon-separators. Leading zeros are always used.
 
-       The additional 'c' specifier can be used with the 'I' specifier to
-       print a compressed IPv6 address as described by
-       http://tools.ietf.org/html/rfc5952
+The additional ``c`` specifier can be used with the ``I`` specifier to
+print a compressed IPv6 address as described by
+http://tools.ietf.org/html/rfc5952
 
-       Passed by reference.
+Passed by reference.
 
-IPv4/IPv6 addresses (generic, with port, flowinfo, scope):
+IPv4/IPv6 addresses (generic, with port, flowinfo, scope)
+=========================================================
+
+::
 
        %pIS    1.2.3.4         or 0001:0002:0003:0004:0005:0006:0007:0008
        %piS    001.002.003.004 or 00010002000300040005000600070008
@@ -195,87 +244,103 @@ IPv4/IPv6 addresses (generic, with port, flowinfo, scope):
        %pISpc  1.2.3.4:12345   or [1:2:3:4:5:6:7:8]:12345
        %p[Ii]S[pfschnbl]
 
-       For printing an IP address without the need to distinguish whether it's
-       of type AF_INET or AF_INET6, a pointer to a valid 'struct sockaddr',
-       specified through 'IS' or 'iS', can be passed to this format specifier.
+For printing an IP address without the need to distinguish whether it``s
+of type AF_INET or AF_INET6, a pointer to a valid ``struct sockaddr``,
+specified through ``IS`` or ``iS``, can be passed to this format specifier.
 
-       The additional 'p', 'f', and 's' specifiers are used to specify port
-       (IPv4, IPv6), flowinfo (IPv6) and scope (IPv6). Ports have a ':' prefix,
-       flowinfo a '/' and scope a '%', each followed by the actual value.
+The additional ``p``, ``f``, and ``s`` specifiers are used to specify port
+(IPv4, IPv6), flowinfo (IPv6) and scope (IPv6). Ports have a ``:`` prefix,
+flowinfo a ``/`` and scope a ``%``, each followed by the actual value.
 
-       In case of an IPv6 address the compressed IPv6 address as described by
-       http://tools.ietf.org/html/rfc5952 is being used if the additional
-       specifier 'c' is given. The IPv6 address is surrounded by '[', ']' in
-       case of additional specifiers 'p', 'f' or 's' as suggested by
-       https://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-07
+In case of an IPv6 address the compressed IPv6 address as described by
+http://tools.ietf.org/html/rfc5952 is being used if the additional
+specifier ``c`` is given. The IPv6 address is surrounded by ``[``, ``]`` in
+case of additional specifiers ``p``, ``f`` or ``s`` as suggested by
+https://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-07
 
-       In case of IPv4 addresses, the additional 'h', 'n', 'b', and 'l'
-       specifiers can be used as well and are ignored in case of an IPv6
-       address.
+In case of IPv4 addresses, the additional ``h``, ``n``, ``b``, and ``l``
+specifiers can be used as well and are ignored in case of an IPv6
+address.
 
-       Passed by reference.
+Passed by reference.
 
-       Further examples:
+Further examples::
 
        %pISfc          1.2.3.4         or [1:2:3:4:5:6:7:8]/123456789
        %pISsc          1.2.3.4         or [1:2:3:4:5:6:7:8]%1234567890
        %pISpfc         1.2.3.4:12345   or [1:2:3:4:5:6:7:8]:12345/123456789
 
-UUID/GUID addresses:
+UUID/GUID addresses
+===================
+
+::
 
        %pUb    00010203-0405-0607-0809-0a0b0c0d0e0f
        %pUB    00010203-0405-0607-0809-0A0B0C0D0E0F
        %pUl    03020100-0504-0706-0809-0a0b0c0e0e0f
        %pUL    03020100-0504-0706-0809-0A0B0C0E0E0F
 
-       For printing 16-byte UUID/GUIDs addresses. The additional 'l', 'L',
-       'b' and 'B' specifiers are used to specify a little endian order in
-       lower ('l') or upper case ('L') hex characters - and big endian order
-       in lower ('b') or upper case ('B') hex characters.
+For printing 16-byte UUID/GUIDs addresses. The additional 'l', 'L',
+'b' and 'B' specifiers are used to specify a little endian order in
+lower ('l') or upper case ('L') hex characters - and big endian order
+in lower ('b') or upper case ('B') hex characters.
 
-       Where no additional specifiers are used the default big endian
-       order with lower case hex characters will be printed.
+Where no additional specifiers are used the default big endian
+order with lower case hex characters will be printed.
 
-       Passed by reference.
+Passed by reference.
+
+dentry names
+============
 
-dentry names:
+::
 
        %pd{,2,3,4}
        %pD{,2,3,4}
 
-       For printing dentry name; if we race with d_move(), the name might be
-       a mix of old and new ones, but it won't oops.  %pd dentry is a safer
-       equivalent of %s dentry->d_name.name we used to use, %pd<n> prints
-       n last components.  %pD does the same thing for struct file.
+For printing dentry name; if we race with :c:func:`d_move`, the name might be
+a mix of old and new ones, but it won't oops.  ``%pd`` dentry is a safer
+equivalent of ``%s`` ``dentry->d_name.name`` we used to use, ``%pd<n>`` prints
+``n`` last components.  ``%pD`` does the same thing for struct file.
 
-       Passed by reference.
+Passed by reference.
 
-block_device names:
+block_device names
+==================
+
+::
 
        %pg     sda, sda1 or loop0p1
 
-       For printing name of block_device pointers.
+For printing name of block_device pointers.
+
+struct va_format
+================
 
-struct va_format:
+::
 
        %pV
 
-       For printing struct va_format structures. These contain a format string
-       and va_list as follows:
+For printing struct va_format structures. These contain a format string
+and va_list as follows::
 
        struct va_format {
                const char *fmt;
                va_list *va;
        };
 
-       Implements a "recursive vsnprintf".
+Implements a "recursive vsnprintf".
 
-       Do not use this feature without some mechanism to verify the
-       correctness of the format string and va_list arguments.
+Do not use this feature without some mechanism to verify the
+correctness of the format string and va_list arguments.
 
-       Passed by reference.
+Passed by reference.
+
+kobjects
+========
+
+::
 
-kobjects:
        %pO
 
        Base specifier for kobject based structs. Must be followed with
@@ -311,61 +376,70 @@ kobjects:
 
        Passed by reference.
 
-struct clk:
+
+struct clk
+==========
+
+::
 
        %pC     pll1
        %pCn    pll1
        %pCr    1560000000
 
-       For printing struct clk structures. '%pC' and '%pCn' print the name
-       (Common Clock Framework) or address (legacy clock framework) of the
-       structure; '%pCr' prints the current clock rate.
+For printing struct clk structures. ``%pC`` and ``%pCn`` print the name
+(Common Clock Framework) or address (legacy clock framework) of the
+structure; ``%pCr`` prints the current clock rate.
 
-       Passed by reference.
+Passed by reference.
 
-bitmap and its derivatives such as cpumask and nodemask:
+bitmap and its derivatives such as cpumask and nodemask
+=======================================================
+
+::
 
        %*pb    0779
        %*pbl   0,3-6,8-10
 
-       For printing bitmap and its derivatives such as cpumask and nodemask,
-       %*pb output the bitmap with field width as the number of bits and %*pbl
-       output the bitmap as range list with field width as the number of bits.
+For printing bitmap and its derivatives such as cpumask and nodemask,
+``%*pb`` output the bitmap with field width as the number of bits and ``%*pbl``
+output the bitmap as range list with field width as the number of bits.
 
-       Passed by reference.
+Passed by reference.
+
+Flags bitfields such as page flags, gfp_flags
+=============================================
 
-Flags bitfields such as page flags, gfp_flags:
+::
 
        %pGp    referenced|uptodate|lru|active|private
        %pGg    GFP_USER|GFP_DMA32|GFP_NOWARN
        %pGv    read|exec|mayread|maywrite|mayexec|denywrite
 
-       For printing flags bitfields as a collection of symbolic constants that
-       would construct the value. The type of flags is given by the third
-       character. Currently supported are [p]age flags, [v]ma_flags (both
-       expect unsigned long *) and [g]fp_flags (expects gfp_t *). The flag
-       names and print order depends on the particular type.
+For printing flags bitfields as a collection of symbolic constants that
+would construct the value. The type of flags is given by the third
+character. Currently supported are [p]age flags, [v]ma_flags (both
+expect ``unsigned long *``) and [g]fp_flags (expects ``gfp_t *``). The flag
+names and print order depends on the particular        type.
 
-       Note that this format should not be used directly in TP_printk() part
-       of a tracepoint. Instead, use the show_*_flags() functions from
-       <trace/events/mmflags.h>.
+Note that this format should not be used directly in :c:func:`TP_printk()` part
+of a tracepoint. Instead, use the ``show_*_flags()`` functions from
+<trace/events/mmflags.h>.
 
-       Passed by reference.
+Passed by reference.
+
+Network device features
+=======================
 
-Network device features:
+::
 
        %pNF    0x000000000000c000
 
-       For printing netdev_features_t.
+For printing netdev_features_t.
 
-       Passed by reference.
+Passed by reference.
 
-If you add other %p extensions, please extend lib/test_printf.c with
+If you add other ``%p`` extensions, please extend lib/test_printf.c with
 one or more test cases, if at all feasible.
 
 
 Thank you for your cooperation and attention.
-
-
-By Randy Dunlap <rdunlap@infradead.org> and
-Andrew Murray <amurray@mpc-data.co.uk>
index 789b27c..8fbf0aa 100644 (file)
@@ -1,4 +1,6 @@
+======================================
 Pulse Width Modulation (PWM) interface
+======================================
 
 This provides an overview about the Linux PWM interface
 
@@ -16,7 +18,7 @@ Users of the legacy PWM API use unique IDs to refer to PWM devices.
 
 Instead of referring to a PWM device via its unique ID, board setup code
 should instead register a static mapping that can be used to match PWM
-consumers to providers, as given in the following example:
+consumers to providers, as given in the following example::
 
        static struct pwm_lookup board_pwm_lookup[] = {
                PWM_LOOKUP("tegra-pwm", 0, "pwm-backlight", NULL,
@@ -40,9 +42,9 @@ New users should use the pwm_get() function and pass to it the consumer
 device or a consumer name. pwm_put() is used to free the PWM device. Managed
 variants of these functions, devm_pwm_get() and devm_pwm_put(), also exist.
 
-After being requested, a PWM has to be configured using:
+After being requested, a PWM has to be configured using::
 
-int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state);
+       int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state);
 
 This API controls both the PWM period/duty_cycle config and the
 enable/disable state.
@@ -72,11 +74,14 @@ interface is provided to use the PWMs from userspace. It is exposed at
 pwmchipN, where N is the base of the PWM chip. Inside the directory you
 will find:
 
-npwm - The number of PWM channels this chip supports (read-only).
+  npwm
+    The number of PWM channels this chip supports (read-only).
 
-export - Exports a PWM channel for use with sysfs (write-only).
+  export
+    Exports a PWM channel for use with sysfs (write-only).
 
-unexport - Unexports a PWM channel from sysfs (write-only).
+  unexport
+   Unexports a PWM channel from sysfs (write-only).
 
 The PWM channels are numbered using a per-chip index from 0 to npwm-1.
 
@@ -84,21 +89,26 @@ When a PWM channel is exported a pwmX directory will be created in the
 pwmchipN directory it is associated with, where X is the number of the
 channel that was exported. The following properties will then be available:
 
-period - The total period of the PWM signal (read/write).
-       Value is in nanoseconds and is the sum of the active and inactive
-       time of the PWM.
+  period
+    The total period of the PWM signal (read/write).
+    Value is in nanoseconds and is the sum of the active and inactive
+    time of the PWM.
 
-duty_cycle - The active time of the PWM signal (read/write).
-       Value is in nanoseconds and must be less than the period.
+  duty_cycle
+    The active time of the PWM signal (read/write).
+    Value is in nanoseconds and must be less than the period.
 
-polarity - Changes the polarity of the PWM signal (read/write).
-       Writes to this property only work if the PWM chip supports changing
-       the polarity. The polarity can only be changed if the PWM is not
-       enabled. Value is the string "normal" or "inversed".
+  polarity
+    Changes the polarity of the PWM signal (read/write).
+    Writes to this property only work if the PWM chip supports changing
+    the polarity. The polarity can only be changed if the PWM is not
+    enabled. Value is the string "normal" or "inversed".
 
-enable - Enable/disable the PWM signal (read/write).
-       0 - disabled
-       1 - enabled
+  enable
+    Enable/disable the PWM signal (read/write).
+
+       - 0 - disabled
+       - 1 - enabled
 
 Implementing a PWM driver
 -------------------------
index b9d9cc5..b8a8c70 100644 (file)
@@ -1,7 +1,10 @@
+=================================
 Red-black Trees (rbtree) in Linux
-January 18, 2007
-Rob Landley <rob@landley.net>
-=============================
+=================================
+
+
+:Date: January 18, 2007
+:Author: Rob Landley <rob@landley.net>
 
 What are red-black trees, and what are they for?
 ------------------------------------------------
@@ -56,7 +59,7 @@ user of the rbtree code.
 Creating a new rbtree
 ---------------------
 
-Data nodes in an rbtree tree are structures containing a struct rb_node member:
+Data nodes in an rbtree tree are structures containing a struct rb_node member::
 
   struct mytype {
        struct rb_node node;
@@ -78,7 +81,7 @@ Searching for a value in an rbtree
 Writing a search function for your tree is fairly straightforward: start at the
 root, compare each value, and follow the left or right branch as necessary.
 
-Example:
+Example::
 
   struct mytype *my_search(struct rb_root *root, char *string)
   {
@@ -110,7 +113,7 @@ The search for insertion differs from the previous search by finding the
 location of the pointer on which to graft the new node.  The new node also
 needs a link to its parent node for rebalancing purposes.
 
-Example:
+Example::
 
   int my_insert(struct rb_root *root, struct mytype *data)
   {
@@ -140,11 +143,11 @@ Example:
 Removing or replacing existing data in an rbtree
 ------------------------------------------------
 
-To remove an existing node from a tree, call:
+To remove an existing node from a tree, call::
 
   void rb_erase(struct rb_node *victim, struct rb_root *tree);
 
-Example:
+Example::
 
   struct mytype *data = mysearch(&mytree, "walrus");
 
@@ -153,7 +156,7 @@ Example:
        myfree(data);
   }
 
-To replace an existing node in a tree with a new one with the same key, call:
+To replace an existing node in a tree with a new one with the same key, call::
 
   void rb_replace_node(struct rb_node *old, struct rb_node *new,
                        struct rb_root *tree);
@@ -166,7 +169,7 @@ Iterating through the elements stored in an rbtree (in sort order)
 
 Four functions are provided for iterating through an rbtree's contents in
 sorted order.  These work on arbitrary trees, and should not need to be
-modified or wrapped (except for locking purposes):
+modified or wrapped (except for locking purposes)::
 
   struct rb_node *rb_first(struct rb_root *tree);
   struct rb_node *rb_last(struct rb_root *tree);
@@ -184,7 +187,7 @@ which the containing data structure may be accessed with the container_of()
 macro, and individual members may be accessed directly via
 rb_entry(node, type, member).
 
-Example:
+Example::
 
   struct rb_node *node;
   for (node = rb_first(&mytree); node; node = rb_next(node))
@@ -241,7 +244,8 @@ user should have a single rb_erase_augmented() call site in order to limit
 compiled code size.
 
 
-Sample usage:
+Sample usage
+^^^^^^^^^^^^
 
 Interval tree is an example of augmented rb tree. Reference -
 "Introduction to Algorithms" by Cormen, Leiserson, Rivest and Stein.
@@ -259,12 +263,12 @@ This "extra information" stored in each node is the maximum hi
 information can be maintained at each node just be looking at the node
 and its immediate children. And this will be used in O(log n) lookup
 for lowest match (lowest start address among all possible matches)
-with something like:
+with something like::
 
-struct interval_tree_node *
-interval_tree_first_match(struct rb_root *root,
-                         unsigned long start, unsigned long last)
-{
+  struct interval_tree_node *
+  interval_tree_first_match(struct rb_root *root,
+                           unsigned long start, unsigned long last)
+  {
        struct interval_tree_node *node;
 
        if (!root->rb_node)
@@ -301,13 +305,13 @@ interval_tree_first_match(struct rb_root *root,
                }
                return NULL;    /* No match */
        }
-}
+  }
 
-Insertion/removal are defined using the following augmented callbacks:
+Insertion/removal are defined using the following augmented callbacks::
 
-static inline unsigned long
-compute_subtree_last(struct interval_tree_node *node)
-{
+  static inline unsigned long
+  compute_subtree_last(struct interval_tree_node *node)
+  {
        unsigned long max = node->last, subtree_last;
        if (node->rb.rb_left) {
                subtree_last = rb_entry(node->rb.rb_left,
@@ -322,10 +326,10 @@ compute_subtree_last(struct interval_tree_node *node)
                        max = subtree_last;
        }
        return max;
-}
+  }
 
-static void augment_propagate(struct rb_node *rb, struct rb_node *stop)
-{
+  static void augment_propagate(struct rb_node *rb, struct rb_node *stop)
+  {
        while (rb != stop) {
                struct interval_tree_node *node =
                        rb_entry(rb, struct interval_tree_node, rb);
@@ -335,20 +339,20 @@ static void augment_propagate(struct rb_node *rb, struct rb_node *stop)
                node->__subtree_last = subtree_last;
                rb = rb_parent(&node->rb);
        }
-}
+  }
 
-static void augment_copy(struct rb_node *rb_old, struct rb_node *rb_new)
-{
+  static void augment_copy(struct rb_node *rb_old, struct rb_node *rb_new)
+  {
        struct interval_tree_node *old =
                rb_entry(rb_old, struct interval_tree_node, rb);
        struct interval_tree_node *new =
                rb_entry(rb_new, struct interval_tree_node, rb);
 
        new->__subtree_last = old->__subtree_last;
-}
+  }
 
-static void augment_rotate(struct rb_node *rb_old, struct rb_node *rb_new)
-{
+  static void augment_rotate(struct rb_node *rb_old, struct rb_node *rb_new)
+  {
        struct interval_tree_node *old =
                rb_entry(rb_old, struct interval_tree_node, rb);
        struct interval_tree_node *new =
@@ -356,15 +360,15 @@ static void augment_rotate(struct rb_node *rb_old, struct rb_node *rb_new)
 
        new->__subtree_last = old->__subtree_last;
        old->__subtree_last = compute_subtree_last(old);
-}
+  }
 
-static const struct rb_augment_callbacks augment_callbacks = {
+  static const struct rb_augment_callbacks augment_callbacks = {
        augment_propagate, augment_copy, augment_rotate
-};
+  };
 
-void interval_tree_insert(struct interval_tree_node *node,
-                         struct rb_root *root)
-{
+  void interval_tree_insert(struct interval_tree_node *node,
+                           struct rb_root *root)
+  {
        struct rb_node **link = &root->rb_node, *rb_parent = NULL;
        unsigned long start = node->start, last = node->last;
        struct interval_tree_node *parent;
@@ -383,10 +387,10 @@ void interval_tree_insert(struct interval_tree_node *node,
        node->__subtree_last = last;
        rb_link_node(&node->rb, rb_parent, link);
        rb_insert_augmented(&node->rb, root, &augment_callbacks);
-}
+  }
 
-void interval_tree_remove(struct interval_tree_node *node,
-                         struct rb_root *root)
-{
+  void interval_tree_remove(struct interval_tree_node *node,
+                           struct rb_root *root)
+  {
        rb_erase_augmented(&node->rb, root, &augment_callbacks);
-}
+  }
index f075974..77fb03a 100644 (file)
@@ -1,6 +1,9 @@
+==========================
 Remote Processor Framework
+==========================
 
-1. Introduction
+Introduction
+============
 
 Modern SoCs typically have heterogeneous remote processor devices in asymmetric
 multiprocessing (AMP) configurations, which may be running different instances
@@ -26,44 +29,62 @@ remoteproc will add those devices. This makes it possible to reuse the
 existing virtio drivers with remote processor backends at a minimal development
 cost.
 
-2. User API
+User API
+========
+
+::
 
   int rproc_boot(struct rproc *rproc)
-    - Boot a remote processor (i.e. load its firmware, power it on, ...).
-      If the remote processor is already powered on, this function immediately
-      returns (successfully).
-      Returns 0 on success, and an appropriate error value otherwise.
-      Note: to use this function you should already have a valid rproc
-      handle. There are several ways to achieve that cleanly (devres, pdata,
-      the way remoteproc_rpmsg.c does this, or, if this becomes prevalent, we
-      might also consider using dev_archdata for this).
+
+Boot a remote processor (i.e. load its firmware, power it on, ...).
+
+If the remote processor is already powered on, this function immediately
+returns (successfully).
+
+Returns 0 on success, and an appropriate error value otherwise.
+Note: to use this function you should already have a valid rproc
+handle. There are several ways to achieve that cleanly (devres, pdata,
+the way remoteproc_rpmsg.c does this, or, if this becomes prevalent, we
+might also consider using dev_archdata for this).
+
+::
 
   void rproc_shutdown(struct rproc *rproc)
-    - Power off a remote processor (previously booted with rproc_boot()).
-      In case @rproc is still being used by an additional user(s), then
-      this function will just decrement the power refcount and exit,
-      without really powering off the device.
-      Every call to rproc_boot() must (eventually) be accompanied by a call
-      to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug.
-      Notes:
-      - we're not decrementing the rproc's refcount, only the power refcount.
-        which means that the @rproc handle stays valid even after
-        rproc_shutdown() returns, and users can still use it with a subsequent
-        rproc_boot(), if needed.
+
+Power off a remote processor (previously booted with rproc_boot()).
+In case @rproc is still being used by an additional user(s), then
+this function will just decrement the power refcount and exit,
+without really powering off the device.
+
+Every call to rproc_boot() must (eventually) be accompanied by a call
+to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug.
+
+.. note::
+
+  we're not decrementing the rproc's refcount, only the power refcount.
+  which means that the @rproc handle stays valid even after
+  rproc_shutdown() returns, and users can still use it with a subsequent
+  rproc_boot(), if needed.
+
+::
 
   struct rproc *rproc_get_by_phandle(phandle phandle)
-    - Find an rproc handle using a device tree phandle. Returns the rproc
-      handle on success, and NULL on failure. This function increments
-      the remote processor's refcount, so always use rproc_put() to
-      decrement it back once rproc isn't needed anymore.
 
-3. Typical usage
+Find an rproc handle using a device tree phandle. Returns the rproc
+handle on success, and NULL on failure. This function increments
+the remote processor's refcount, so always use rproc_put() to
+decrement it back once rproc isn't needed anymore.
+
+Typical usage
+=============
 
-#include <linux/remoteproc.h>
+::
 
-/* in case we were given a valid 'rproc' handle */
-int dummy_rproc_example(struct rproc *my_rproc)
-{
+  #include <linux/remoteproc.h>
+
+  /* in case we were given a valid 'rproc' handle */
+  int dummy_rproc_example(struct rproc *my_rproc)
+  {
        int ret;
 
        /* let's power on and boot our remote processor */
@@ -80,84 +101,111 @@ int dummy_rproc_example(struct rproc *my_rproc)
 
        /* let's shut it down now */
        rproc_shutdown(my_rproc);
-}
+  }
+
+API for implementors
+====================
 
-4. API for implementors
+::
 
   struct rproc *rproc_alloc(struct device *dev, const char *name,
                                const struct rproc_ops *ops,
                                const char *firmware, int len)
-    - Allocate a new remote processor handle, but don't register
-      it yet. Required parameters are the underlying device, the
-      name of this remote processor, platform-specific ops handlers,
-      the name of the firmware to boot this rproc with, and the
-      length of private data needed by the allocating rproc driver (in bytes).
-
-      This function should be used by rproc implementations during
-      initialization of the remote processor.
-      After creating an rproc handle using this function, and when ready,
-      implementations should then call rproc_add() to complete
-      the registration of the remote processor.
-      On success, the new rproc is returned, and on failure, NULL.
-
-      Note: _never_ directly deallocate @rproc, even if it was not registered
-      yet. Instead, when you need to unroll rproc_alloc(), use rproc_free().
+
+Allocate a new remote processor handle, but don't register
+it yet. Required parameters are the underlying device, the
+name of this remote processor, platform-specific ops handlers,
+the name of the firmware to boot this rproc with, and the
+length of private data needed by the allocating rproc driver (in bytes).
+
+This function should be used by rproc implementations during
+initialization of the remote processor.
+
+After creating an rproc handle using this function, and when ready,
+implementations should then call rproc_add() to complete
+the registration of the remote processor.
+
+On success, the new rproc is returned, and on failure, NULL.
+
+.. note::
+
+  **never** directly deallocate @rproc, even if it was not registered
+  yet. Instead, when you need to unroll rproc_alloc(), use rproc_free().
+
+::
 
   void rproc_free(struct rproc *rproc)
-    - Free an rproc handle that was allocated by rproc_alloc.
-      This function essentially unrolls rproc_alloc(), by decrementing the
-      rproc's refcount. It doesn't directly free rproc; that would happen
-      only if there are no other references to rproc and its refcount now
-      dropped to zero.
+
+Free an rproc handle that was allocated by rproc_alloc.
+
+This function essentially unrolls rproc_alloc(), by decrementing the
+rproc's refcount. It doesn't directly free rproc; that would happen
+only if there are no other references to rproc and its refcount now
+dropped to zero.
+
+::
 
   int rproc_add(struct rproc *rproc)
-    - Register @rproc with the remoteproc framework, after it has been
-      allocated with rproc_alloc().
-      This is called by the platform-specific rproc implementation, whenever
-      a new remote processor device is probed.
-      Returns 0 on success and an appropriate error code otherwise.
-      Note: this function initiates an asynchronous firmware loading
-      context, which will look for virtio devices supported by the rproc's
-      firmware.
-      If found, those virtio devices will be created and added, so as a result
-      of registering this remote processor, additional virtio drivers might get
-      probed.
+
+Register @rproc with the remoteproc framework, after it has been
+allocated with rproc_alloc().
+
+This is called by the platform-specific rproc implementation, whenever
+a new remote processor device is probed.
+
+Returns 0 on success and an appropriate error code otherwise.
+Note: this function initiates an asynchronous firmware loading
+context, which will look for virtio devices supported by the rproc's
+firmware.
+
+If found, those virtio devices will be created and added, so as a result
+of registering this remote processor, additional virtio drivers might get
+probed.
+
+::
 
   int rproc_del(struct rproc *rproc)
-    - Unroll rproc_add().
-      This function should be called when the platform specific rproc
-      implementation decides to remove the rproc device. it should
-      _only_ be called if a previous invocation of rproc_add()
-      has completed successfully.
 
-      After rproc_del() returns, @rproc is still valid, and its
-      last refcount should be decremented by calling rproc_free().
+Unroll rproc_add().
+
+This function should be called when the platform specific rproc
+implementation decides to remove the rproc device. it should
+_only_ be called if a previous invocation of rproc_add()
+has completed successfully.
 
-      Returns 0 on success and -EINVAL if @rproc isn't valid.
+After rproc_del() returns, @rproc is still valid, and its
+last refcount should be decremented by calling rproc_free().
+
+Returns 0 on success and -EINVAL if @rproc isn't valid.
+
+::
 
   void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
-    - Report a crash in a remoteproc
-      This function must be called every time a crash is detected by the
-      platform specific rproc implementation. This should not be called from a
-      non-remoteproc driver. This function can be called from atomic/interrupt
-      context.
 
-5. Implementation callbacks
+Report a crash in a remoteproc
+
+This function must be called every time a crash is detected by the
+platform specific rproc implementation. This should not be called from a
+non-remoteproc driver. This function can be called from atomic/interrupt
+context.
+
+Implementation callbacks
+========================
 
 These callbacks should be provided by platform-specific remoteproc
-drivers:
-
-/**
- * struct rproc_ops - platform-specific device handlers
* @start:     power on the device and boot it
* @stop:      power off the device
* @kick:      kick a virtqueue (virtqueue id given as a parameter)
- */
-struct rproc_ops {
+drivers::
+
+  /**
  * struct rproc_ops - platform-specific device handlers
  * @start:   power on the device and boot it
  * @stop:    power off the device
  * @kick:    kick a virtqueue (virtqueue id given as a parameter)
  */
+  struct rproc_ops {
        int (*start)(struct rproc *rproc);
        int (*stop)(struct rproc *rproc);
        void (*kick)(struct rproc *rproc, int vqid);
-};
+  };
 
 Every remoteproc implementation should at least provide the ->start and ->stop
 handlers. If rpmsg/virtio functionality is also desired, then the ->kick handler
@@ -179,7 +227,8 @@ the exact virtqueue index to look in is optional: it is easy (and not
 too expensive) to go through the existing virtqueues and look for new buffers
 in the used rings.
 
-6. Binary Firmware Structure
+Binary Firmware Structure
+=========================
 
 At this point remoteproc only supports ELF32 firmware binaries. However,
 it is quite expected that other platforms/devices which we'd want to
@@ -207,43 +256,43 @@ resource entries that publish the existence of supported features
 or configurations by the remote processor, such as trace buffers and
 supported virtio devices (and their configurations).
 
-The resource table begins with this header:
-
-/**
- * struct resource_table - firmware resource table header
- * @ver: version number
- * @num: number of resource entries
- * @reserved: reserved (must be zero)
- * @offset: array of offsets pointing at the various resource entries
- *
- * The header of the resource table, as expressed by this structure,
- * contains a version number (should we need to change this format in the
- * future), the number of available resource entries, and their offsets
- * in the table.
- */
-struct resource_table {
+The resource table begins with this header::
+
+  /**
  * struct resource_table - firmware resource table header
  * @ver: version number
  * @num: number of resource entries
  * @reserved: reserved (must be zero)
  * @offset: array of offsets pointing at the various resource entries
  *
  * The header of the resource table, as expressed by this structure,
  * contains a version number (should we need to change this format in the
  * future), the number of available resource entries, and their offsets
  * in the table.
  */
+  struct resource_table {
        u32 ver;
        u32 num;
        u32 reserved[2];
        u32 offset[0];
-} __packed;
+  } __packed;
 
 Immediately following this header are the resource entries themselves,
-each of which begins with the following resource entry header:
-
-/**
- * struct fw_rsc_hdr - firmware resource entry header
- * @type: resource type
- * @data: resource data
- *
- * Every resource entry begins with a 'struct fw_rsc_hdr' header providing
- * its @type. The content of the entry itself will immediately follow
- * this header, and it should be parsed according to the resource type.
- */
-struct fw_rsc_hdr {
+each of which begins with the following resource entry header::
+
+  /**
  * struct fw_rsc_hdr - firmware resource entry header
  * @type: resource type
  * @data: resource data
  *
  * Every resource entry begins with a 'struct fw_rsc_hdr' header providing
  * its @type. The content of the entry itself will immediately follow
  * this header, and it should be parsed according to the resource type.
  */
+  struct fw_rsc_hdr {
        u32 type;
        u8 data[0];
-} __packed;
+  } __packed;
 
 Some resources entries are mere announcements, where the host is informed
 of specific remoteproc configuration. Other entries require the host to
@@ -252,32 +301,32 @@ is expected, where the firmware requests a resource, and once allocated,
 the host should provide back its details (e.g. address of an allocated
 memory region).
 
-Here are the various resource types that are currently supported:
-
-/**
- * enum fw_resource_type - types of resource entries
- *
- * @RSC_CARVEOUT:   request for allocation of a physically contiguous
*                 memory region.
- * @RSC_DEVMEM:     request to iommu_map a memory-based peripheral.
* @RSC_TRACE:     announces the availability of a trace buffer into which
*                 the remote processor will be writing logs.
- * @RSC_VDEV:       declare support for a virtio device, and serve as its
*                 virtio header.
- * @RSC_LAST:       just keep this one at the end
- *
- * Please note that these values are used as indices to the rproc_handle_rsc
- * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to
- * check the validity of an index before the lookup table is accessed, so
- * please update it as needed.
- */
-enum fw_resource_type {
+Here are the various resource types that are currently supported::
+
+  /**
  * enum fw_resource_type - types of resource entries
  *
  * @RSC_CARVEOUT:   request for allocation of a physically contiguous
  *               memory region.
  * @RSC_DEVMEM:     request to iommu_map a memory-based peripheral.
  * @RSC_TRACE:           announces the availability of a trace buffer into which
  *               the remote processor will be writing logs.
  * @RSC_VDEV:       declare support for a virtio device, and serve as its
  *               virtio header.
  * @RSC_LAST:       just keep this one at the end
  *
  * Please note that these values are used as indices to the rproc_handle_rsc
  * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to
  * check the validity of an index before the lookup table is accessed, so
  * please update it as needed.
  */
+  enum fw_resource_type {
        RSC_CARVEOUT    = 0,
        RSC_DEVMEM      = 1,
        RSC_TRACE       = 2,
        RSC_VDEV        = 3,
        RSC_LAST        = 4,
-};
+  };
 
 For more details regarding a specific resource type, please see its
 dedicated structure in include/linux/remoteproc.h.
@@ -286,7 +335,8 @@ We also expect that platform-specific resource entries will show up
 at some point. When that happens, we could easily add a new RSC_PLATFORM
 type, and hand those resources to the platform-specific rproc driver to handle.
 
-7. Virtio and remoteproc
+Virtio and remoteproc
+=====================
 
 The firmware should provide remoteproc information about virtio devices
 that it supports, and their configurations: a RSC_VDEV resource entry
index 8c17406..a289285 100644 (file)
@@ -1,13 +1,13 @@
+===============================
 rfkill - RF kill switch support
 ===============================
 
-1. Introduction
-2. Implementation details
-3. Kernel API
-4. Userspace support
 
+.. contents::
+   :depth: 2
 
-1. Introduction
+Introduction
+============
 
 The rfkill subsystem provides a generic interface to disabling any radio
 transmitter in the system. When a transmitter is blocked, it shall not
@@ -21,17 +21,24 @@ aircraft.
 The rfkill subsystem has a concept of "hard" and "soft" block, which
 differ little in their meaning (block == transmitters off) but rather in
 whether they can be changed or not:
- - hard block: read-only radio block that cannot be overridden by software
- - soft block: writable radio block (need not be readable) that is set by
-               the system software.
+
+ - hard block
+       read-only radio block that cannot be overridden by software
+
+ - soft block
+       writable radio block (need not be readable) that is set by
+        the system software.
 
 The rfkill subsystem has two parameters, rfkill.default_state and
-rfkill.master_switch_mode, which are documented in admin-guide/kernel-parameters.rst.
+rfkill.master_switch_mode, which are documented in
+admin-guide/kernel-parameters.rst.
 
 
-2. Implementation details
+Implementation details
+======================
 
 The rfkill subsystem is composed of three main components:
+
  * the rfkill core,
  * the deprecated rfkill-input module (an input layer handler, being
    replaced by userspace policy code) and
@@ -55,7 +62,8 @@ use the return value of rfkill_set_hw_state() unless the hardware actually
 keeps track of soft and hard block separately.
 
 
-3. Kernel API
+Kernel API
+==========
 
 
 Drivers for radio transmitters normally implement an rfkill driver.
@@ -69,7 +77,7 @@ For some platforms, it is possible that the hardware state changes during
 suspend/hibernation, in which case it will be necessary to update the rfkill
 core with the current state is at resume time.
 
-To create an rfkill driver, driver's Kconfig needs to have
+To create an rfkill driver, driver's Kconfig needs to have::
 
        depends on RFKILL || !RFKILL
 
@@ -87,7 +95,8 @@ RFKill provides per-switch LED triggers, which can be used to drive LEDs
 according to the switch state (LED_FULL when blocked, LED_OFF otherwise).
 
 
-5. Userspace support
+Userspace support
+=================
 
 The recommended userspace interface to use is /dev/rfkill, which is a misc
 character device that allows userspace to obtain and set the state of rfkill
@@ -112,11 +121,11 @@ rfkill core framework.
 Additionally, each rfkill device is registered in sysfs and emits uevents.
 
 rfkill devices issue uevents (with an action of "change"), with the following
-environment variables set:
+environment variables set::
 
-RFKILL_NAME
-RFKILL_STATE
-RFKILL_TYPE
+       RFKILL_NAME
+       RFKILL_STATE
+       RFKILL_TYPE
 
 The contents of these variables corresponds to the "name", "state" and
 "type" sysfs files explained above.
index 16eb314..8a5d34a 100644 (file)
@@ -1,7 +1,9 @@
-Started by Paul Jackson <pj@sgi.com>
-
+====================
 The robust futex ABI
---------------------
+====================
+
+:Author: Started by Paul Jackson <pj@sgi.com>
+
 
 Robust_futexes provide a mechanism that is used in addition to normal
 futexes, for kernel assist of cleanup of held locks on task exit.
@@ -32,7 +34,7 @@ probably causing deadlock or other such failure of the other threads
 waiting on the same locks.
 
 A thread that anticipates possibly using robust_futexes should first
-issue the system call:
+issue the system call::
 
     asmlinkage long
     sys_set_robust_list(struct robust_list_head __user *head, size_t len);
@@ -91,7 +93,7 @@ that lock using the futex mechanism.
 When a thread has invoked the above system call to indicate it
 anticipates using robust_futexes, the kernel stores the passed in 'head'
 pointer for that task.  The task may retrieve that value later on by
-using the system call:
+using the system call::
 
     asmlinkage long
     sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr,
@@ -135,6 +137,7 @@ manipulating this list), the user code must observe the following
 protocol on 'lock entry' insertion and removal:
 
 On insertion:
+
  1) set the 'list_op_pending' word to the address of the 'lock entry'
     to be inserted,
  2) acquire the futex lock,
@@ -143,6 +146,7 @@ On insertion:
  4) clear the 'list_op_pending' word.
 
 On removal:
+
  1) set the 'list_op_pending' word to the address of the 'lock entry'
     to be removed,
  2) remove the lock entry for this lock from the 'head' list,
index 61c22d6..6c42c75 100644 (file)
@@ -1,4 +1,8 @@
-Started by: Ingo Molnar <mingo@redhat.com>
+========================================
+A description of what robust futexes are
+========================================
+
+:Started by: Ingo Molnar <mingo@redhat.com>
 
 Background
 ----------
@@ -163,7 +167,7 @@ Implementation details
 ----------------------
 
 The patch adds two new syscalls: one to register the userspace list, and
-one to query the registered list pointer:
+one to query the registered list pointer::
 
  asmlinkage long
  sys_set_robust_list(struct robust_list_head __user *head,
@@ -185,7 +189,7 @@ straightforward. The kernel doesn't have any internal distinction between
 robust and normal futexes.
 
 If a futex is found to be held at exit time, the kernel sets the
-following bit of the futex word:
+following bit of the futex word::
 
        #define FUTEX_OWNER_DIED        0x40000000
 
@@ -193,7 +197,7 @@ and wakes up the next futex waiter (if any). User-space does the rest of
 the cleanup.
 
 Otherwise, robust futexes are acquired by glibc by putting the TID into
-the futex field atomically. Waiters set the FUTEX_WAITERS bit:
+the futex field atomically. Waiters set the FUTEX_WAITERS bit::
 
        #define FUTEX_WAITERS           0x80000000
 
index a95e36a..24b7a9e 100644 (file)
@@ -1,10 +1,15 @@
+============================================
 Remote Processor Messaging (rpmsg) Framework
+============================================
 
-Note: this document describes the rpmsg bus and how to write rpmsg drivers.
-To learn how to add rpmsg support for new platforms, check out remoteproc.txt
-(also a resident of Documentation/).
+.. note::
 
-1. Introduction
+  This document describes the rpmsg bus and how to write rpmsg drivers.
+  To learn how to add rpmsg support for new platforms, check out remoteproc.txt
+  (also a resident of Documentation/).
+
+Introduction
+============
 
 Modern SoCs typically employ heterogeneous remote processor devices in
 asymmetric multiprocessing (AMP) configurations, which may be running
@@ -58,170 +63,222 @@ to their destination address (this is done by invoking the driver's rx handler
 with the payload of the inbound message).
 
 
-2. User API
+User API
+========
+
+::
 
   int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len);
-   - sends a message across to the remote processor on a given channel.
-     The caller should specify the channel, the data it wants to send,
-     and its length (in bytes). The message will be sent on the specified
-     channel, i.e. its source and destination address fields will be
-     set to the channel's src and dst addresses.
-
-     In case there are no TX buffers available, the function will block until
-     one becomes available (i.e. until the remote processor consumes
-     a tx buffer and puts it back on virtio's used descriptor ring),
-     or a timeout of 15 seconds elapses. When the latter happens,
-     -ERESTARTSYS is returned.
-     The function can only be called from a process context (for now).
-     Returns 0 on success and an appropriate error value on failure.
+
+sends a message across to the remote processor on a given channel.
+The caller should specify the channel, the data it wants to send,
+and its length (in bytes). The message will be sent on the specified
+channel, i.e. its source and destination address fields will be
+set to the channel's src and dst addresses.
+
+In case there are no TX buffers available, the function will block until
+one becomes available (i.e. until the remote processor consumes
+a tx buffer and puts it back on virtio's used descriptor ring),
+or a timeout of 15 seconds elapses. When the latter happens,
+-ERESTARTSYS is returned.
+
+The function can only be called from a process context (for now).
+Returns 0 on success and an appropriate error value on failure.
+
+::
 
   int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst);
-   - sends a message across to the remote processor on a given channel,
-     to a destination address provided by the caller.
-     The caller should specify the channel, the data it wants to send,
-     its length (in bytes), and an explicit destination address.
-     The message will then be sent to the remote processor to which the
-     channel belongs, using the channel's src address, and the user-provided
-     dst address (thus the channel's dst address will be ignored).
-
-     In case there are no TX buffers available, the function will block until
-     one becomes available (i.e. until the remote processor consumes
-     a tx buffer and puts it back on virtio's used descriptor ring),
-     or a timeout of 15 seconds elapses. When the latter happens,
-     -ERESTARTSYS is returned.
-     The function can only be called from a process context (for now).
-     Returns 0 on success and an appropriate error value on failure.
+
+sends a message across to the remote processor on a given channel,
+to a destination address provided by the caller.
+
+The caller should specify the channel, the data it wants to send,
+its length (in bytes), and an explicit destination address.
+
+The message will then be sent to the remote processor to which the
+channel belongs, using the channel's src address, and the user-provided
+dst address (thus the channel's dst address will be ignored).
+
+In case there are no TX buffers available, the function will block until
+one becomes available (i.e. until the remote processor consumes
+a tx buffer and puts it back on virtio's used descriptor ring),
+or a timeout of 15 seconds elapses. When the latter happens,
+-ERESTARTSYS is returned.
+
+The function can only be called from a process context (for now).
+Returns 0 on success and an appropriate error value on failure.
+
+::
 
   int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
                                                        void *data, int len);
-   - sends a message across to the remote processor, using the src and dst
-     addresses provided by the user.
-     The caller should specify the channel, the data it wants to send,
-     its length (in bytes), and explicit source and destination addresses.
-     The message will then be sent to the remote processor to which the
-     channel belongs, but the channel's src and dst addresses will be
-     ignored (and the user-provided addresses will be used instead).
-
-     In case there are no TX buffers available, the function will block until
-     one becomes available (i.e. until the remote processor consumes
-     a tx buffer and puts it back on virtio's used descriptor ring),
-     or a timeout of 15 seconds elapses. When the latter happens,
-     -ERESTARTSYS is returned.
-     The function can only be called from a process context (for now).
-     Returns 0 on success and an appropriate error value on failure.
+
+
+sends a message across to the remote processor, using the src and dst
+addresses provided by the user.
+
+The caller should specify the channel, the data it wants to send,
+its length (in bytes), and explicit source and destination addresses.
+The message will then be sent to the remote processor to which the
+channel belongs, but the channel's src and dst addresses will be
+ignored (and the user-provided addresses will be used instead).
+
+In case there are no TX buffers available, the function will block until
+one becomes available (i.e. until the remote processor consumes
+a tx buffer and puts it back on virtio's used descriptor ring),
+or a timeout of 15 seconds elapses. When the latter happens,
+-ERESTARTSYS is returned.
+
+The function can only be called from a process context (for now).
+Returns 0 on success and an appropriate error value on failure.
+
+::
 
   int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len);
-   - sends a message across to the remote processor on a given channel.
-     The caller should specify the channel, the data it wants to send,
-     and its length (in bytes). The message will be sent on the specified
-     channel, i.e. its source and destination address fields will be
-     set to the channel's src and dst addresses.
 
-     In case there are no TX buffers available, the function will immediately
-     return -ENOMEM without waiting until one becomes available.
-     The function can only be called from a process context (for now).
-     Returns 0 on success and an appropriate error value on failure.
+sends a message across to the remote processor on a given channel.
+The caller should specify the channel, the data it wants to send,
+and its length (in bytes). The message will be sent on the specified
+channel, i.e. its source and destination address fields will be
+set to the channel's src and dst addresses.
+
+In case there are no TX buffers available, the function will immediately
+return -ENOMEM without waiting until one becomes available.
+
+The function can only be called from a process context (for now).
+Returns 0 on success and an appropriate error value on failure.
+
+::
 
   int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
-   - sends a message across to the remote processor on a given channel,
-     to a destination address provided by the user.
-     The user should specify the channel, the data it wants to send,
-     its length (in bytes), and an explicit destination address.
-     The message will then be sent to the remote processor to which the
-     channel belongs, using the channel's src address, and the user-provided
-     dst address (thus the channel's dst address will be ignored).
-
-     In case there are no TX buffers available, the function will immediately
-     return -ENOMEM without waiting until one becomes available.
-     The function can only be called from a process context (for now).
-     Returns 0 on success and an appropriate error value on failure.
+
+
+sends a message across to the remote processor on a given channel,
+to a destination address provided by the user.
+
+The user should specify the channel, the data it wants to send,
+its length (in bytes), and an explicit destination address.
+
+The message will then be sent to the remote processor to which the
+channel belongs, using the channel's src address, and the user-provided
+dst address (thus the channel's dst address will be ignored).
+
+In case there are no TX buffers available, the function will immediately
+return -ENOMEM without waiting until one becomes available.
+
+The function can only be called from a process context (for now).
+Returns 0 on success and an appropriate error value on failure.
+
+::
 
   int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
                                                        void *data, int len);
-   - sends a message across to the remote processor, using source and
-     destination addresses provided by the user.
-     The user should specify the channel, the data it wants to send,
-     its length (in bytes), and explicit source and destination addresses.
-     The message will then be sent to the remote processor to which the
-     channel belongs, but the channel's src and dst addresses will be
-     ignored (and the user-provided addresses will be used instead).
-
-     In case there are no TX buffers available, the function will immediately
-     return -ENOMEM without waiting until one becomes available.
-     The function can only be called from a process context (for now).
-     Returns 0 on success and an appropriate error value on failure.
+
+
+sends a message across to the remote processor, using source and
+destination addresses provided by the user.
+
+The user should specify the channel, the data it wants to send,
+its length (in bytes), and explicit source and destination addresses.
+The message will then be sent to the remote processor to which the
+channel belongs, but the channel's src and dst addresses will be
+ignored (and the user-provided addresses will be used instead).
+
+In case there are no TX buffers available, the function will immediately
+return -ENOMEM without waiting until one becomes available.
+
+The function can only be called from a process context (for now).
+Returns 0 on success and an appropriate error value on failure.
+
+::
 
   struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rpdev,
                void (*cb)(struct rpmsg_channel *, void *, int, void *, u32),
                void *priv, u32 addr);
-   - every rpmsg address in the system is bound to an rx callback (so when
-     inbound messages arrive, they are dispatched by the rpmsg bus using the
-     appropriate callback handler) by means of an rpmsg_endpoint struct.
-
-     This function allows drivers to create such an endpoint, and by that,
-     bind a callback, and possibly some private data too, to an rpmsg address
-     (either one that is known in advance, or one that will be dynamically
-     assigned for them).
-
-     Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint
-     is already created for them when they are probed by the rpmsg bus
-     (using the rx callback they provide when they registered to the rpmsg bus).
-
-     So things should just work for simple drivers: they already have an
-     endpoint, their rx callback is bound to their rpmsg address, and when
-     relevant inbound messages arrive (i.e. messages which their dst address
-     equals to the src address of their rpmsg channel), the driver's handler
-     is invoked to process it.
-
-     That said, more complicated drivers might do need to allocate
-     additional rpmsg addresses, and bind them to different rx callbacks.
-     To accomplish that, those drivers need to call this function.
-     Drivers should provide their channel (so the new endpoint would bind
-     to the same remote processor their channel belongs to), an rx callback
-     function, an optional private data (which is provided back when the
-     rx callback is invoked), and an address they want to bind with the
-     callback. If addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
-     dynamically assign them an available rpmsg address (drivers should have
-     a very good reason why not to always use RPMSG_ADDR_ANY here).
-
-     Returns a pointer to the endpoint on success, or NULL on error.
+
+every rpmsg address in the system is bound to an rx callback (so when
+inbound messages arrive, they are dispatched by the rpmsg bus using the
+appropriate callback handler) by means of an rpmsg_endpoint struct.
+
+This function allows drivers to create such an endpoint, and by that,
+bind a callback, and possibly some private data too, to an rpmsg address
+(either one that is known in advance, or one that will be dynamically
+assigned for them).
+
+Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint
+is already created for them when they are probed by the rpmsg bus
+(using the rx callback they provide when they registered to the rpmsg bus).
+
+So things should just work for simple drivers: they already have an
+endpoint, their rx callback is bound to their rpmsg address, and when
+relevant inbound messages arrive (i.e. messages which their dst address
+equals to the src address of their rpmsg channel), the driver's handler
+is invoked to process it.
+
+That said, more complicated drivers might do need to allocate
+additional rpmsg addresses, and bind them to different rx callbacks.
+To accomplish that, those drivers need to call this function.
+Drivers should provide their channel (so the new endpoint would bind
+to the same remote processor their channel belongs to), an rx callback
+function, an optional private data (which is provided back when the
+rx callback is invoked), and an address they want to bind with the
+callback. If addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
+dynamically assign them an available rpmsg address (drivers should have
+a very good reason why not to always use RPMSG_ADDR_ANY here).
+
+Returns a pointer to the endpoint on success, or NULL on error.
+
+::
 
   void rpmsg_destroy_ept(struct rpmsg_endpoint *ept);
-   - destroys an existing rpmsg endpoint. user should provide a pointer
-     to an rpmsg endpoint that was previously created with rpmsg_create_ept().
+
+
+destroys an existing rpmsg endpoint. user should provide a pointer
+to an rpmsg endpoint that was previously created with rpmsg_create_ept().
+
+::
 
   int register_rpmsg_driver(struct rpmsg_driver *rpdrv);
-   - registers an rpmsg driver with the rpmsg bus. user should provide
-     a pointer to an rpmsg_driver struct, which contains the driver's
-     ->probe() and ->remove() functions, an rx callback, and an id_table
-     specifying the names of the channels this driver is interested to
-     be probed with.
+
+
+registers an rpmsg driver with the rpmsg bus. user should provide
+a pointer to an rpmsg_driver struct, which contains the driver's
+->probe() and ->remove() functions, an rx callback, and an id_table
+specifying the names of the channels this driver is interested to
+be probed with.
+
+::
 
   void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv);
-   - unregisters an rpmsg driver from the rpmsg bus. user should provide
-     a pointer to a previously-registered rpmsg_driver struct.
-     Returns 0 on success, and an appropriate error value on failure.
 
 
-3. Typical usage
+unregisters an rpmsg driver from the rpmsg bus. user should provide
+a pointer to a previously-registered rpmsg_driver struct.
+Returns 0 on success, and an appropriate error value on failure.
+
+
+Typical usage
+=============
 
 The following is a simple rpmsg driver, that sends an "hello!" message
 on probe(), and whenever it receives an incoming message, it dumps its
 content to the console.
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/rpmsg.h>
+::
+
+  #include <linux/kernel.h>
+  #include <linux/module.h>
+  #include <linux/rpmsg.h>
 
-static void rpmsg_sample_cb(struct rpmsg_channel *rpdev, void *data, int len,
+  static void rpmsg_sample_cb(struct rpmsg_channel *rpdev, void *data, int len,
                                                void *priv, u32 src)
-{
+  {
        print_hex_dump(KERN_INFO, "incoming message:", DUMP_PREFIX_NONE,
                                                16, 1, data, len, true);
-}
+  }
 
-static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
-{
+  static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
+  {
        int err;
 
        dev_info(&rpdev->dev, "chnl: 0x%x -> 0x%x\n", rpdev->src, rpdev->dst);
@@ -234,32 +291,35 @@ static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
        }
 
        return 0;
-}
+  }
 
-static void rpmsg_sample_remove(struct rpmsg_channel *rpdev)
-{
+  static void rpmsg_sample_remove(struct rpmsg_channel *rpdev)
+  {
        dev_info(&rpdev->dev, "rpmsg sample client driver is removed\n");
-}
+  }
 
-static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = {
+  static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = {
        { .name = "rpmsg-client-sample" },
        { },
-};
-MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table);
+  };
+  MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table);
 
-static struct rpmsg_driver rpmsg_sample_client = {
+  static struct rpmsg_driver rpmsg_sample_client = {
        .drv.name       = KBUILD_MODNAME,
        .id_table       = rpmsg_driver_sample_id_table,
        .probe          = rpmsg_sample_probe,
        .callback       = rpmsg_sample_cb,
        .remove         = rpmsg_sample_remove,
-};
-module_rpmsg_driver(rpmsg_sample_client);
+  };
+  module_rpmsg_driver(rpmsg_sample_client);
+
+.. note::
 
-Note: a similar sample which can be built and loaded can be found
-in samples/rpmsg/.
+   a similar sample which can be built and loaded can be found
+   in samples/rpmsg/.
 
-4. Allocations of rpmsg channels:
+Allocations of rpmsg channels
+=============================
 
 At this point we only support dynamic allocations of rpmsg channels.
 
index ddc3660..c0c9774 100644 (file)
@@ -1,6 +1,6 @@
-
-       Real Time Clock (RTC) Drivers for Linux
-       =======================================
+=======================================
+Real Time Clock (RTC) Drivers for Linux
+=======================================
 
 When Linux developers talk about a "Real Time Clock", they usually mean
 something that tracks wall clock time and is battery backed so that it
@@ -32,8 +32,8 @@ only issue an alarm up to 24 hours in the future, other hardware may
 be able to schedule one any time in the upcoming century.
 
 
-       Old PC/AT-Compatible driver:  /dev/rtc
-       --------------------------------------
+Old PC/AT-Compatible driver:  /dev/rtc
+--------------------------------------
 
 All PCs (even Alpha machines) have a Real Time Clock built into them.
 Usually they are built into the chipset of the computer, but some may
@@ -105,8 +105,8 @@ that will be using this driver.  See the code at the end of this document.
 (The original /dev/rtc driver was written by Paul Gortmaker.)
 
 
-       New portable "RTC Class" drivers:  /dev/rtcN
-       --------------------------------------------
+New portable "RTC Class" drivers:  /dev/rtcN
+--------------------------------------------
 
 Because Linux supports many non-ACPI and non-PC platforms, some of which
 have more than one RTC style clock, it needed a more portable solution
@@ -136,35 +136,39 @@ a high functionality RTC is integrated into the SOC.  That system might read
 the system clock from the discrete RTC, but use the integrated one for all
 other tasks, because of its greater functionality.
 
-SYSFS INTERFACE
+SYSFS interface
 ---------------
 
 The sysfs interface under /sys/class/rtc/rtcN provides access to various
 rtc attributes without requiring the use of ioctls. All dates and times
 are in the RTC's timezone, rather than in system time.
 
-date:                   RTC-provided date
-hctosys:        1 if the RTC provided the system time at boot via the
+================ ==============================================================
+date            RTC-provided date
+hctosys         1 if the RTC provided the system time at boot via the
                 CONFIG_RTC_HCTOSYS kernel option, 0 otherwise
-max_user_freq:  The maximum interrupt rate an unprivileged user may request
+max_user_freq   The maximum interrupt rate an unprivileged user may request
                 from this RTC.
-name:           The name of the RTC corresponding to this sysfs directory
-since_epoch:    The number of seconds since the epoch according to the RTC
-time:           RTC-provided time
-wakealarm:      The time at which the clock will generate a system wakeup
+name            The name of the RTC corresponding to this sysfs directory
+since_epoch     The number of seconds since the epoch according to the RTC
+time            RTC-provided time
+wakealarm       The time at which the clock will generate a system wakeup
                 event. This is a one shot wakeup event, so must be reset
-                after wake if a daily wakeup is required. Format is seconds since
-                the epoch by default, or if there's a leading +, seconds in the
-                future, or if there is a leading +=, seconds ahead of the current
-                alarm.
-offset:                 The amount which the rtc clock has been adjusted in firmware.
+                after wake if a daily wakeup is required. Format is seconds
+                since the epoch by default, or if there's a leading +, seconds
+                in the future, or if there is a leading +=, seconds ahead of
+                the current alarm.
+offset          The amount which the rtc clock has been adjusted in firmware.
                 Visible only if the driver supports clock offset adjustment.
                 The unit is parts per billion, i.e. The number of clock ticks
                 which are added to or removed from the rtc's base clock per
                 billion ticks. A positive value makes a day pass more slowly,
                 longer, and a negative value makes a day pass more quickly.
+*/nvmem                 The non volatile storage exported as a raw file, as described
+                in Documentation/nvmem/nvmem.txt
+================ ==============================================================
 
-IOCTL INTERFACE
+IOCTL interface
 ---------------
 
 The ioctl() calls supported by /dev/rtc are also supported by the RTC class
index 0d831a7..1648fa8 100644 (file)
@@ -894,6 +894,12 @@ The keyctl syscall functions are:
      To apply a keyring restriction the process must have Set Attribute
      permission and the keyring must not be previously restricted.
 
+     One application of restricted keyrings is to verify X.509 certificate
+     chains or individual certificate signatures using the asymmetric key type.
+     See Documentation/crypto/asymmetric-keys.txt for specific restrictions
+     applicable to the asymmetric key type.
+
+
 Kernel Services
 ===============
 
index 876c96a..7270922 100644 (file)
@@ -1,3 +1,7 @@
+====================================
+SGI IOC4 PCI (multi function) device
+====================================
+
 The SGI IOC4 PCI device is a bit of a strange beast, so some notes on
 it are in order.
 
index 908d348..9965821 100644 (file)
@@ -1,6 +1,8 @@
-         SipHash - a short input PRF
------------------------------------------------
-Written by Jason A. Donenfeld <jason@zx2c4.com>
+===========================
+SipHash - a short input PRF
+===========================
+
+:Author: Written by Jason A. Donenfeld <jason@zx2c4.com>
 
 SipHash is a cryptographically secure PRF -- a keyed hash function -- that
 performs very well for short inputs, hence the name. It was designed by
@@ -13,58 +15,61 @@ an input buffer or several input integers. It spits out an integer that is
 indistinguishable from random. You may then use that integer as part of secure
 sequence numbers, secure cookies, or mask it off for use in a hash table.
 
-1. Generating a key
+Generating a key
+================
 
 Keys should always be generated from a cryptographically secure source of
-random numbers, either using get_random_bytes or get_random_once:
+random numbers, either using get_random_bytes or get_random_once::
 
-siphash_key_t key;
-get_random_bytes(&key, sizeof(key));
+       siphash_key_t key;
+       get_random_bytes(&key, sizeof(key));
 
 If you're not deriving your key from here, you're doing it wrong.
 
-2. Using the functions
+Using the functions
+===================
 
 There are two variants of the function, one that takes a list of integers, and
-one that takes a buffer:
+one that takes a buffer::
 
-u64 siphash(const void *data, size_t len, const siphash_key_t *key);
+       u64 siphash(const void *data, size_t len, const siphash_key_t *key);
 
-And:
+And::
 
-u64 siphash_1u64(u64, const siphash_key_t *key);
-u64 siphash_2u64(u64, u64, const siphash_key_t *key);
-u64 siphash_3u64(u64, u64, u64, const siphash_key_t *key);
-u64 siphash_4u64(u64, u64, u64, u64, const siphash_key_t *key);
-u64 siphash_1u32(u32, const siphash_key_t *key);
-u64 siphash_2u32(u32, u32, const siphash_key_t *key);
-u64 siphash_3u32(u32, u32, u32, const siphash_key_t *key);
-u64 siphash_4u32(u32, u32, u32, u32, const siphash_key_t *key);
+       u64 siphash_1u64(u64, const siphash_key_t *key);
+       u64 siphash_2u64(u64, u64, const siphash_key_t *key);
+       u64 siphash_3u64(u64, u64, u64, const siphash_key_t *key);
+       u64 siphash_4u64(u64, u64, u64, u64, const siphash_key_t *key);
+       u64 siphash_1u32(u32, const siphash_key_t *key);
+       u64 siphash_2u32(u32, u32, const siphash_key_t *key);
+       u64 siphash_3u32(u32, u32, u32, const siphash_key_t *key);
+       u64 siphash_4u32(u32, u32, u32, u32, const siphash_key_t *key);
 
 If you pass the generic siphash function something of a constant length, it
 will constant fold at compile-time and automatically choose one of the
 optimized functions.
 
-3. Hashtable key function usage:
+Hashtable key function usage::
 
-struct some_hashtable {
-       DECLARE_HASHTABLE(hashtable, 8);
-       siphash_key_t key;
-};
+       struct some_hashtable {
+               DECLARE_HASHTABLE(hashtable, 8);
+               siphash_key_t key;
+       };
 
-void init_hashtable(struct some_hashtable *table)
-{
-       get_random_bytes(&table->key, sizeof(table->key));
-}
+       void init_hashtable(struct some_hashtable *table)
+       {
+               get_random_bytes(&table->key, sizeof(table->key));
+       }
 
-static inline hlist_head *some_hashtable_bucket(struct some_hashtable *table, struct interesting_input *input)
-{
-       return &table->hashtable[siphash(input, sizeof(*input), &table->key) & (HASH_SIZE(table->hashtable) - 1)];
-}
+       static inline hlist_head *some_hashtable_bucket(struct some_hashtable *table, struct interesting_input *input)
+       {
+               return &table->hashtable[siphash(input, sizeof(*input), &table->key) & (HASH_SIZE(table->hashtable) - 1)];
+       }
 
 You may then iterate like usual over the returned hash bucket.
 
-4. Security
+Security
+========
 
 SipHash has a very high security margin, with its 128-bit key. So long as the
 key is kept secret, it is impossible for an attacker to guess the outputs of
@@ -73,7 +78,8 @@ is significant.
 
 Linux implements the "2-4" variant of SipHash.
 
-5. Struct-passing Pitfalls
+Struct-passing Pitfalls
+=======================
 
 Often times the XuY functions will not be large enough, and instead you'll
 want to pass a pre-filled struct to siphash. When doing this, it's important
@@ -81,30 +87,32 @@ to always ensure the struct has no padding holes. The easiest way to do this
 is to simply arrange the members of the struct in descending order of size,
 and to use offsetendof() instead of sizeof() for getting the size. For
 performance reasons, if possible, it's probably a good thing to align the
-struct to the right boundary. Here's an example:
-
-const struct {
-       struct in6_addr saddr;
-       u32 counter;
-       u16 dport;
-} __aligned(SIPHASH_ALIGNMENT) combined = {
-       .saddr = *(struct in6_addr *)saddr,
-       .counter = counter,
-       .dport = dport
-};
-u64 h = siphash(&combined, offsetofend(typeof(combined), dport), &secret);
-
-6. Resources
+struct to the right boundary. Here's an example::
+
+       const struct {
+               struct in6_addr saddr;
+               u32 counter;
+               u16 dport;
+       } __aligned(SIPHASH_ALIGNMENT) combined = {
+               .saddr = *(struct in6_addr *)saddr,
+               .counter = counter,
+               .dport = dport
+       };
+       u64 h = siphash(&combined, offsetofend(typeof(combined), dport), &secret);
+
+Resources
+=========
 
 Read the SipHash paper if you're interested in learning more:
 https://131002.net/siphash/siphash.pdf
 
+-------------------------------------------------------------------------------
 
-~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
-
+===============================================
 HalfSipHash - SipHash's insecure younger cousin
------------------------------------------------
-Written by Jason A. Donenfeld <jason@zx2c4.com>
+===============================================
+
+:Author: Written by Jason A. Donenfeld <jason@zx2c4.com>
 
 On the off-chance that SipHash is not fast enough for your needs, you might be
 able to justify using HalfSipHash, a terrifying but potentially useful
@@ -120,7 +128,8 @@ then when you can be absolutely certain that the outputs will never be
 transmitted out of the kernel. This is only remotely useful over `jhash` as a
 means of mitigating hashtable flooding denial of service attacks.
 
-1. Generating a key
+Generating a key
+================
 
 Keys should always be generated from a cryptographically secure source of
 random numbers, either using get_random_bytes or get_random_once:
@@ -130,44 +139,49 @@ get_random_bytes(&key, sizeof(key));
 
 If you're not deriving your key from here, you're doing it wrong.
 
-2. Using the functions
+Using the functions
+===================
 
 There are two variants of the function, one that takes a list of integers, and
-one that takes a buffer:
+one that takes a buffer::
 
-u32 hsiphash(const void *data, size_t len, const hsiphash_key_t *key);
+       u32 hsiphash(const void *data, size_t len, const hsiphash_key_t *key);
 
-And:
+And::
 
-u32 hsiphash_1u32(u32, const hsiphash_key_t *key);
-u32 hsiphash_2u32(u32, u32, const hsiphash_key_t *key);
-u32 hsiphash_3u32(u32, u32, u32, const hsiphash_key_t *key);
-u32 hsiphash_4u32(u32, u32, u32, u32, const hsiphash_key_t *key);
+       u32 hsiphash_1u32(u32, const hsiphash_key_t *key);
+       u32 hsiphash_2u32(u32, u32, const hsiphash_key_t *key);
+       u32 hsiphash_3u32(u32, u32, u32, const hsiphash_key_t *key);
+       u32 hsiphash_4u32(u32, u32, u32, u32, const hsiphash_key_t *key);
 
 If you pass the generic hsiphash function something of a constant length, it
 will constant fold at compile-time and automatically choose one of the
 optimized functions.
 
-3. Hashtable key function usage:
+Hashtable key function usage
+============================
+
+::
 
-struct some_hashtable {
-       DECLARE_HASHTABLE(hashtable, 8);
-       hsiphash_key_t key;
-};
+       struct some_hashtable {
+               DECLARE_HASHTABLE(hashtable, 8);
+               hsiphash_key_t key;
+       };
 
-void init_hashtable(struct some_hashtable *table)
-{
-       get_random_bytes(&table->key, sizeof(table->key));
-}
+       void init_hashtable(struct some_hashtable *table)
+       {
+               get_random_bytes(&table->key, sizeof(table->key));
+       }
 
-static inline hlist_head *some_hashtable_bucket(struct some_hashtable *table, struct interesting_input *input)
-{
-       return &table->hashtable[hsiphash(input, sizeof(*input), &table->key) & (HASH_SIZE(table->hashtable) - 1)];
-}
+       static inline hlist_head *some_hashtable_bucket(struct some_hashtable *table, struct interesting_input *input)
+       {
+               return &table->hashtable[hsiphash(input, sizeof(*input), &table->key) & (HASH_SIZE(table->hashtable) - 1)];
+       }
 
 You may then iterate like usual over the returned hash bucket.
 
-4. Performance
+Performance
+===========
 
 HalfSipHash is roughly 3 times slower than JenkinsHash. For many replacements,
 this will not be a problem, as the hashtable lookup isn't the bottleneck. And
index 6b492e8..0792774 100644 (file)
@@ -1,3 +1,7 @@
+=================================================
+Msc Keyboard Scan Expansion/GPIO Expansion device
+=================================================
+
 What is smsc-ece1099?
 ----------------------
 
index ef419fd..b83dfa1 100644 (file)
@@ -1,30 +1,34 @@
-                       Static Keys
-                       -----------
+===========
+Static Keys
+===========
 
-DEPRECATED API:
+.. warning::
 
-The use of 'struct static_key' directly, is now DEPRECATED. In addition
-static_key_{true,false}() is also DEPRECATED. IE DO NOT use the following:
+   DEPRECATED API:
 
-struct static_key false = STATIC_KEY_INIT_FALSE;
-struct static_key true = STATIC_KEY_INIT_TRUE;
-static_key_true()
-static_key_false()
+   The use of 'struct static_key' directly, is now DEPRECATED. In addition
+   static_key_{true,false}() is also DEPRECATED. IE DO NOT use the following::
 
-The updated API replacements are:
+       struct static_key false = STATIC_KEY_INIT_FALSE;
+       struct static_key true = STATIC_KEY_INIT_TRUE;
+       static_key_true()
+       static_key_false()
 
-DEFINE_STATIC_KEY_TRUE(key);
-DEFINE_STATIC_KEY_FALSE(key);
-DEFINE_STATIC_KEY_ARRAY_TRUE(keys, count);
-DEFINE_STATIC_KEY_ARRAY_FALSE(keys, count);
-static_branch_likely()
-static_branch_unlikely()
+   The updated API replacements are::
 
-0) Abstract
+       DEFINE_STATIC_KEY_TRUE(key);
+       DEFINE_STATIC_KEY_FALSE(key);
+       DEFINE_STATIC_KEY_ARRAY_TRUE(keys, count);
+       DEFINE_STATIC_KEY_ARRAY_FALSE(keys, count);
+       static_branch_likely()
+       static_branch_unlikely()
+
+Abstract
+========
 
 Static keys allows the inclusion of seldom used features in
 performance-sensitive fast-path kernel code, via a GCC feature and a code
-patching technique. A quick example:
+patching technique. A quick example::
 
        DEFINE_STATIC_KEY_FALSE(key);
 
@@ -45,7 +49,8 @@ The static_branch_unlikely() branch will be generated into the code with as litt
 impact to the likely code path as possible.
 
 
-1) Motivation
+Motivation
+==========
 
 
 Currently, tracepoints are implemented using a conditional branch. The
@@ -60,7 +65,8 @@ possible. Although tracepoints are the original motivation for this work, other
 kernel code paths should be able to make use of the static keys facility.
 
 
-2) Solution
+Solution
+========
 
 
 gcc (v4.5) adds a new 'asm goto' statement that allows branching to a label:
@@ -71,7 +77,7 @@ Using the 'asm goto', we can create branches that are either taken or not taken
 by default, without the need to check memory. Then, at run-time, we can patch
 the branch site to change the branch direction.
 
-For example, if we have a simple branch that is disabled by default:
+For example, if we have a simple branch that is disabled by default::
 
        if (static_branch_unlikely(&key))
                printk("I am the true branch\n");
@@ -87,14 +93,15 @@ optimization.
 This lowlevel patching mechanism is called 'jump label patching', and it gives
 the basis for the static keys facility.
 
-3) Static key label API, usage and examples:
+Static key label API, usage and examples
+========================================
 
 
-In order to make use of this optimization you must first define a key:
+In order to make use of this optimization you must first define a key::
 
        DEFINE_STATIC_KEY_TRUE(key);
 
-or:
+or::
 
        DEFINE_STATIC_KEY_FALSE(key);
 
@@ -102,14 +109,14 @@ or:
 The key must be global, that is, it can't be allocated on the stack or dynamically
 allocated at run-time.
 
-The key is then used in code as:
+The key is then used in code as::
 
         if (static_branch_unlikely(&key))
                 do unlikely code
         else
                 do likely code
 
-Or:
+Or::
 
         if (static_branch_likely(&key))
                 do likely code
@@ -120,15 +127,15 @@ Keys defined via DEFINE_STATIC_KEY_TRUE(), or DEFINE_STATIC_KEY_FALSE, may
 be used in either static_branch_likely() or static_branch_unlikely()
 statements.
 
-Branch(es) can be set true via:
+Branch(es) can be set true via::
 
-static_branch_enable(&key);
+       static_branch_enable(&key);
 
-or false via:
+or false via::
 
-static_branch_disable(&key);
+       static_branch_disable(&key);
 
-The branch(es) can then be switched via reference counts:
+The branch(es) can then be switched via reference counts::
 
        static_branch_inc(&key);
        ...
@@ -142,11 +149,11 @@ static_branch_inc(), will change the branch back to true. Likewise, if the
 key is initialized false, a 'static_branch_inc()', will change the branch to
 true. And then a 'static_branch_dec()', will again make the branch false.
 
-Where an array of keys is required, it can be defined as:
+Where an array of keys is required, it can be defined as::
 
        DEFINE_STATIC_KEY_ARRAY_TRUE(keys, count);
 
-or:
+or::
 
        DEFINE_STATIC_KEY_ARRAY_FALSE(keys, count);
 
@@ -159,96 +166,98 @@ simply fall back to a traditional, load, test, and jump sequence. Also, the
 struct jump_entry table must be at least 4-byte aligned because the
 static_key->entry field makes use of the two least significant bits.
 
-* select HAVE_ARCH_JUMP_LABEL, see: arch/x86/Kconfig
-
-* #define JUMP_LABEL_NOP_SIZE, see: arch/x86/include/asm/jump_label.h
+* ``select HAVE_ARCH_JUMP_LABEL``,
+    see: arch/x86/Kconfig
 
-* __always_inline bool arch_static_branch(struct static_key *key, bool branch), see:
-                                       arch/x86/include/asm/jump_label.h
+* ``#define JUMP_LABEL_NOP_SIZE``,
+    see: arch/x86/include/asm/jump_label.h
 
-* __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch),
-                                       see: arch/x86/include/asm/jump_label.h
+* ``__always_inline bool arch_static_branch(struct static_key *key, bool branch)``,
+    see: arch/x86/include/asm/jump_label.h
 
-* void arch_jump_label_transform(struct jump_entry *entry, enum jump_label_type type),
-                                       see: arch/x86/kernel/jump_label.c
+* ``__always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)``,
+    see: arch/x86/include/asm/jump_label.h
 
-* __init_or_module void arch_jump_label_transform_static(struct jump_entry *entry, enum jump_label_type type),
-                                       see: arch/x86/kernel/jump_label.c
+* ``void arch_jump_label_transform(struct jump_entry *entry, enum jump_label_type type)``,
+    see: arch/x86/kernel/jump_label.c
 
+* ``__init_or_module void arch_jump_label_transform_static(struct jump_entry *entry, enum jump_label_type type)``,
+    see: arch/x86/kernel/jump_label.c
 
-* struct jump_entry, see: arch/x86/include/asm/jump_label.h
+* ``struct jump_entry``,
+    see: arch/x86/include/asm/jump_label.h
 
 
 5) Static keys / jump label analysis, results (x86_64):
 
 
 As an example, let's add the following branch to 'getppid()', such that the
-system call now looks like:
+system call now looks like::
 
-SYSCALL_DEFINE0(getppid)
-{
+  SYSCALL_DEFINE0(getppid)
+  {
         int pid;
 
-+       if (static_branch_unlikely(&key))
-+               printk("I am the true branch\n");
+  +     if (static_branch_unlikely(&key))
+  +             printk("I am the true branch\n");
 
         rcu_read_lock();
         pid = task_tgid_vnr(rcu_dereference(current->real_parent));
         rcu_read_unlock();
 
         return pid;
-}
-
-The resulting instructions with jump labels generated by GCC is:
-
-ffffffff81044290 <sys_getppid>:
-ffffffff81044290:       55                      push   %rbp
-ffffffff81044291:       48 89 e5                mov    %rsp,%rbp
-ffffffff81044294:       e9 00 00 00 00          jmpq   ffffffff81044299 <sys_getppid+0x9>
-ffffffff81044299:       65 48 8b 04 25 c0 b6    mov    %gs:0xb6c0,%rax
-ffffffff810442a0:       00 00
-ffffffff810442a2:       48 8b 80 80 02 00 00    mov    0x280(%rax),%rax
-ffffffff810442a9:       48 8b 80 b0 02 00 00    mov    0x2b0(%rax),%rax
-ffffffff810442b0:       48 8b b8 e8 02 00 00    mov    0x2e8(%rax),%rdi
-ffffffff810442b7:       e8 f4 d9 00 00          callq  ffffffff81051cb0 <pid_vnr>
-ffffffff810442bc:       5d                      pop    %rbp
-ffffffff810442bd:       48 98                   cltq
-ffffffff810442bf:       c3                      retq
-ffffffff810442c0:       48 c7 c7 e3 54 98 81    mov    $0xffffffff819854e3,%rdi
-ffffffff810442c7:       31 c0                   xor    %eax,%eax
-ffffffff810442c9:       e8 71 13 6d 00          callq  ffffffff8171563f <printk>
-ffffffff810442ce:       eb c9                   jmp    ffffffff81044299 <sys_getppid+0x9>
-
-Without the jump label optimization it looks like:
-
-ffffffff810441f0 <sys_getppid>:
-ffffffff810441f0:       8b 05 8a 52 d8 00       mov    0xd8528a(%rip),%eax        # ffffffff81dc9480 <key>
-ffffffff810441f6:       55                      push   %rbp
-ffffffff810441f7:       48 89 e5                mov    %rsp,%rbp
-ffffffff810441fa:       85 c0                   test   %eax,%eax
-ffffffff810441fc:       75 27                   jne    ffffffff81044225 <sys_getppid+0x35>
-ffffffff810441fe:       65 48 8b 04 25 c0 b6    mov    %gs:0xb6c0,%rax
-ffffffff81044205:       00 00
-ffffffff81044207:       48 8b 80 80 02 00 00    mov    0x280(%rax),%rax
-ffffffff8104420e:       48 8b 80 b0 02 00 00    mov    0x2b0(%rax),%rax
-ffffffff81044215:       48 8b b8 e8 02 00 00    mov    0x2e8(%rax),%rdi
-ffffffff8104421c:       e8 2f da 00 00          callq  ffffffff81051c50 <pid_vnr>
-ffffffff81044221:       5d                      pop    %rbp
-ffffffff81044222:       48 98                   cltq
-ffffffff81044224:       c3                      retq
-ffffffff81044225:       48 c7 c7 13 53 98 81    mov    $0xffffffff81985313,%rdi
-ffffffff8104422c:       31 c0                   xor    %eax,%eax
-ffffffff8104422e:       e8 60 0f 6d 00          callq  ffffffff81715193 <printk>
-ffffffff81044233:       eb c9                   jmp    ffffffff810441fe <sys_getppid+0xe>
-ffffffff81044235:       66 66 2e 0f 1f 84 00    data32 nopw %cs:0x0(%rax,%rax,1)
-ffffffff8104423c:       00 00 00 00
+  }
+
+The resulting instructions with jump labels generated by GCC is::
+
+  ffffffff81044290 <sys_getppid>:
+  ffffffff81044290:       55                      push   %rbp
+  ffffffff81044291:       48 89 e5                mov    %rsp,%rbp
+  ffffffff81044294:       e9 00 00 00 00          jmpq   ffffffff81044299 <sys_getppid+0x9>
+  ffffffff81044299:       65 48 8b 04 25 c0 b6    mov    %gs:0xb6c0,%rax
+  ffffffff810442a0:       00 00
+  ffffffff810442a2:       48 8b 80 80 02 00 00    mov    0x280(%rax),%rax
+  ffffffff810442a9:       48 8b 80 b0 02 00 00    mov    0x2b0(%rax),%rax
+  ffffffff810442b0:       48 8b b8 e8 02 00 00    mov    0x2e8(%rax),%rdi
+  ffffffff810442b7:       e8 f4 d9 00 00          callq  ffffffff81051cb0 <pid_vnr>
+  ffffffff810442bc:       5d                      pop    %rbp
+  ffffffff810442bd:       48 98                   cltq
+  ffffffff810442bf:       c3                      retq
+  ffffffff810442c0:       48 c7 c7 e3 54 98 81    mov    $0xffffffff819854e3,%rdi
+  ffffffff810442c7:       31 c0                   xor    %eax,%eax
+  ffffffff810442c9:       e8 71 13 6d 00          callq  ffffffff8171563f <printk>
+  ffffffff810442ce:       eb c9                   jmp    ffffffff81044299 <sys_getppid+0x9>
+
+Without the jump label optimization it looks like::
+
+  ffffffff810441f0 <sys_getppid>:
+  ffffffff810441f0:       8b 05 8a 52 d8 00       mov    0xd8528a(%rip),%eax        # ffffffff81dc9480 <key>
+  ffffffff810441f6:       55                      push   %rbp
+  ffffffff810441f7:       48 89 e5                mov    %rsp,%rbp
+  ffffffff810441fa:       85 c0                   test   %eax,%eax
+  ffffffff810441fc:       75 27                   jne    ffffffff81044225 <sys_getppid+0x35>
+  ffffffff810441fe:       65 48 8b 04 25 c0 b6    mov    %gs:0xb6c0,%rax
+  ffffffff81044205:       00 00
+  ffffffff81044207:       48 8b 80 80 02 00 00    mov    0x280(%rax),%rax
+  ffffffff8104420e:       48 8b 80 b0 02 00 00    mov    0x2b0(%rax),%rax
+  ffffffff81044215:       48 8b b8 e8 02 00 00    mov    0x2e8(%rax),%rdi
+  ffffffff8104421c:       e8 2f da 00 00          callq  ffffffff81051c50 <pid_vnr>
+  ffffffff81044221:       5d                      pop    %rbp
+  ffffffff81044222:       48 98                   cltq
+  ffffffff81044224:       c3                      retq
+  ffffffff81044225:       48 c7 c7 13 53 98 81    mov    $0xffffffff81985313,%rdi
+  ffffffff8104422c:       31 c0                   xor    %eax,%eax
+  ffffffff8104422e:       e8 60 0f 6d 00          callq  ffffffff81715193 <printk>
+  ffffffff81044233:       eb c9                   jmp    ffffffff810441fe <sys_getppid+0xe>
+  ffffffff81044235:       66 66 2e 0f 1f 84 00    data32 nopw %cs:0x0(%rax,%rax,1)
+  ffffffff8104423c:       00 00 00 00
 
 Thus, the disable jump label case adds a 'mov', 'test' and 'jne' instruction
 vs. the jump label case just has a 'no-op' or 'jmp 0'. (The jmp 0, is patched
 to a 5 byte atomic no-op instruction at boot-time.) Thus, the disabled jump
-label case adds:
+label case adds::
 
-6 (mov) + 2 (test) + 2 (jne) = 10 - 5 (5 byte jump 0) = 5 addition bytes.
+  6 (mov) + 2 (test) + 2 (jne) = 10 - 5 (5 byte jump 0) = 5 addition bytes.
 
 If we then include the padding bytes, the jump label code saves, 16 total bytes
 of instruction memory for this small function. In this case the non-jump label
@@ -262,7 +271,7 @@ Since there are a number of static key API uses in the scheduler paths,
 'pipe-test' (also known as 'perf bench sched pipe') can be used to show the
 performance improvement. Testing done on 3.3.0-rc2:
 
-jump label disabled:
+jump label disabled::
 
  Performance counter stats for 'bash -c /tmp/pipe-test' (50 runs):
 
@@ -279,7 +288,7 @@ jump label disabled:
 
        1.601607384 seconds time elapsed                                          ( +-  0.07% )
 
-jump label enabled:
+jump label enabled::
 
  Performance counter stats for 'bash -c /tmp/pipe-test' (50 runs):
 
index cd66ec8..119f151 100644 (file)
@@ -1,24 +1,31 @@
-                      Video Mode Selection Support 2.13
-                   (c) 1995--1999 Martin Mares, <mj@ucw.cz>
---------------------------------------------------------------------------------
+.. include:: <isonum.txt>
 
-1. Intro
-~~~~~~~~
-   This small document describes the "Video Mode Selection" feature which
+=================================
+Video Mode Selection Support 2.13
+=================================
+
+:Copyright: |copy| 1995--1999 Martin Mares, <mj@ucw.cz>
+
+Intro
+~~~~~
+
+This small document describes the "Video Mode Selection" feature which
 allows the use of various special video modes supported by the video BIOS. Due
 to usage of the BIOS, the selection is limited to boot time (before the
 kernel decompression starts) and works only on 80X86 machines.
 
-   **  Short intro for the impatient: Just use vga=ask for the first time,
-   **  enter `scan' on the video mode prompt, pick the mode you want to use,
-   **  remember its mode ID (the four-digit hexadecimal number) and then
-   **  set the vga parameter to this number (converted to decimal first).
+.. note::
 
-   The video mode to be used is selected by a kernel parameter which can be
+   Short intro for the impatient: Just use vga=ask for the first time,
+   enter ``scan`` on the video mode prompt, pick the mode you want to use,
+   remember its mode ID (the four-digit hexadecimal number) and then
+   set the vga parameter to this number (converted to decimal first).
+
+The video mode to be used is selected by a kernel parameter which can be
 specified in the kernel Makefile (the SVGA_MODE=... line) or by the "vga=..."
 option of LILO (or some other boot loader you use) or by the "vidmode" utility
 (present in standard Linux utility packages). You can use the following values
-of this parameter:
+of this parameter::
 
    NORMAL_VGA - Standard 80x25 mode available on all display adapters.
 
@@ -37,77 +44,79 @@ of this parameter:
       for exact meaning of the ID). Warning: rdev and LILO don't support
       hexadecimal numbers -- you have to convert it to decimal manually.
 
-2. Menu
-~~~~~~~
-   The ASK_VGA mode causes the kernel to offer a video mode menu upon
+Menu
+~~~~
+
+The ASK_VGA mode causes the kernel to offer a video mode menu upon
 bootup. It displays a "Press <RETURN> to see video modes available, <SPACE>
 to continue or wait 30 secs" message. If you press <RETURN>, you enter the
 menu, if you press <SPACE> or wait 30 seconds, the kernel will boot up in
 the standard 80x25 mode.
 
-   The menu looks like:
+The menu looks like::
 
-Video adapter: <name-of-detected-video-adapter>
-Mode:    COLSxROWS:
-0  0F00  80x25
-1  0F01  80x50
-2  0F02  80x43
-3  0F03  80x26
-....
-Enter mode number or `scan': <flashing-cursor-here>
+       Video adapter: <name-of-detected-video-adapter>
+       Mode:    COLSxROWS:
+       0  0F00  80x25
+       1  0F01  80x50
+       2  0F02  80x43
+       3  0F03  80x26
+       ....
+       Enter mode number or ``scan``: <flashing-cursor-here>
 
-   <name-of-detected-video-adapter> tells what video adapter did Linux detect
+<name-of-detected-video-adapter> tells what video adapter did Linux detect
 -- it's either a generic adapter name (MDA, CGA, HGC, EGA, VGA, VESA VGA [a VGA
 with VESA-compliant BIOS]) or a chipset name (e.g., Trident). Direct detection
 of chipsets is turned off by default (see CONFIG_VIDEO_SVGA in chapter 4 to see
 how to enable it if you really want) as it's inherently unreliable due to
 absolutely insane PC design.
 
-   "0  0F00  80x25" means that the first menu item (the menu items are numbered
+"0  0F00  80x25" means that the first menu item (the menu items are numbered
 from "0" to "9" and from "a" to "z") is a 80x25 mode with ID=0x0f00 (see the
 next section for a description of mode IDs).
 
-   <flashing-cursor-here> encourages you to enter the item number or mode ID
+<flashing-cursor-here> encourages you to enter the item number or mode ID
 you wish to set and press <RETURN>. If the computer complains something about
 "Unknown mode ID", it is trying to tell you that it isn't possible to set such
 a mode. It's also possible to press only <RETURN> which leaves the current mode.
 
-   The mode list usually contains a few basic modes and some VESA modes.  In
+The mode list usually contains a few basic modes and some VESA modes.  In
 case your chipset has been detected, some chipset-specific modes are shown as
 well (some of these might be missing or unusable on your machine as different
 BIOSes are often shipped with the same card and the mode numbers depend purely
 on the VGA BIOS).
 
-   The modes displayed on the menu are partially sorted: The list starts with
+The modes displayed on the menu are partially sorted: The list starts with
 the standard modes (80x25 and 80x50) followed by "special" modes (80x28 and
 80x43), local modes (if the local modes feature is enabled), VESA modes and
 finally SVGA modes for the auto-detected adapter.
 
-   If you are not happy with the mode list offered (e.g., if you think your card
+If you are not happy with the mode list offered (e.g., if you think your card
 is able to do more), you can enter "scan" instead of item number / mode ID.  The
 program will try to ask the BIOS for all possible video mode numbers and test
 what happens then. The screen will be probably flashing wildly for some time and
 strange noises will be heard from inside the monitor and so on and then, really
 all consistent video modes supported by your BIOS will appear (plus maybe some
-`ghost modes'). If you are afraid this could damage your monitor, don't use this
-function.
+``ghost modes``). If you are afraid this could damage your monitor, don't use
+this function.
 
-   After scanning, the mode ordering is a bit different: the auto-detected SVGA
-modes are not listed at all and the modes revealed by `scan' are shown before
+After scanning, the mode ordering is a bit different: the auto-detected SVGA
+modes are not listed at all and the modes revealed by ``scan`` are shown before
 all VESA modes.
 
-3. Mode IDs
-~~~~~~~~~~~
-   Because of the complexity of all the video stuff, the video mode IDs
+Mode IDs
+~~~~~~~~
+
+Because of the complexity of all the video stuff, the video mode IDs
 used here are also a bit complex. A video mode ID is a 16-bit number usually
 expressed in a hexadecimal notation (starting with "0x"). You can set a mode
 by entering its mode directly if you know it even if it isn't shown on the menu.
 
-The ID numbers can be divided to three regions:
+The ID numbers can be divided to those regions::
 
    0x0000 to 0x00ff - menu item references. 0x0000 is the first item. Don't use
        outside the menu as this can change from boot to boot (especially if you
-       have used the `scan' feature).
+       have used the ``scan`` feature).
 
    0x0100 to 0x017f - standard BIOS modes. The ID is a BIOS video mode number
        (as presented to INT 10, function 00) increased by 0x0100.
@@ -142,53 +151,54 @@ The ID numbers can be divided to three regions:
        0xffff  equivalent to 0x0f00 (standard 80x25)
        0xfffe  equivalent to 0x0f01 (EGA 80x43 or VGA 80x50)
 
-   If you add 0x8000 to the mode ID, the program will try to recalculate
+If you add 0x8000 to the mode ID, the program will try to recalculate
 vertical display timing according to mode parameters, which can be used to
 eliminate some annoying bugs of certain VGA BIOSes (usually those used for
 cards with S3 chipsets and old Cirrus Logic BIOSes) -- mainly extra lines at the
 end of the display.
 
-4. Options
-~~~~~~~~~~
-   Some options can be set in the source text (in arch/i386/boot/video.S).
+Options
+~~~~~~~
+
+Some options can be set in the source text (in arch/i386/boot/video.S).
 All of them are simple #define's -- change them to #undef's when you want to
 switch them off. Currently supported:
 
-   CONFIG_VIDEO_SVGA - enables autodetection of SVGA cards. This is switched
+CONFIG_VIDEO_SVGA - enables autodetection of SVGA cards. This is switched
 off by default as it's a bit unreliable due to terribly bad PC design. If you
-really want to have the adapter autodetected (maybe in case the `scan' feature
+really want to have the adapter autodetected (maybe in case the ``scan`` feature
 doesn't work on your machine), switch this on and don't cry if the results
 are not completely sane. In case you really need this feature, please drop me
 a mail as I think of removing it some day.
 
-   CONFIG_VIDEO_VESA - enables autodetection of VESA modes. If it doesn't work
+CONFIG_VIDEO_VESA - enables autodetection of VESA modes. If it doesn't work
 on your machine (or displays a "Error: Scanning of VESA modes failed" message),
 you can switch it off and report as a bug.
 
-   CONFIG_VIDEO_COMPACT - enables compacting of the video mode list. If there
+CONFIG_VIDEO_COMPACT - enables compacting of the video mode list. If there
 are more modes with the same screen size, only the first one is kept (see above
 for more info on mode ordering). However, in very strange cases it's possible
 that the first "version" of the mode doesn't work although some of the others
 do -- in this case turn this switch off to see the rest.
 
-   CONFIG_VIDEO_RETAIN - enables retaining of screen contents when switching
+CONFIG_VIDEO_RETAIN - enables retaining of screen contents when switching
 video modes. Works only with some boot loaders which leave enough room for the
 buffer. (If you have old LILO, you can adjust heap_end_ptr and loadflags
 in setup.S, but it's better to upgrade the boot loader...)
 
-   CONFIG_VIDEO_LOCAL - enables inclusion of "local modes" in the list. The
+CONFIG_VIDEO_LOCAL - enables inclusion of "local modes" in the list. The
 local modes are added automatically to the beginning of the list not depending
 on hardware configuration. The local modes are listed in the source text after
 the "local_mode_table:" line. The comment before this line describes the format
 of the table (which also includes a video card name to be displayed on the
 top of the menu).
 
-   CONFIG_VIDEO_400_HACK - force setting of 400 scan lines for standard VGA
+CONFIG_VIDEO_400_HACK - force setting of 400 scan lines for standard VGA
 modes. This option is intended to be used on certain buggy BIOSes which draw
 some useless logo using font download and then fail to reset the correct mode.
 Don't use unless needed as it forces resetting the video card.
 
-   CONFIG_VIDEO_GFX_HACK - includes special hack for setting of graphics modes
+CONFIG_VIDEO_GFX_HACK - includes special hack for setting of graphics modes
 to be used later by special drivers (e.g., 800x600 on IBM ThinkPad -- see
 ftp://ftp.phys.keio.ac.jp/pub/XFree86/800x600/XF86Configs/XF86Config.IBM_TP560).
 Allows to set _any_ BIOS mode including graphic ones and forcing specific
@@ -196,33 +206,36 @@ text screen resolution instead of peeking it from BIOS variables. Don't use
 unless you think you know what you're doing. To activate this setup, use
 mode number 0x0f08 (see section 3).
 
-5. Still doesn't work?
-~~~~~~~~~~~~~~~~~~~~~~
-   When the mode detection doesn't work (e.g., the mode list is incorrect or
+Still doesn't work?
+~~~~~~~~~~~~~~~~~~~
+
+When the mode detection doesn't work (e.g., the mode list is incorrect or
 the machine hangs instead of displaying the menu), try to switch off some of
 the configuration options listed in section 4. If it fails, you can still use
 your kernel with the video mode set directly via the kernel parameter.
 
-   In either case, please send me a bug report containing what _exactly_
+In either case, please send me a bug report containing what _exactly_
 happens and how do the configuration switches affect the behaviour of the bug.
 
-   If you start Linux from M$-DOS, you might also use some DOS tools for
+If you start Linux from M$-DOS, you might also use some DOS tools for
 video mode setting. In this case, you must specify the 0x0f04 mode ("leave
 current settings") to Linux, because if you don't and you use any non-standard
 mode, Linux will switch to 80x25 automatically.
 
-   If you set some extended mode and there's one or more extra lines on the
+If you set some extended mode and there's one or more extra lines on the
 bottom of the display containing already scrolled-out text, your VGA BIOS
 contains the most common video BIOS bug called "incorrect vertical display
 end setting". Adding 0x8000 to the mode ID might fix the problem. Unfortunately,
 this must be done manually -- no autodetection mechanisms are available.
 
-   If you have a VGA card and your display still looks as on EGA, your BIOS
+If you have a VGA card and your display still looks as on EGA, your BIOS
 is probably broken and you need to set the CONFIG_VIDEO_400_HACK switch to
 force setting of the correct mode.
 
-6. History
-~~~~~~~~~~
+History
+~~~~~~~
+
+=============== ================================================================
 1.0 (??-Nov-95)        First version supporting all adapters supported by the old
                setup.S + Cirrus Logic 54XX. Present in some 1.3.4? kernels
                and then removed due to instability on some machines.
@@ -260,17 +273,18 @@ force setting of the correct mode.
                  original version written by hhanemaa@cs.ruu.nl, patched by
                  Jeff Chua, rewritten by me).
                - Screen store/restore fixed.
-2.8 (14-Apr-96)        - Previous release was not compilable without CONFIG_VIDEO_SVGA.
+2.8 (14-Apr-96) - Previous release was not compilable without CONFIG_VIDEO_SVGA.
                - Better recognition of text modes during mode scan.
 2.9 (12-May-96)        - Ignored VESA modes 0x80 - 0xff (more VESA BIOS bugs!)
-2.10 (11-Nov-96)- The whole thing made optional.
+2.10(11-Nov-96) - The whole thing made optional.
                - Added the CONFIG_VIDEO_400_HACK switch.
                - Added the CONFIG_VIDEO_GFX_HACK switch.
                - Code cleanup.
-2.11 (03-May-97)- Yet another cleanup, now including also the documentation.
-               - Direct testing of SVGA adapters turned off by default, `scan'
+2.11(03-May-97) - Yet another cleanup, now including also the documentation.
+               - Direct testing of SVGA adapters turned off by default, ``scan``
                  offered explicitly on the prompt line.
                - Removed the doc section describing adding of new probing
                  functions as I try to get rid of _all_ hardware probing here.
-2.12 (25-May-98)- Added support for VESA frame buffer graphics.
-2.13 (14-May-99)- Minor documentation fixes.
+2.12(25-May-98) Added support for VESA frame buffer graphics.
+2.13(14-May-99) Minor documentation fixes.
+=============== ================================================================
index 7185993..56ea85f 100644 (file)
@@ -1,4 +1,7 @@
+=============
 TEE subsystem
+=============
+
 This document describes the TEE subsystem in Linux.
 
 A TEE (Trusted Execution Environment) is a trusted OS running in some
@@ -80,27 +83,27 @@ The GlobalPlatform TEE Client API [5] is implemented on top of the generic
 TEE API.
 
 Picture of the relationship between the different components in the
-OP-TEE architecture.
-
-    User space                  Kernel                   Secure world
-    ~~~~~~~~~~                  ~~~~~~                   ~~~~~~~~~~~~
- +--------+                                             +-------------+
- | Client |                                             | Trusted     |
- +--------+                                             | Application |
-    /\                                                  +-------------+
-    || +----------+                                           /\
-    || |tee-      |                                           ||
-    || |supplicant|                                           \/
-    || +----------+                                     +-------------+
-    \/      /\                                          | TEE Internal|
- +-------+  ||                                          | API         |
- + TEE   |  ||            +--------+--------+           +-------------+
- | Client|  ||            | TEE    | OP-TEE |           | OP-TEE      |
- | API   |  \/            | subsys | driver |           | Trusted OS  |
- +-------+----------------+----+-------+----+-----------+-------------+
- |      Generic TEE API        |       |     OP-TEE MSG               |
- |      IOCTL (TEE_IOC_*)      |       |     SMCCC (OPTEE_SMC_CALL_*) |
- +-----------------------------+       +------------------------------+
+OP-TEE architecture::
+
+      User space                  Kernel                   Secure world
+      ~~~~~~~~~~                  ~~~~~~                   ~~~~~~~~~~~~
  +--------+                                             +-------------+
  | Client |                                             | Trusted     |
  +--------+                                             | Application |
+      /\                                                  +-------------+
+      || +----------+                                           /\
+      || |tee-      |                                           ||
+      || |supplicant|                                           \/
+      || +----------+                                     +-------------+
+      \/      /\                                          | TEE Internal|
  +-------+  ||                                          | API         |
  + TEE   |  ||            +--------+--------+           +-------------+
  | Client|  ||            | TEE    | OP-TEE |           | OP-TEE      |
  | API   |  \/            | subsys | driver |           | Trusted OS  |
  +-------+----------------+----+-------+----+-----------+-------------+
  |      Generic TEE API        |       |     OP-TEE MSG               |
  |      IOCTL (TEE_IOC_*)      |       |     SMCCC (OPTEE_SMC_CALL_*) |
  +-----------------------------+       +------------------------------+
 
 RPC (Remote Procedure Call) are requests from secure world to kernel driver
 or tee-supplicant. An RPC is identified by a special range of SMCCC return
@@ -109,10 +112,16 @@ kernel are handled by the kernel driver. Other RPC messages will be forwarded to
 tee-supplicant without further involvement of the driver, except switching
 shared memory buffer representation.
 
-References:
+References
+==========
+
 [1] https://github.com/OP-TEE/optee_os
+
 [2] http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
+
 [3] drivers/tee/optee/optee_smc.h
+
 [4] drivers/tee/optee/optee_msg.h
+
 [5] http://www.globalplatform.org/specificationsdevice.asp look for
     "TEE Client API Specification v1.0" and click download.
index 2cbf719..5cb8b88 100644 (file)
@@ -1,5 +1,9 @@
+===================
 this_cpu operations
--------------------
+===================
+
+:Author: Christoph Lameter, August 4th, 2014
+:Author: Pranith Kumar, Aug 2nd, 2014
 
 this_cpu operations are a way of optimizing access to per cpu
 variables associated with the *currently* executing processor. This is
@@ -39,7 +43,7 @@ operations.
 
 The following this_cpu() operations with implied preemption protection
 are defined. These operations can be used without worrying about
-preemption and interrupts.
+preemption and interrupts::
 
        this_cpu_read(pcp)
        this_cpu_write(pcp, val)
@@ -67,14 +71,14 @@ to relocate a per cpu relative address to the proper per cpu area for
 the processor. So the relocation to the per cpu base is encoded in the
 instruction via a segment register prefix.
 
-For example:
+For example::
 
        DEFINE_PER_CPU(int, x);
        int z;
 
        z = this_cpu_read(x);
 
-results in a single instruction
+results in a single instruction::
 
        mov ax, gs:[x]
 
@@ -84,16 +88,16 @@ 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.
 
-Consider the following this_cpu operation:
+Consider the following this_cpu operation::
 
        this_cpu_inc(x)
 
-The above 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;
@@ -121,8 +125,10 @@ has to be paid for this optimization is the need to add up the per cpu
 counters when the value of a counter is needed.
 
 
-Special operations:
--------------------
+Special operations
+------------------
+
+::
 
        y = this_cpu_ptr(&x)
 
@@ -153,11 +159,15 @@ 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.
 
+::
+
        DEFINE_PER_CPU(int, x);
 
 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.
 
+::
+
        int __percpu *p = &x;
 
 &x and hence p is the *offset* of a per cpu variable. this_cpu_ptr()
@@ -168,7 +178,7 @@ strange.
 Operations on a field of a per cpu structure
 --------------------------------------------
 
-Let's say we have a percpu structure
+Let's say we have a percpu structure::
 
        struct s {
                int n,m;
@@ -177,14 +187,14 @@ Let's say we have a percpu structure
        DEFINE_PER_CPU(struct s, p);
 
 
-Operations on these fields are straightforward
+Operations on these fields are straightforward::
 
        this_cpu_inc(p.m)
 
        z = this_cpu_cmpxchg(p.m, 0, 1);
 
 
-If we have an offset to struct s:
+If we have an offset to struct s::
 
        struct s __percpu *ps = &p;
 
@@ -194,7 +204,7 @@ If we have an offset to struct s:
 
 
 The calculation of the pointer may require the use of this_cpu_ptr()
-if we do not make use of this_cpu ops later to manipulate fields:
+if we do not make use of this_cpu ops later to manipulate fields::
 
        struct s *pp;
 
@@ -206,7 +216,7 @@ 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 architectures do not support
 these per cpu local operations. In that case the operation must be
@@ -222,7 +232,7 @@ 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.
+safe::
 
        __this_cpu_read(pcp)
        __this_cpu_write(pcp, val)
@@ -279,7 +289,7 @@ 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:
+function is used::
 
 
        DEFINE_PER_CPU(struct data, datap);
@@ -289,7 +299,7 @@ function is used:
 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
+You can also do the following to convert the datap offset to an address::
 
        struct data *p = this_cpu_ptr(&datap);
 
@@ -305,7 +315,7 @@ 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
+Consider the following example::
 
 
        struct test {
@@ -327,6 +337,3 @@ 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 fff8ff6..d4601df 100644 (file)
@@ -5,10 +5,11 @@ Copyright 2008 Red Hat Inc.
    Author:   Steven Rostedt <srostedt@redhat.com>
   License:   The GNU Free Documentation License, Version 1.2
                (dual licensed under the GPL v2)
-Reviewers:   Elias Oltmanns, Randy Dunlap, Andrew Morton,
-            John Kacur, and David Teigland.
+Original Reviewers:   Elias Oltmanns, Randy Dunlap, Andrew Morton,
+                     John Kacur, and David Teigland.
 Written for: 2.6.28-rc2
 Updated for: 3.10
+Updated for: 4.13 - Copyright 2017 VMware Inc. Steven Rostedt
 
 Introduction
 ------------
@@ -26,9 +27,11 @@ a task is woken to the task is actually scheduled in.
 
 One of the most common uses of ftrace is the event tracing.
 Through out the kernel is hundreds of static event points that
-can be enabled via the debugfs file system to see what is
+can be enabled via the tracefs file system to see what is
 going on in certain parts of the kernel.
 
+See events.txt for more information.
+
 
 Implementation Details
 ----------------------
@@ -39,34 +42,47 @@ See ftrace-design.txt for details for arch porters and such.
 The File System
 ---------------
 
-Ftrace uses the debugfs file system to hold the control files as
+Ftrace uses the tracefs file system to hold the control files as
 well as the files to display output.
 
-When debugfs is configured into the kernel (which selecting any ftrace
-option will do) the directory /sys/kernel/debug will be created. To mount
+When tracefs is configured into the kernel (which selecting any ftrace
+option will do) the directory /sys/kernel/tracing will be created. To mount
 this directory, you can add to your /etc/fstab file:
 
debugfs       /sys/kernel/debug          debugfs defaults        0       0
tracefs       /sys/kernel/tracing       tracefs defaults        0       0
 
 Or you can mount it at run time with:
 
- mount -t debugfs nodev /sys/kernel/debug
+ mount -t tracefs nodev /sys/kernel/tracing
 
 For quicker access to that directory you may want to make a soft link to
 it:
 
- ln -s /sys/kernel/debug /debug
+ ln -s /sys/kernel/tracing /tracing
+
+     *** NOTICE ***
+
+Before 4.1, all ftrace tracing control files were within the debugfs
+file system, which is typically located at /sys/kernel/debug/tracing.
+For backward compatibility, when mounting the debugfs file system,
+the tracefs file system will be automatically mounted at:
+
+ /sys/kernel/debug/tracing
 
-Any selected ftrace option will also create a directory called tracing
-within the debugfs. The rest of the document will assume that you are in
-the ftrace directory (cd /sys/kernel/debug/tracing) and will only concentrate
-on the files within that directory and not distract from the content with
-the extended "/sys/kernel/debug/tracing" path name.
+All files located in the tracefs file system will be located in that
+debugfs file system directory as well.
+
+     *** NOTICE ***
+
+Any selected ftrace option will also create the tracefs file system.
+The rest of the document will assume that you are in the ftrace directory
+(cd /sys/kernel/tracing) and will only concentrate on the files within that
+directory and not distract from the content with the extended
+"/sys/kernel/tracing" path name.
 
 That's it! (assuming that you have ftrace configured into your kernel)
 
-After mounting debugfs, you can see a directory called
-"tracing".  This directory contains the control and output files
+After mounting tracefs you will have access to the control and output files
 of ftrace. Here is a list of some of the key files:
 
 
@@ -92,10 +108,20 @@ of ftrace. Here is a list of some of the key files:
        writing to the ring buffer, the tracing overhead may
        still be occurring.
 
+       The kernel function tracing_off() can be used within the
+       kernel to disable writing to the ring buffer, which will
+       set this file to "0". User space can re-enable tracing by
+       echoing "1" into the file.
+
+       Note, the function and event trigger "traceoff" will also
+       set this file to zero and stop tracing. Which can also
+       be re-enabled by user space using this file.
+
   trace:
 
        This file holds the output of the trace in a human
-       readable format (described below).
+       readable format (described below). Note, tracing is temporarily
+       disabled while this file is being read (opened).
 
   trace_pipe:
 
@@ -109,7 +135,8 @@ of ftrace. Here is a list of some of the key files:
        will not be read again with a sequential read. The
        "trace" file is static, and if the tracer is not
        adding more data, it will display the same
-       information every time it is read.
+       information every time it is read. This file will not
+       disable tracing while being read.
 
   trace_options:
 
@@ -128,12 +155,14 @@ of ftrace. Here is a list of some of the key files:
   tracing_max_latency:
 
        Some of the tracers record the max latency.
-       For example, the time interrupts are disabled.
-       This time is saved in this file. The max trace
-       will also be stored, and displayed by "trace".
-       A new max trace will only be recorded if the
-       latency is greater than the value in this
-       file. (in microseconds)
+       For example, the maximum time that interrupts are disabled.
+       The maximum time is saved in this file. The max trace will also be
+       stored, and displayed by "trace". A new max trace will only be
+       recorded if the latency is greater than the value in this file
+       (in microseconds).
+
+       By echoing in a time into this file, no latency will be recorded
+       unless it is greater than the time in this file.
 
   tracing_thresh:
 
@@ -152,32 +181,34 @@ of ftrace. Here is a list of some of the key files:
        that the kernel uses for allocation, usually 4 KB in size).
        If the last page allocated has room for more bytes
        than requested, the rest of the page will be used,
-       making the actual allocation bigger than requested.
+       making the actual allocation bigger than requested or shown.
        ( Note, the size may not be a multiple of the page size
          due to buffer management meta-data. )
 
+       Buffer sizes for individual CPUs may vary
+       (see "per_cpu/cpu0/buffer_size_kb" below), and if they do
+       this file will show "X".
+
   buffer_total_size_kb:
 
        This displays the total combined size of all the trace buffers.
 
   free_buffer:
 
-       If a process is performing the tracing, and the ring buffer
-       should be shrunk "freed" when the process is finished, even
-       if it were to be killed by a signal, this file can be used
-       for that purpose. On close of this file, the ring buffer will
-       be resized to its minimum size. Having a process that is tracing
-       also open this file, when the process exits its file descriptor
-       for this file will be closed, and in doing so, the ring buffer
-       will be "freed".
+       If a process is performing tracing, and the ring buffer should be
+       shrunk "freed" when the process is finished, even if it were to be
+       killed by a signal, this file can be used for that purpose. On close
+       of this file, the ring buffer will be resized to its minimum size.
+       Having a process that is tracing also open this file, when the process
+       exits its file descriptor for this file will be closed, and in doing so,
+       the ring buffer will be "freed".
 
        It may also stop tracing if disable_on_free option is set.
 
   tracing_cpumask:
 
-       This is a mask that lets the user only trace
-       on specified CPUs. The format is a hex string
-       representing the CPUs.
+       This is a mask that lets the user only trace on specified CPUs.
+       The format is a hex string representing the CPUs.
 
   set_ftrace_filter:
 
@@ -190,6 +221,9 @@ of ftrace. Here is a list of some of the key files:
        to be traced. Echoing names of functions into this file
        will limit the trace to only those functions.
 
+       The functions listed in "available_filter_functions" are what
+       can be written into this file.
+
        This interface also allows for commands to be used. See the
        "Filter commands" section for more details.
 
@@ -202,7 +236,14 @@ of ftrace. Here is a list of some of the key files:
 
   set_ftrace_pid:
 
-       Have the function tracer only trace a single thread.
+       Have the function tracer only trace the threads whose PID are
+       listed in this file.
+
+       If the "function-fork" option is set, then when a task whose
+       PID is listed in this file forks, the child's PID will
+       automatically be added to this file, and the child will be
+       traced by the function tracer as well. This option will also
+       cause PIDs of tasks that exit to be removed from the file.
 
   set_event_pid:
 
@@ -217,17 +258,28 @@ of ftrace. Here is a list of some of the key files:
 
   set_graph_function:
 
-       Set a "trigger" function where tracing should start
-       with the function graph tracer (See the section
-       "dynamic ftrace" for more details).
+       Functions listed in this file will cause the function graph
+       tracer to only trace these functions and the functions that
+       they call. (See the section "dynamic ftrace" for more details).
+
+  set_graph_notrace:
+
+       Similar to set_graph_function, but will disable function graph
+       tracing when the function is hit until it exits the function.
+       This makes it possible to ignore tracing functions that are called
+       by a specific function.
 
   available_filter_functions:
 
-       This lists the functions that ftrace
-       has processed and can trace. These are the function
-       names that you can pass to "set_ftrace_filter" or
-       "set_ftrace_notrace". (See the section "dynamic ftrace"
-       below for more details.)
+       This lists the functions that ftrace has processed and can trace.
+       These are the function names that you can pass to
+       "set_ftrace_filter" or "set_ftrace_notrace".
+       (See the section "dynamic ftrace" below for more details.)
+
+  dyn_ftrace_total_info:
+
+       This file is for debugging purposes. The number of functions that
+       have been converted to nops and are available to be traced.
 
   enabled_functions:
 
@@ -250,12 +302,21 @@ of ftrace. Here is a list of some of the key files:
        an 'I' will be displayed on the same line as the function that
        can be overridden.
 
+       If the architecture supports it, it will also show what callback
+       is being directly called by the function. If the count is greater
+       than 1 it most likely will be ftrace_ops_list_func().
+
+       If the callback of the function jumps to a trampoline that is
+       specific to a the callback and not the standard trampoline,
+       its address will be printed as well as the function that the
+       trampoline calls.
+
   function_profile_enabled:
 
        When set it will enable all functions with either the function
-       tracer, or if enabled, the function graph tracer. It will
+       tracer, or if configured, the function graph tracer. It will
        keep a histogram of the number of functions that were called
-       and if run with the function graph tracer, it will also keep
+       and if the function graph tracer was configured, it will also keep
        track of the time spent in those functions. The histogram
        content can be displayed in the files:
 
@@ -283,12 +344,11 @@ of ftrace. Here is a list of some of the key files:
   printk_formats:
 
        This is for tools that read the raw format files. If an event in
-       the ring buffer references a string (currently only trace_printk()
-       does this), only a pointer to the string is recorded into the buffer
-       and not the string itself. This prevents tools from knowing what
-       that string was. This file displays the string and address for
-       the string allowing tools to map the pointers to what the
-       strings were.
+       the ring buffer references a string, only a pointer to the string
+       is recorded into the buffer and not the string itself. This prevents
+       tools from knowing what that string was. This file displays the string
+       and address for the string allowing tools to map the pointers to what
+       the strings were.
 
   saved_cmdlines:
 
@@ -298,6 +358,22 @@ of ftrace. Here is a list of some of the key files:
        comms for events. If a pid for a comm is not listed, then
        "<...>" is displayed in the output.
 
+       If the option "record-cmd" is set to "0", then comms of tasks
+       will not be saved during recording. By default, it is enabled.
+
+  saved_cmdlines_size:
+
+       By default, 128 comms are saved (see "saved_cmdlines" above). To
+       increase or decrease the amount of comms that are cached, echo
+       in a the number of comms to cache, into this file.
+
+  saved_tgids:
+
+       If the option "record-tgid" is set, on each scheduling context switch
+       the Task Group ID of a task is saved in a table mapping the PID of
+       the thread to its TGID. By default, the "record-tgid" option is
+       disabled.
+
   snapshot:
 
        This displays the "snapshot" buffer and also lets the user
@@ -336,6 +412,9 @@ of ftrace. Here is a list of some of the key files:
          # cat trace_clock
          [local] global counter x86-tsc
 
+         The clock with the square brackets around it is the one
+         in effect.
+
          local: Default clock, but may not be in sync across CPUs
 
          global: This clock is in sync with all CPUs but may
@@ -448,6 +527,23 @@ of ftrace. Here is a list of some of the key files:
 
        See events.txt for more information.
 
+  set_event:
+
+       By echoing in the event into this file, will enable that event.
+
+       See events.txt for more information.
+
+  available_events:
+
+       A list of events that can be enabled in tracing.
+
+       See events.txt for more information.
+
+  hwlat_detector:
+
+       Directory for the Hardware Latency Detector.
+       See "Hardware Latency Detector" section below.
+
   per_cpu:
 
        This is a directory that contains the trace per_cpu information.
@@ -539,13 +635,25 @@ Here is the list of current tracers that may be configured.
        to draw a graph of function calls similar to C code
        source.
 
+  "blk"
+
+       The block tracer. The tracer used by the blktrace user
+       application.
+
+  "hwlat"
+
+       The Hardware Latency tracer is used to detect if the hardware
+       produces any latency. See "Hardware Latency Detector" section
+       below.
+
   "irqsoff"
 
        Traces the areas that disable interrupts and saves
        the trace with the longest max latency.
        See tracing_max_latency. When a new max is recorded,
        it replaces the old trace. It is best to view this
-       trace with the latency-format option enabled.
+       trace with the latency-format option enabled, which
+       happens automatically when the tracer is selected.
 
   "preemptoff"
 
@@ -571,6 +679,26 @@ Here is the list of current tracers that may be configured.
         RT tasks (as the current "wakeup" does). This is useful
         for those interested in wake up timings of RT tasks.
 
+  "wakeup_dl"
+
+       Traces and records the max latency that it takes for
+       a SCHED_DEADLINE task to be woken (as the "wakeup" and
+       "wakeup_rt" does).
+
+  "mmiotrace"
+
+       A special tracer that is used to trace binary module.
+       It will trace all the calls that a module makes to the
+       hardware. Everything it writes and reads from the I/O
+       as well.
+
+  "branch"
+
+       This tracer can be configured when tracing likely/unlikely
+       calls within the kernel. It will trace when a likely and
+       unlikely branch is hit and if it was correct in its prediction
+       of being correct.
+
   "nop"
 
        This is the "trace nothing" tracer. To remove all
@@ -582,7 +710,7 @@ Examples of using the tracer
 ----------------------------
 
 Here are typical examples of using the tracers when controlling
-them only with the debugfs interface (without using any
+them only with the tracefs interface (without using any
 user-land utilities).
 
 Output format:
@@ -674,7 +802,7 @@ why a latency happened. Here is a typical trace.
 This shows that the current tracer is "irqsoff" tracing the time
 for which interrupts were disabled. It gives the trace version (which
 never changes) and the version of the kernel upon which this was executed on
-(3.10). Then it displays the max latency in microseconds (259 us). The number
+(3.8). Then it displays the max latency in microseconds (259 us). The number
 of trace entries displayed and the total number (both are four: #4/4).
 VP, KP, SP, and HP are always zero and are reserved for later use.
 #P is the number of online CPUs (#P:4).
@@ -709,6 +837,8 @@ explains which is which.
        '.' otherwise.
 
   hardirq/softirq:
+       'Z' - NMI occurred inside a hardirq
+       'z' - NMI is running
        'H' - hard irq occurred inside a softirq.
        'h' - hard irq is running
        's' - soft irq is running
@@ -757,24 +887,24 @@ nohex
 nobin
 noblock
 trace_printk
-nobranch
 annotate
 nouserstacktrace
 nosym-userobj
 noprintk-msg-only
 context-info
 nolatency-format
-sleep-time
-graph-time
 record-cmd
+norecord-tgid
 overwrite
 nodisable_on_free
 irq-info
 markers
 noevent-fork
 function-trace
+nofunction-fork
 nodisplay-graph
 nostacktrace
+nobranch
 
 To disable one of the options, echo in the option prepended with
 "no".
@@ -830,8 +960,6 @@ Here are the available options:
 
   trace_printk - Can disable trace_printk() from writing into the buffer.
 
-  branch - Enable branch tracing with the tracer.
-
   annotate - It is sometimes confusing when the CPU buffers are full
             and one CPU buffer had a lot of events recently, thus
             a shorter time frame, were another CPU may have only had
@@ -850,7 +978,8 @@ Here are the available options:
           <idle>-0     [001] .Ns3 21169.031485: sub_preempt_count <-_raw_spin_unlock
 
   userstacktrace - This option changes the trace. It records a
-                  stacktrace of the current userspace thread.
+                  stacktrace of the current user space thread after
+                  each trace event.
 
   sym-userobj - when user stacktrace are enabled, look up which
                object the address belongs to, and print a
@@ -873,29 +1002,21 @@ x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6]
   context-info - Show only the event data. Hides the comm, PID,
                 timestamp, CPU, and other useful data.
 
-  latency-format - This option changes the trace. When
-                   it is enabled, the trace displays
-                   additional information about the
-                   latencies, as described in "Latency
-                   trace format".
-
-  sleep-time - When running function graph tracer, to include
-              the time a task schedules out in its function.
-              When enabled, it will account time the task has been
-              scheduled out as part of the function call.
-
-  graph-time - When running function profiler with function graph tracer,
-              to include the time to call nested functions. When this is
-              not set, the time reported for the function will only
-              include the time the function itself executed for, not the
-              time for functions that it called.
+  latency-format - This option changes the trace output. When it is enabled,
+                  the trace displays additional information about the
+                  latency, as described in "Latency trace format".
 
   record-cmd - When any event or tracer is enabled, a hook is enabled
-              in the sched_switch trace point to fill comm cache
+              in the sched_switch trace point to fill comm cache
               with mapped pids and comms. But this may cause some
               overhead, and if you only care about pids, and not the
               name of the task, disabling this option can lower the
-              impact of tracing.
+              impact of tracing. See "saved_cmdlines".
+
+  record-tgid - When any event or tracer is enabled, a hook is enabled
+               in the sched_switch trace point to fill the cache of
+               mapped Thread Group IDs (TGID) mapping to pids. See
+               "saved_tgids".
 
   overwrite - This controls what happens when the trace buffer is
               full. If "1" (default), the oldest events are
@@ -935,19 +1056,98 @@ x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6]
            functions. This keeps the overhead of the tracer down
            when performing latency tests.
 
+  function-fork - When set, tasks with PIDs listed in set_ftrace_pid will
+                 have the PIDs of their children added to set_ftrace_pid
+                 when those tasks fork. Also, when tasks with PIDs in
+                 set_ftrace_pid exit, their PIDs will be removed from the
+                 file.
+
   display-graph - When set, the latency tracers (irqsoff, wakeup, etc) will
                  use function graph tracing instead of function tracing.
 
-  stacktrace - This is one of the options that changes the trace
-              itself. When a trace is recorded, so is the stack
-              of functions. This allows for back traces of
-              trace sites.
+  stacktrace - When set, a stack trace is recorded after any trace event
+              is recorded.
+
+  branch - Enable branch tracing with the tracer. This enables branch
+          tracer along with the currently set tracer. Enabling this
+          with the "nop" tracer is the same as just enabling the
+          "branch" tracer.
 
  Note: Some tracers have their own options. They only appear in this
        file when the tracer is active. They always appear in the
        options directory.
 
 
+Here are the per tracer options:
+
+Options for function tracer:
+
+  func_stack_trace - When set, a stack trace is recorded after every
+                    function that is recorded. NOTE! Limit the functions
+                    that are recorded before enabling this, with
+                    "set_ftrace_filter" otherwise the system performance
+                    will be critically degraded. Remember to disable
+                    this option before clearing the function filter.
+
+Options for function_graph tracer:
+
+ Since the function_graph tracer has a slightly different output
+ it has its own options to control what is displayed.
+
+  funcgraph-overrun - When set, the "overrun" of the graph stack is
+                     displayed after each function traced. The
+                     overrun, is when the stack depth of the calls
+                     is greater than what is reserved for each task.
+                     Each task has a fixed array of functions to
+                     trace in the call graph. If the depth of the
+                     calls exceeds that, the function is not traced.
+                     The overrun is the number of functions missed
+                     due to exceeding this array.
+
+  funcgraph-cpu - When set, the CPU number of the CPU where the trace
+                 occurred is displayed.
+
+  funcgraph-overhead - When set, if the function takes longer than
+                      A certain amount, then a delay marker is
+                      displayed. See "delay" above, under the
+                      header description.
+
+  funcgraph-proc - Unlike other tracers, the process' command line
+                  is not displayed by default, but instead only
+                  when a task is traced in and out during a context
+                  switch. Enabling this options has the command
+                  of each process displayed at every line.
+
+  funcgraph-duration - At the end of each function (the return)
+                      the duration of the amount of time in the
+                      function is displayed in microseconds.
+
+  funcgraph-abstime - When set, the timestamp is displayed at each
+                     line.
+
+  funcgraph-irqs - When disabled, functions that happen inside an
+                  interrupt will not be traced.
+
+  funcgraph-tail - When set, the return event will include the function
+                  that it represents. By default this is off, and
+                  only a closing curly bracket "}" is displayed for
+                  the return of a function.
+
+  sleep-time - When running function graph tracer, to include
+              the time a task schedules out in its function.
+              When enabled, it will account time the task has been
+              scheduled out as part of the function call.
+
+  graph-time - When running function profiler with function graph tracer,
+              to include the time to call nested functions. When this is
+              not set, the time reported for the function will only
+              include the time the function itself executed for, not the
+              time for functions that it called.
+
+Options for blk tracer:
+
+  blk_classic - Shows a more minimalistic output.
+
 
 irqsoff
 -------
@@ -1711,6 +1911,85 @@ events.
   <idle>-0       2d..3    6us :      0:120:R ==> [002]  5882: 94:R sleep
 
 
+Hardware Latency Detector
+-------------------------
+
+The hardware latency detector is executed by enabling the "hwlat" tracer.
+
+NOTE, this tracer will affect the performance of the system as it will
+periodically make a CPU constantly busy with interrupts disabled.
+
+ # echo hwlat > current_tracer
+ # sleep 100
+ # cat trace
+# tracer: hwlat
+#
+#                              _-----=> irqs-off
+#                             / _----=> need-resched
+#                            | / _---=> hardirq/softirq
+#                            || / _--=> preempt-depth
+#                            ||| /     delay
+#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
+#              | |       |   ||||       |         |
+           <...>-3638  [001] d... 19452.055471: #1     inner/outer(us):   12/14    ts:1499801089.066141940
+           <...>-3638  [003] d... 19454.071354: #2     inner/outer(us):   11/9     ts:1499801091.082164365
+           <...>-3638  [002] dn.. 19461.126852: #3     inner/outer(us):   12/9     ts:1499801098.138150062
+           <...>-3638  [001] d... 19488.340960: #4     inner/outer(us):    8/12    ts:1499801125.354139633
+           <...>-3638  [003] d... 19494.388553: #5     inner/outer(us):    8/12    ts:1499801131.402150961
+           <...>-3638  [003] d... 19501.283419: #6     inner/outer(us):    0/12    ts:1499801138.297435289 nmi-total:4 nmi-count:1
+
+
+The above output is somewhat the same in the header. All events will have
+interrupts disabled 'd'. Under the FUNCTION title there is:
+
+ #1 - This is the count of events recorded that were greater than the
+      tracing_threshold (See below).
+
+ inner/outer(us):   12/14
+
+      This shows two numbers as "inner latency" and "outer latency". The test
+      runs in a loop checking a timestamp twice. The latency detected within
+      the two timestamps is the "inner latency" and the latency detected
+      after the previous timestamp and the next timestamp in the loop is
+      the "outer latency".
+
+ ts:1499801089.066141940
+
+      The absolute timestamp that the event happened.
+
+ nmi-total:4 nmi-count:1
+
+      On architectures that support it, if an NMI comes in during the
+      test, the time spent in NMI is reported in "nmi-total" (in
+      microseconds).
+
+      All architectures that have NMIs will show the "nmi-count" if an
+      NMI comes in during the test.
+
+hwlat files:
+
+  tracing_threshold - This gets automatically set to "10" to represent 10
+                     microseconds. This is the threshold of latency that
+                     needs to be detected before the trace will be recorded.
+
+                     Note, when hwlat tracer is finished (another tracer is
+                     written into "current_tracer"), the original value for
+                     tracing_threshold is placed back into this file.
+
+  hwlat_detector/width - The length of time the test runs with interrupts
+                        disabled.
+
+  hwlat_detector/window - The length of time of the window which the test
+                         runs. That is, the test will run for "width"
+                         microseconds per "window" microseconds
+
+  tracing_cpumask - When the test is started. A kernel thread is created that
+                   runs the test. This thread will alternate between CPUs
+                   listed in the tracing_cpumask between each period
+                   (one "window"). To limit the test to specific CPUs
+                   set the mask in this file to only the CPUs that the test
+                   should run on.
+
 function
 --------
 
@@ -1821,15 +2100,15 @@ something like this simple program:
 #define STR(x) _STR(x)
 #define MAX_PATH 256
 
-const char *find_debugfs(void)
+const char *find_tracefs(void)
 {
-       static char debugfs[MAX_PATH+1];
-       static int debugfs_found;
+       static char tracefs[MAX_PATH+1];
+       static int tracefs_found;
        char type[100];
        FILE *fp;
 
-       if (debugfs_found)
-               return debugfs;
+       if (tracefs_found)
+               return tracefs;
 
        if ((fp = fopen("/proc/mounts","r")) == NULL) {
                perror("/proc/mounts");
@@ -1839,27 +2118,27 @@ const char *find_debugfs(void)
        while (fscanf(fp, "%*s %"
                      STR(MAX_PATH)
                      "s %99s %*s %*d %*d\n",
-                     debugfs, type) == 2) {
-               if (strcmp(type, "debugfs") == 0)
+                     tracefs, type) == 2) {
+               if (strcmp(type, "tracefs") == 0)
                        break;
        }
        fclose(fp);
 
-       if (strcmp(type, "debugfs") != 0) {
-               fprintf(stderr, "debugfs not mounted");
+       if (strcmp(type, "tracefs") != 0) {
+               fprintf(stderr, "tracefs not mounted");
                return NULL;
        }
 
-       strcat(debugfs, "/tracing/");
-       debugfs_found = 1;
+       strcat(tracefs, "/tracing/");
+       tracefs_found = 1;
 
-       return debugfs;
+       return tracefs;
 }
 
 const char *tracing_file(const char *file_name)
 {
        static char trace_file[MAX_PATH+1];
-       snprintf(trace_file, MAX_PATH, "%s/%s", find_debugfs(), file_name);
+       snprintf(trace_file, MAX_PATH, "%s/%s", find_tracefs(), file_name);
        return trace_file;
 }
 
@@ -1898,12 +2177,12 @@ Or this simple script!
 ------
 #!/bin/bash
 
-debugfs=`sed -ne 's/^debugfs \(.*\) debugfs.*/\1/p' /proc/mounts`
-echo nop > $debugfs/tracing/current_tracer
-echo 0 > $debugfs/tracing/tracing_on
-echo $$ > $debugfs/tracing/set_ftrace_pid
-echo function > $debugfs/tracing/current_tracer
-echo 1 > $debugfs/tracing/tracing_on
+tracefs=`sed -ne 's/^tracefs \(.*\) tracefs.*/\1/p' /proc/mounts`
+echo nop > $tracefs/tracing/current_tracer
+echo 0 > $tracefs/tracing/tracing_on
+echo $$ > $tracefs/tracing/set_ftrace_pid
+echo function > $tracefs/tracing/current_tracer
+echo 1 > $tracefs/tracing/tracing_on
 exec "$@"
 ------
 
@@ -2145,13 +2424,18 @@ include the -pg switch in the compiling of the kernel.)
 At compile time every C file object is run through the
 recordmcount program (located in the scripts directory). This
 program will parse the ELF headers in the C object to find all
-the locations in the .text section that call mcount. (Note, only
-white listed .text sections are processed, since processing other
-sections like .init.text may cause races due to those sections
-being freed unexpectedly).
-
-A new section called "__mcount_loc" is created that holds
-references to all the mcount call sites in the .text section.
+the locations in the .text section that call mcount. Starting
+with gcc verson 4.6, the -mfentry has been added for x86, which
+calls "__fentry__" instead of "mcount". Which is called before
+the creation of the stack frame.
+
+Note, not all sections are traced. They may be prevented by either
+a notrace, or blocked another way and all inline functions are not
+traced. Check the "available_filter_functions" file to see what functions
+can be traced.
+
+A section called "__mcount_loc" is created that holds
+references to all the mcount/fentry call sites in the .text section.
 The recordmcount program re-links this section back into the
 original object. The final linking stage of the kernel will add all these
 references into a single table.
@@ -2679,7 +2963,7 @@ in time without stopping tracing. Ftrace swaps the current
 buffer with a spare buffer, and tracing continues in the new
 current (=previous spare) buffer.
 
-The following debugfs files in "tracing" are related to this
+The following tracefs files in "tracing" are related to this
 feature:
 
   snapshot:
@@ -2752,7 +3036,7 @@ cat: snapshot: Device or resource busy
 
 Instances
 ---------
-In the debugfs tracing directory is a directory called "instances".
+In the tracefs tracing directory is a directory called "instances".
 This directory can have new directories created inside of it using
 mkdir, and removing directories with rmdir. The directory created
 with mkdir in this directory will already contain files and other
index c6f4ead..38310dc 100644 (file)
@@ -523,11 +523,11 @@ CPU 에게 기대할 수 있는 최소한의 보장사항 몇가지가 있습니
      즉, ACQUIRE 는 최소한의 "취득" 동작처럼, 그리고 RELEASE 는 최소한의 "공개"
      처럼 동작한다는 의미입니다.
 
-atomic_ops.txt 에서 설명되는 어토믹 오퍼레이션들 중에는 완전히 순서잡힌 것들과
-(배리어를 사용하지 않는) 완화된 순서의 것들 외에 ACQUIRE 와 RELEASE 부류의
-것들도 존재합니다.  로드와 스토어를 모두 수행하는 조합된 어토믹 오퍼레이션에서,
-ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE 는 해당
-오퍼레이션의 스토어 부분에만 적용됩니다.
+core-api/atomic_ops.rst 에서 설명되는 어토믹 오퍼레이션들 중에는 완전히
+순서잡힌 것들과 (배리어를 사용하지 않는) 완화된 순서의 것들 외에 ACQUIRE 와
+RELEASE 부류의 것들도 존재합니다.  로드와 스토어를 모두 수행하는 조합된 어토믹
+오퍼레이션에서, ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE 는
+해당 오퍼레이션의 스토어 부분에만 적용됩니다.
 
 메모리 배리어들은 두 CPU 간, 또는 CPU 와 디바이스 간에 상호작용의 가능성이 있을
 때에만 필요합니다.  만약 어떤 코드에 그런 상호작용이 없을 것이 보장된다면, 해당
@@ -1848,7 +1848,7 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
      이 코드는 객체의 업데이트된 death 마크가 레퍼런스 카운터 감소 동작
      *전에* 보일 것을 보장합니다.
 
-     더 많은 정보를 위해선 Documentation/atomic_ops.txt 문서를 참고하세요.
+     더 많은 정보를 위해선 Documentation/core-api/atomic_ops.rst 문서를 참고하세요.
      어디서 이것들을 사용해야 할지 궁금하다면 "어토믹 오퍼레이션" 서브섹션을
      참고하세요.
 
@@ -2550,7 +2550,7 @@ CPU 에서는 사용되는 어토믹 인스트럭션 자체에 메모리 배리
 있는데, 그런 경우에 이 특수 메모리 배리어 도구들은 no-op 이 되어 실질적으로
 아무일도 하지 않습니다.
 
-더 많은 내용을 위해선 Documentation/atomic_ops.txt 를 참고하세요.
+더 많은 내용을 위해선 Documentation/core-api/atomic_ops.rst 를 참고하세요.
 
 
 디바이스 액세스
index 3f76c0c..51b4ff0 100644 (file)
@@ -1,6 +1,15 @@
+=========================
 UNALIGNED MEMORY ACCESSES
 =========================
 
+:Author: Daniel Drake <dsd@gentoo.org>,
+:Author: Johannes Berg <johannes@sipsolutions.net>
+
+:With help from: Alan Cox, Avuton Olrich, Heikki Orsila, Jan Engelhardt,
+  Kyle McMartin, Kyle Moffett, Randy Dunlap, Robert Hancock, Uli Kunitz,
+  Vadim Lobanov
+
+
 Linux runs on a wide variety of architectures which have varying behaviour
 when it comes to memory access. This document presents some details about
 unaligned accesses, why you need to write code that doesn't cause them,
@@ -73,7 +82,7 @@ memory addresses of certain variables, etc.
 
 Fortunately things are not too complex, as in most cases, the compiler
 ensures that things will work for you. For example, take the following
-structure:
+structure::
 
        struct foo {
                u16 field1;
@@ -106,7 +115,7 @@ On a related topic, with the above considerations in mind you may observe
 that you could reorder the fields in the structure in order to place fields
 where padding would otherwise be inserted, and hence reduce the overall
 resident memory size of structure instances. The optimal layout of the
-above example is:
+above example is::
 
        struct foo {
                u32 field2;
@@ -139,21 +148,21 @@ Code that causes unaligned access
 With the above in mind, let's move onto a real life example of a function
 that can cause an unaligned memory access. The following function taken
 from include/linux/etherdevice.h is an optimized routine to compare two
-ethernet MAC addresses for equality.
+ethernet MAC addresses for equality::
 
-bool ether_addr_equal(const u8 *addr1, const u8 *addr2)
-{
-#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+  bool ether_addr_equal(const u8 *addr1, const u8 *addr2)
+  {
+  #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
        u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2)) |
                   ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4)));
 
        return fold == 0;
-#else
+  #else
        const u16 *a = (const u16 *)addr1;
        const u16 *b = (const u16 *)addr2;
        return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0;
-#endif
-}
+  #endif
+  }
 
 In the above function, when the hardware has efficient unaligned access
 capability, there is no issue with this code.  But when the hardware isn't
@@ -171,7 +180,8 @@ as it is a decent optimization for the cases when you can ensure alignment,
 which is true almost all of the time in ethernet networking context.
 
 
-Here is another example of some code that could cause unaligned accesses:
+Here is another example of some code that could cause unaligned accesses::
+
        void myfunc(u8 *data, u32 value)
        {
                [...]
@@ -184,6 +194,7 @@ to an address that is not evenly divisible by 4.
 
 In summary, the 2 main scenarios where you may run into unaligned access
 problems involve:
+
  1. Casting variables to types of different lengths
  2. Pointer arithmetic followed by access to at least 2 bytes of data
 
@@ -195,7 +206,7 @@ The easiest way to avoid unaligned access is to use the get_unaligned() and
 put_unaligned() macros provided by the <asm/unaligned.h> header file.
 
 Going back to an earlier example of code that potentially causes unaligned
-access:
+access::
 
        void myfunc(u8 *data, u32 value)
        {
@@ -204,7 +215,7 @@ access:
                [...]
        }
 
-To avoid the unaligned memory access, you would rewrite it as follows:
+To avoid the unaligned memory access, you would rewrite it as follows::
 
        void myfunc(u8 *data, u32 value)
        {
@@ -215,7 +226,7 @@ To avoid the unaligned memory access, you would rewrite it as follows:
        }
 
 The get_unaligned() macro works similarly. Assuming 'data' is a pointer to
-memory and you wish to avoid unaligned access, its usage is as follows:
+memory and you wish to avoid unaligned access, its usage is as follows::
 
        u32 value = get_unaligned((u32 *) data);
 
@@ -245,18 +256,10 @@ For some ethernet hardware that cannot DMA to unaligned addresses like
 4*n+2 or non-ethernet hardware, this can be a problem, and it is then
 required to copy the incoming frame into an aligned buffer. Because this is
 unnecessary on architectures that can do unaligned accesses, the code can be
-made dependent on CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS like so:
-
-#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
-       skb = original skb
-#else
-       skb = copy skb
-#endif
-
---
-Authors: Daniel Drake <dsd@gentoo.org>,
-         Johannes Berg <johannes@sipsolutions.net>
-With help from: Alan Cox, Avuton Olrich, Heikki Orsila, Jan Engelhardt,
-Kyle McMartin, Kyle Moffett, Randy Dunlap, Robert Hancock, Uli Kunitz,
-Vadim Lobanov
+made dependent on CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS like so::
 
+       #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+               skb = original skb
+       #else
+               skb = copy skb
+       #endif
index e5e57b4..1b39503 100644 (file)
@@ -1,14 +1,17 @@
-/*
- * VFIO Mediated devices
- *
- * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
- *     Author: Neo Jia <cjia@nvidia.com>
- *             Kirti Wankhede <kwankhede@nvidia.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:: <isonum.txt>
+
+=====================
+VFIO Mediated devices
+=====================
+
+:Copyright: |copy| 2016, NVIDIA CORPORATION. All rights reserved.
+:Author: Neo Jia <cjia@nvidia.com>
+:Author: Kirti Wankhede <kwankhede@nvidia.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.
+
 
 Virtual Function I/O (VFIO) Mediated devices[1]
 ===============================================
@@ -42,7 +45,7 @@ removes it from a VFIO group.
 
 The following high-level block diagram shows the main components and interfaces
 in the VFIO mediated driver framework. The diagram shows NVIDIA, Intel, and IBM
-devices as examples, as these devices are the first devices to use this module.
+devices as examples, as these devices are the first devices to use this module::
 
      +---------------+
      |               |
@@ -91,7 +94,7 @@ Registration Interface for a Mediated Bus Driver
 ------------------------------------------------
 
 The registration interface for a mediated bus driver provides the following
-structure to represent a mediated device's driver:
+structure to represent a mediated device's driver::
 
      /*
       * struct mdev_driver [2] - Mediated device's driver
@@ -110,14 +113,14 @@ structure to represent a mediated device's driver:
 A mediated bus driver for mdev should use this structure in the function calls
 to register and unregister itself with the core driver:
 
-* Register:
+* Register::
 
-  extern int  mdev_register_driver(struct mdev_driver *drv,
+    extern int  mdev_register_driver(struct mdev_driver *drv,
                                   struct module *owner);
 
-* Unregister:
+* Unregister::
 
-  extern void mdev_unregister_driver(struct mdev_driver *drv);
+    extern void mdev_unregister_driver(struct mdev_driver *drv);
 
 The mediated bus driver is responsible for adding mediated devices to the VFIO
 group when devices are bound to the driver and removing mediated devices from
@@ -152,15 +155,15 @@ The callbacks in the mdev_parent_ops structure are as follows:
 * mmap: mmap emulation callback
 
 A driver should use the mdev_parent_ops structure in the function call to
-register itself with the mdev core driver:
+register itself with the mdev core driver::
 
-extern int  mdev_register_device(struct device *dev,
-                                 const struct mdev_parent_ops *ops);
+       extern int  mdev_register_device(struct device *dev,
+                                        const struct mdev_parent_ops *ops);
 
 However, the mdev_parent_ops structure is not required in the function call
-that a driver should use to unregister itself with the mdev core driver:
+that a driver should use to unregister itself with the mdev core driver::
 
-extern void mdev_unregister_device(struct device *dev);
+       extern void mdev_unregister_device(struct device *dev);
 
 
 Mediated Device Management Interface Through sysfs
@@ -183,30 +186,32 @@ with the mdev core driver.
 Directories and files under the sysfs for Each Physical Device
 --------------------------------------------------------------
 
-|- [parent physical device]
-|--- Vendor-specific-attributes [optional]
-|--- [mdev_supported_types]
-|     |--- [<type-id>]
-|     |   |--- create
-|     |   |--- name
-|     |   |--- available_instances
-|     |   |--- device_api
-|     |   |--- description
-|     |   |--- [devices]
-|     |--- [<type-id>]
-|     |   |--- create
-|     |   |--- name
-|     |   |--- available_instances
-|     |   |--- device_api
-|     |   |--- description
-|     |   |--- [devices]
-|     |--- [<type-id>]
-|          |--- create
-|          |--- name
-|          |--- available_instances
-|          |--- device_api
-|          |--- description
-|          |--- [devices]
+::
+
+  |- [parent physical device]
+  |--- Vendor-specific-attributes [optional]
+  |--- [mdev_supported_types]
+  |     |--- [<type-id>]
+  |     |   |--- create
+  |     |   |--- name
+  |     |   |--- available_instances
+  |     |   |--- device_api
+  |     |   |--- description
+  |     |   |--- [devices]
+  |     |--- [<type-id>]
+  |     |   |--- create
+  |     |   |--- name
+  |     |   |--- available_instances
+  |     |   |--- device_api
+  |     |   |--- description
+  |     |   |--- [devices]
+  |     |--- [<type-id>]
+  |          |--- create
+  |          |--- name
+  |          |--- available_instances
+  |          |--- device_api
+  |          |--- description
+  |          |--- [devices]
 
 * [mdev_supported_types]
 
@@ -219,12 +224,12 @@ Directories and files under the sysfs for Each Physical Device
 
   The [<type-id>] name is created by adding the device driver string as a prefix
   to the string provided by the vendor driver. This format of this name is as
-  follows:
+  follows::
 
        sprintf(buf, "%s-%s", dev_driver_string(parent->dev), group->name);
 
   (or using mdev_parent_dev(mdev) to arrive at the parent device outside
-   of the core mdev code)
+  of the core mdev code)
 
 * device_api
 
@@ -239,7 +244,7 @@ Directories and files under the sysfs for Each Physical Device
 * [device]
 
   This directory contains links to the devices of type <type-id> that have been
-created.
+  created.
 
 * name
 
@@ -253,21 +258,25 @@ created.
 Directories and Files Under the sysfs for Each mdev Device
 ----------------------------------------------------------
 
-|- [parent phy device]
-|--- [$MDEV_UUID]
+::
+
+  |- [parent phy device]
+  |--- [$MDEV_UUID]
          |--- remove
          |--- mdev_type {link to its type}
          |--- vendor-specific-attributes [optional]
 
 * remove (write only)
+
 Writing '1' to the 'remove' file destroys the mdev device. The vendor driver can
 fail the remove() callback if that device is active and the vendor driver
 doesn't support hot unplug.
 
-Example:
+Example::
+
        # echo 1 > /sys/bus/mdev/devices/$mdev_UUID/remove
 
-Mediated device Hot plug:
+Mediated device Hot plug
 ------------------------
 
 Mediated devices can be created and assigned at runtime. The procedure to hot
@@ -277,13 +286,13 @@ Translation APIs for Mediated Devices
 =====================================
 
 The following APIs are provided for translating user pfn to host pfn in a VFIO
-driver:
+driver::
 
-extern int vfio_pin_pages(struct device *dev, unsigned long *user_pfn,
-                          int npage, int prot, unsigned long *phys_pfn);
+       extern int vfio_pin_pages(struct device *dev, unsigned long *user_pfn,
+                                 int npage, int prot, unsigned long *phys_pfn);
 
-extern int vfio_unpin_pages(struct device *dev, unsigned long *user_pfn,
-                            int npage);
+       extern int vfio_unpin_pages(struct device *dev, unsigned long *user_pfn,
+                                   int npage);
 
 These functions call back into the back-end IOMMU module by using the pin_pages
 and unpin_pages callbacks of the struct vfio_iommu_driver_ops[4]. Currently
@@ -304,81 +313,80 @@ card.
 
    This step creates a dummy device, /sys/devices/virtual/mtty/mtty/
 
-   Files in this device directory in sysfs are similar to the following:
-
-   # tree /sys/devices/virtual/mtty/mtty/
-      /sys/devices/virtual/mtty/mtty/
-      |-- mdev_supported_types
-      |   |-- mtty-1
-      |   |   |-- available_instances
-      |   |   |-- create
-      |   |   |-- device_api
-      |   |   |-- devices
-      |   |   `-- name
-      |   `-- mtty-2
-      |       |-- available_instances
-      |       |-- create
-      |       |-- device_api
-      |       |-- devices
-      |       `-- name
-      |-- mtty_dev
-      |   `-- sample_mtty_dev
-      |-- power
-      |   |-- autosuspend_delay_ms
-      |   |-- control
-      |   |-- runtime_active_time
-      |   |-- runtime_status
-      |   `-- runtime_suspended_time
-      |-- subsystem -> ../../../../class/mtty
-      `-- uevent
+   Files in this device directory in sysfs are similar to the following::
+
+     # tree /sys/devices/virtual/mtty/mtty/
+        /sys/devices/virtual/mtty/mtty/
+        |-- mdev_supported_types
+        |   |-- mtty-1
+        |   |   |-- available_instances
+        |   |   |-- create
+        |   |   |-- device_api
+        |   |   |-- devices
+        |   |   `-- name
+        |   `-- mtty-2
+        |       |-- available_instances
+        |       |-- create
+        |       |-- device_api
+        |       |-- devices
+        |       `-- name
+        |-- mtty_dev
+        |   `-- sample_mtty_dev
+        |-- power
+        |   |-- autosuspend_delay_ms
+        |   |-- control
+        |   |-- runtime_active_time
+        |   |-- runtime_status
+        |   `-- runtime_suspended_time
+        |-- subsystem -> ../../../../class/mtty
+        `-- uevent
 
 2. Create a mediated device by using the dummy device that you created in the
-   previous step.
+   previous step::
 
-   # echo "83b8f4f2-509f-382f-3c1e-e6bfe0fa1001" >     \
+     # echo "83b8f4f2-509f-382f-3c1e-e6bfe0fa1001" >   \
               /sys/devices/virtual/mtty/mtty/mdev_supported_types/mtty-2/create
 
-3. Add parameters to qemu-kvm.
+3. Add parameters to qemu-kvm::
 
-   -device vfio-pci,\
-    sysfsdev=/sys/bus/mdev/devices/83b8f4f2-509f-382f-3c1e-e6bfe0fa1001
+     -device vfio-pci,\
+      sysfsdev=/sys/bus/mdev/devices/83b8f4f2-509f-382f-3c1e-e6bfe0fa1001
 
 4. Boot the VM.
 
    In the Linux guest VM, with no hardware on the host, the device appears
-   as  follows:
-
-   # lspci -s 00:05.0 -xxvv
-   00:05.0 Serial controller: Device 4348:3253 (rev 10) (prog-if 02 [16550])
-           Subsystem: Device 4348:3253
-           Physical Slot: 5
-           Control: I/O+ Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr-
-   Stepping- SERR- FastB2B- DisINTx-
-           Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
-   <TAbort- <MAbort- >SERR- <PERR- INTx-
-           Interrupt: pin A routed to IRQ 10
-           Region 0: I/O ports at c150 [size=8]
-           Region 1: I/O ports at c158 [size=8]
-           Kernel driver in use: serial
-   00: 48 43 53 32 01 00 00 02 10 02 00 07 00 00 00 00
-   10: 51 c1 00 00 59 c1 00 00 00 00 00 00 00 00 00 00
-   20: 00 00 00 00 00 00 00 00 00 00 00 00 48 43 53 32
-   30: 00 00 00 00 00 00 00 00 00 00 00 00 0a 01 00 00
-
-   In the Linux guest VM, dmesg output for the device is as follows:
-
-   serial 0000:00:05.0: PCI INT A -> Link[LNKA] -> GSI 10 (level, high) -> IRQ
-10
-   0000:00:05.0: ttyS1 at I/O 0xc150 (irq = 10) is a 16550A
-   0000:00:05.0: ttyS2 at I/O 0xc158 (irq = 10) is a 16550A
-
-
-5. In the Linux guest VM, check the serial ports.
-
-   # setserial -g /dev/ttyS*
-   /dev/ttyS0, UART: 16550A, Port: 0x03f8, IRQ: 4
-   /dev/ttyS1, UART: 16550A, Port: 0xc150, IRQ: 10
-   /dev/ttyS2, UART: 16550A, Port: 0xc158, IRQ: 10
+   as  follows::
+
+     # lspci -s 00:05.0 -xxvv
+     00:05.0 Serial controller: Device 4348:3253 (rev 10) (prog-if 02 [16550])
+             Subsystem: Device 4348:3253
+             Physical Slot: 5
+             Control: I/O+ Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr-
+     Stepping- SERR- FastB2B- DisINTx-
+             Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
+     <TAbort- <MAbort- >SERR- <PERR- INTx-
+             Interrupt: pin A routed to IRQ 10
+             Region 0: I/O ports at c150 [size=8]
+             Region 1: I/O ports at c158 [size=8]
+             Kernel driver in use: serial
+     00: 48 43 53 32 01 00 00 02 10 02 00 07 00 00 00 00
+     10: 51 c1 00 00 59 c1 00 00 00 00 00 00 00 00 00 00
+     20: 00 00 00 00 00 00 00 00 00 00 00 00 48 43 53 32
+     30: 00 00 00 00 00 00 00 00 00 00 00 00 0a 01 00 00
+
+     In the Linux guest VM, dmesg output for the device is as follows:
+
+     serial 0000:00:05.0: PCI INT A -> Link[LNKA] -> GSI 10 (level, high) -> IRQ 10
+     0000:00:05.0: ttyS1 at I/O 0xc150 (irq = 10) is a 16550A
+     0000:00:05.0: ttyS2 at I/O 0xc158 (irq = 10) is a 16550A
+
+
+5. In the Linux guest VM, check the serial ports::
+
+     # setserial -g /dev/ttyS*
+     /dev/ttyS0, UART: 16550A, Port: 0x03f8, IRQ: 4
+     /dev/ttyS1, UART: 16550A, Port: 0xc150, IRQ: 10
+     /dev/ttyS2, UART: 16550A, Port: 0xc158, IRQ: 10
 
 6. Using minicom or any terminal emulation program, open port /dev/ttyS1 or
    /dev/ttyS2 with hardware flow control disabled.
@@ -388,14 +396,14 @@ card.
 
    Data is loop backed from hosts mtty driver.
 
-8. Destroy the mediated device that you created.
+8. Destroy the mediated device that you created::
 
-   # echo 1 > /sys/bus/mdev/devices/83b8f4f2-509f-382f-3c1e-e6bfe0fa1001/remove
+     # echo 1 > /sys/bus/mdev/devices/83b8f4f2-509f-382f-3c1e-e6bfe0fa1001/remove
 
 References
 ==========
 
-[1] See Documentation/vfio.txt for more information on VFIO.
-[2] struct mdev_driver in include/linux/mdev.h
-[3] struct mdev_parent_ops in include/linux/mdev.h
-[4] struct vfio_iommu_driver_ops in include/linux/vfio.h
+1. See Documentation/vfio.txt for more information on VFIO.
+2. struct mdev_driver in include/linux/mdev.h
+3. struct mdev_parent_ops in include/linux/mdev.h
+4. struct vfio_iommu_driver_ops in include/linux/vfio.h
index 1dd3fdd..ef6a511 100644 (file)
@@ -1,5 +1,7 @@
-VFIO - "Virtual Function I/O"[1]
--------------------------------------------------------------------------------
+==================================
+VFIO - "Virtual Function I/O" [1]_
+==================================
+
 Many modern system now provide DMA and interrupt remapping facilities
 to help ensure I/O devices behave within the boundaries they've been
 allotted.  This includes x86 hardware with AMD-Vi and Intel VT-d,
@@ -7,14 +9,14 @@ POWER systems with Partitionable Endpoints (PEs) and embedded PowerPC
 systems such as Freescale PAMU.  The VFIO driver is an IOMMU/device
 agnostic framework for exposing direct device access to userspace, in
 a secure, IOMMU protected environment.  In other words, this allows
-safe[2], non-privileged, userspace drivers.
+safe [2]_, non-privileged, userspace drivers.
 
 Why do we want that?  Virtual machines often make use of direct device
 access ("device assignment") when configured for the highest possible
 I/O performance.  From a device and host perspective, this simply
 turns the VM into a userspace driver, with the benefits of
 significantly reduced latency, higher bandwidth, and direct use of
-bare-metal device drivers[3].
+bare-metal device drivers [3]_.
 
 Some applications, particularly in the high performance computing
 field, also benefit from low-overhead, direct device access from
@@ -31,7 +33,7 @@ KVM PCI specific device assignment code as well as provide a more
 secure, more featureful userspace driver environment than UIO.
 
 Groups, Devices, and IOMMUs
--------------------------------------------------------------------------------
+---------------------------
 
 Devices are the main target of any I/O driver.  Devices typically
 create a programming interface made up of I/O access, interrupts,
@@ -114,40 +116,40 @@ well as mechanisms for describing and registering interrupt
 notifications.
 
 VFIO Usage Example
--------------------------------------------------------------------------------
+------------------
 
-Assume user wants to access PCI device 0000:06:0d.0
+Assume user wants to access PCI device 0000:06:0d.0::
 
-$ readlink /sys/bus/pci/devices/0000:06:0d.0/iommu_group
-../../../../kernel/iommu_groups/26
+       $ readlink /sys/bus/pci/devices/0000:06:0d.0/iommu_group
+       ../../../../kernel/iommu_groups/26
 
 This device is therefore in IOMMU group 26.  This device is on the
 pci bus, therefore the user will make use of vfio-pci to manage the
-group:
+group::
 
-# modprobe vfio-pci
+       # modprobe vfio-pci
 
 Binding this device to the vfio-pci driver creates the VFIO group
-character devices for this group:
+character devices for this group::
 
-$ lspci -n -s 0000:06:0d.0
-06:0d.0 0401: 1102:0002 (rev 08)
-# echo 0000:06:0d.0 > /sys/bus/pci/devices/0000:06:0d.0/driver/unbind
-# echo 1102 0002 > /sys/bus/pci/drivers/vfio-pci/new_id
+       $ lspci -n -s 0000:06:0d.0
+       06:0d.0 0401: 1102:0002 (rev 08)
+       # echo 0000:06:0d.0 > /sys/bus/pci/devices/0000:06:0d.0/driver/unbind
+       # echo 1102 0002 > /sys/bus/pci/drivers/vfio-pci/new_id
 
 Now we need to look at what other devices are in the group to free
-it for use by VFIO:
-
-$ ls -l /sys/bus/pci/devices/0000:06:0d.0/iommu_group/devices
-total 0
-lrwxrwxrwx. 1 root root 0 Apr 23 16:13 0000:00:1e.0 ->
-       ../../../../devices/pci0000:00/0000:00:1e.0
-lrwxrwxrwx. 1 root root 0 Apr 23 16:13 0000:06:0d.0 ->
-       ../../../../devices/pci0000:00/0000:00:1e.0/0000:06:0d.0
-lrwxrwxrwx. 1 root root 0 Apr 23 16:13 0000:06:0d.1 ->
-       ../../../../devices/pci0000:00/0000:00:1e.0/0000:06:0d.1
-
-This device is behind a PCIe-to-PCI bridge[4], therefore we also
+it for use by VFIO::
+
+       $ ls -l /sys/bus/pci/devices/0000:06:0d.0/iommu_group/devices
+       total 0
+       lrwxrwxrwx. 1 root root 0 Apr 23 16:13 0000:00:1e.0 ->
+               ../../../../devices/pci0000:00/0000:00:1e.0
+       lrwxrwxrwx. 1 root root 0 Apr 23 16:13 0000:06:0d.0 ->
+               ../../../../devices/pci0000:00/0000:00:1e.0/0000:06:0d.0
+       lrwxrwxrwx. 1 root root 0 Apr 23 16:13 0000:06:0d.1 ->
+               ../../../../devices/pci0000:00/0000:00:1e.0/0000:06:0d.1
+
+This device is behind a PCIe-to-PCI bridge [4]_, therefore we also
 need to add device 0000:06:0d.1 to the group following the same
 procedure as above.  Device 0000:00:1e.0 is a bridge that does
 not currently have a host driver, therefore it's not required to
@@ -157,12 +159,12 @@ support PCI bridges).
 The final step is to provide the user with access to the group if
 unprivileged operation is desired (note that /dev/vfio/vfio provides
 no capabilities on its own and is therefore expected to be set to
-mode 0666 by the system).
+mode 0666 by the system)::
 
-# chown user:user /dev/vfio/26
+       # chown user:user /dev/vfio/26
 
 The user now has full access to all the devices and the iommu for this
-group and can access them as follows:
+group and can access them as follows::
 
        int container, group, device, i;
        struct vfio_group_status group_status =
@@ -248,31 +250,31 @@ VFIO bus driver API
 VFIO bus drivers, such as vfio-pci make use of only a few interfaces
 into VFIO core.  When devices are bound and unbound to the driver,
 the driver should call vfio_add_group_dev() and vfio_del_group_dev()
-respectively:
+respectively::
 
-extern int vfio_add_group_dev(struct iommu_group *iommu_group,
-                              struct device *dev,
-                              const struct vfio_device_ops *ops,
-                              void *device_data);
+       extern int vfio_add_group_dev(struct iommu_group *iommu_group,
+                                     struct device *dev,
+                                     const struct vfio_device_ops *ops,
+                                     void *device_data);
 
-extern void *vfio_del_group_dev(struct device *dev);
+       extern void *vfio_del_group_dev(struct device *dev);
 
 vfio_add_group_dev() indicates to the core to begin tracking the
 specified iommu_group and register the specified dev as owned by
 a VFIO bus driver.  The driver provides an ops structure for callbacks
-similar to a file operations structure:
-
-struct vfio_device_ops {
-       int     (*open)(void *device_data);
-       void    (*release)(void *device_data);
-       ssize_t (*read)(void *device_data, char __user *buf,
-                       size_t count, loff_t *ppos);
-       ssize_t (*write)(void *device_data, const char __user *buf,
-                        size_t size, loff_t *ppos);
-       long    (*ioctl)(void *device_data, unsigned int cmd,
-                        unsigned long arg);
-       int     (*mmap)(void *device_data, struct vm_area_struct *vma);
-};
+similar to a file operations structure::
+
+       struct vfio_device_ops {
+               int     (*open)(void *device_data);
+               void    (*release)(void *device_data);
+               ssize_t (*read)(void *device_data, char __user *buf,
+                               size_t count, loff_t *ppos);
+               ssize_t (*write)(void *device_data, const char __user *buf,
+                                size_t size, loff_t *ppos);
+               long    (*ioctl)(void *device_data, unsigned int cmd,
+                                unsigned long arg);
+               int     (*mmap)(void *device_data, struct vm_area_struct *vma);
+       };
 
 Each function is passed the device_data that was originally registered
 in the vfio_add_group_dev() call above.  This allows the bus driver
@@ -285,50 +287,55 @@ own VFIO_DEVICE_GET_REGION_INFO ioctl.
 
 
 PPC64 sPAPR implementation note
--------------------------------------------------------------------------------
+-------------------------------
 
 This implementation has some specifics:
 
 1) On older systems (POWER7 with P5IOC2/IODA1) only one IOMMU group per
-container is supported as an IOMMU table is allocated at the boot time,
-one table per a IOMMU group which is a Partitionable Endpoint (PE)
-(PE is often a PCI domain but not always).
-Newer systems (POWER8 with IODA2) have improved hardware design which allows
-to remove this limitation and have multiple IOMMU groups per a VFIO container.
+   container is supported as an IOMMU table is allocated at the boot time,
+   one table per a IOMMU group which is a Partitionable Endpoint (PE)
+   (PE is often a PCI domain but not always).
+
+   Newer systems (POWER8 with IODA2) have improved hardware design which allows
+   to remove this limitation and have multiple IOMMU groups per a VFIO
+   container.
 
 2) The hardware supports so called DMA windows - the PCI address range
-within which DMA transfer is allowed, any attempt to access address space
-out of the window leads to the whole PE isolation.
+   within which DMA transfer is allowed, any attempt to access address space
+   out of the window leads to the whole PE isolation.
 
 3) PPC64 guests are paravirtualized but not fully emulated. There is an API
-to map/unmap pages for DMA, and it normally maps 1..32 pages per call and
-currently there is no way to reduce the number of calls. In order to make things
-faster, the map/unmap handling has been implemented in real mode which provides
-an excellent performance which has limitations such as inability to do
-locked pages accounting in real time.
+   to map/unmap pages for DMA, and it normally maps 1..32 pages per call and
+   currently there is no way to reduce the number of calls. In order to make
+   things faster, the map/unmap handling has been implemented in real mode
+   which provides an excellent performance which has limitations such as
+   inability to do locked pages accounting in real time.
 
 4) According to sPAPR specification, A Partitionable Endpoint (PE) is an I/O
-subtree that can be treated as a unit for the purposes of partitioning and
-error recovery. A PE may be a single or multi-function IOA (IO Adapter), a
-function of a multi-function IOA, or multiple IOAs (possibly including switch
-and bridge structures above the multiple IOAs). PPC64 guests detect PCI errors
-and recover from them via EEH RTAS services, which works on the basis of
-additional ioctl commands.
+   subtree that can be treated as a unit for the purposes of partitioning and
+   error recovery. A PE may be a single or multi-function IOA (IO Adapter), a
+   function of a multi-function IOA, or multiple IOAs (possibly including
+   switch and bridge structures above the multiple IOAs). PPC64 guests detect
+   PCI errors and recover from them via EEH RTAS services, which works on the
+   basis of additional ioctl commands.
 
-So 4 additional ioctls have been added:
+   So 4 additional ioctls have been added:
 
-       VFIO_IOMMU_SPAPR_TCE_GET_INFO - returns the size and the start
-               of the DMA window on the PCI bus.
+       VFIO_IOMMU_SPAPR_TCE_GET_INFO
+               returns the size and the start of the DMA window on the PCI bus.
 
-       VFIO_IOMMU_ENABLE - enables the container. The locked pages accounting
+       VFIO_IOMMU_ENABLE
+               enables the container. The locked pages accounting
                is done at this point. This lets user first to know what
                the DMA window is and adjust rlimit before doing any real job.
 
-       VFIO_IOMMU_DISABLE - disables the container.
+       VFIO_IOMMU_DISABLE
+               disables the container.
 
-       VFIO_EEH_PE_OP - provides an API for EEH setup, error detection and recovery.
+       VFIO_EEH_PE_OP
+               provides an API for EEH setup, error detection and recovery.
 
-The code flow from the example above should be slightly changed:
+   The code flow from the example above should be slightly changed::
 
        struct vfio_eeh_pe_op pe_op = { .argsz = sizeof(pe_op), .flags = 0 };
 
@@ -442,73 +449,73 @@ The code flow from the example above should be slightly changed:
        ....
 
 5) There is v2 of SPAPR TCE IOMMU. It deprecates VFIO_IOMMU_ENABLE/
-VFIO_IOMMU_DISABLE and implements 2 new ioctls:
-VFIO_IOMMU_SPAPR_REGISTER_MEMORY and VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY
-(which are unsupported in v1 IOMMU).
+   VFIO_IOMMU_DISABLE and implements 2 new ioctls:
+   VFIO_IOMMU_SPAPR_REGISTER_MEMORY and VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY
+   (which are unsupported in v1 IOMMU).
 
-PPC64 paravirtualized guests generate a lot of map/unmap requests,
-and the handling of those includes pinning/unpinning pages and updating
-mm::locked_vm counter to make sure we do not exceed the rlimit.
-The v2 IOMMU splits accounting and pinning into separate operations:
+   PPC64 paravirtualized guests generate a lot of map/unmap requests,
+   and the handling of those includes pinning/unpinning pages and updating
+   mm::locked_vm counter to make sure we do not exceed the rlimit.
+   The v2 IOMMU splits accounting and pinning into separate operations:
 
-- VFIO_IOMMU_SPAPR_REGISTER_MEMORY/VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY ioctls
-receive a user space address and size of the block to be pinned.
-Bisecting is not supported and VFIO_IOMMU_UNREGISTER_MEMORY is expected to
-be called with the exact address and size used for registering
-the memory block. The userspace is not expected to call these often.
-The ranges are stored in a linked list in a VFIO container.
+   - VFIO_IOMMU_SPAPR_REGISTER_MEMORY/VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY ioctls
+     receive a user space address and size of the block to be pinned.
+     Bisecting is not supported and VFIO_IOMMU_UNREGISTER_MEMORY is expected to
+     be called with the exact address and size used for registering
+     the memory block. The userspace is not expected to call these often.
+     The ranges are stored in a linked list in a VFIO container.
 
-- VFIO_IOMMU_MAP_DMA/VFIO_IOMMU_UNMAP_DMA ioctls only update the actual
-IOMMU table and do not do pinning; instead these check that the userspace
-address is from pre-registered range.
+   - VFIO_IOMMU_MAP_DMA/VFIO_IOMMU_UNMAP_DMA ioctls only update the actual
+     IOMMU table and do not do pinning; instead these check that the userspace
+     address is from pre-registered range.
 
-This separation helps in optimizing DMA for guests.
+   This separation helps in optimizing DMA for guests.
 
 6) sPAPR specification allows guests to have an additional DMA window(s) on
-a PCI bus with a variable page size. Two ioctls have been added to support
-this: VFIO_IOMMU_SPAPR_TCE_CREATE and VFIO_IOMMU_SPAPR_TCE_REMOVE.
-The platform has to support the functionality or error will be returned to
-the userspace. The existing hardware supports up to 2 DMA windows, one is
-2GB long, uses 4K pages and called "default 32bit window"; the other can
-be as big as entire RAM, use different page size, it is optional - guests
-create those in run-time if the guest driver supports 64bit DMA.
-
-VFIO_IOMMU_SPAPR_TCE_CREATE receives a page shift, a DMA window size and
-a number of TCE table levels (if a TCE table is going to be big enough and
-the kernel may not be able to allocate enough of physically contiguous memory).
-It creates a new window in the available slot and returns the bus address where
-the new window starts. Due to hardware limitation, the user space cannot choose
-the location of DMA windows.
-
-VFIO_IOMMU_SPAPR_TCE_REMOVE receives the bus start address of the window
-and removes it.
+   a PCI bus with a variable page size. Two ioctls have been added to support
+   this: VFIO_IOMMU_SPAPR_TCE_CREATE and VFIO_IOMMU_SPAPR_TCE_REMOVE.
+   The platform has to support the functionality or error will be returned to
+   the userspace. The existing hardware supports up to 2 DMA windows, one is
+   2GB long, uses 4K pages and called "default 32bit window"; the other can
+   be as big as entire RAM, use different page size, it is optional - guests
+   create those in run-time if the guest driver supports 64bit DMA.
+
+   VFIO_IOMMU_SPAPR_TCE_CREATE receives a page shift, a DMA window size and
+   a number of TCE table levels (if a TCE table is going to be big enough and
+   the kernel may not be able to allocate enough of physically contiguous
+   memory). It creates a new window in the available slot and returns the bus
+   address where the new window starts. Due to hardware limitation, the user
+   space cannot choose the location of DMA windows.
+
+   VFIO_IOMMU_SPAPR_TCE_REMOVE receives the bus start address of the window
+   and removes it.
 
 -------------------------------------------------------------------------------
 
-[1] VFIO was originally an acronym for "Virtual Function I/O" in its
-initial implementation by Tom Lyon while as Cisco.  We've since
-outgrown the acronym, but it's catchy.
-
-[2] "safe" also depends upon a device being "well behaved".  It's
-possible for multi-function devices to have backdoors between
-functions and even for single function devices to have alternative
-access to things like PCI config space through MMIO registers.  To
-guard against the former we can include additional precautions in the
-IOMMU driver to group multi-function PCI devices together
-(iommu=group_mf).  The latter we can't prevent, but the IOMMU should
-still provide isolation.  For PCI, SR-IOV Virtual Functions are the
-best indicator of "well behaved", as these are designed for
-virtualization usage models.
-
-[3] As always there are trade-offs to virtual machine device
-assignment that are beyond the scope of VFIO.  It's expected that
-future IOMMU technologies will reduce some, but maybe not all, of
-these trade-offs.
-
-[4] In this case the device is below a PCI bridge, so transactions
-from either function of the device are indistinguishable to the iommu:
-
--[0000:00]-+-1e.0-[06]--+-0d.0
-                        \-0d.1
-
-00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev 90)
+.. [1] VFIO was originally an acronym for "Virtual Function I/O" in its
+   initial implementation by Tom Lyon while as Cisco.  We've since
+   outgrown the acronym, but it's catchy.
+
+.. [2] "safe" also depends upon a device being "well behaved".  It's
+   possible for multi-function devices to have backdoors between
+   functions and even for single function devices to have alternative
+   access to things like PCI config space through MMIO registers.  To
+   guard against the former we can include additional precautions in the
+   IOMMU driver to group multi-function PCI devices together
+   (iommu=group_mf).  The latter we can't prevent, but the IOMMU should
+   still provide isolation.  For PCI, SR-IOV Virtual Functions are the
+   best indicator of "well behaved", as these are designed for
+   virtualization usage models.
+
+.. [3] As always there are trade-offs to virtual machine device
+   assignment that are beyond the scope of VFIO.  It's expected that
+   future IOMMU technologies will reduce some, but maybe not all, of
+   these trade-offs.
+
+.. [4] In this case the device is below a PCI bridge, so transactions
+   from either function of the device are indistinguishable to the iommu::
+
+       -[0000:00]-+-1e.0-[06]--+-0d.0
+                               \-0d.1
+
+       00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev 90)
index 3a9831b..e63a35f 100644 (file)
@@ -4329,3 +4329,21 @@ Querying this capability returns a bitmap indicating the possible
 virtual SMT modes that can be set using KVM_CAP_PPC_SMT.  If bit N
 (counting from the right) is set, then a virtual SMT mode of 2^N is
 available.
+
+8.11 KVM_CAP_HYPERV_SYNIC2
+
+Architectures: x86
+
+This capability enables a newer version of Hyper-V Synthetic interrupt
+controller (SynIC).  The only difference with KVM_CAP_HYPERV_SYNIC is that KVM
+doesn't clear SynIC message and event flags pages when they are enabled by
+writing to the respective MSRs.
+
+8.12 KVM_CAP_HYPERV_VP_INDEX
+
+Architectures: x86
+
+This capability indicates that userspace can load HV_X64_MSR_VP_INDEX msr.  Its
+value is used to denote the target vcpu for a SynIC interrupt.  For
+compatibilty, KVM initializes this msr to KVM's internal vcpu index.  When this
+capability is absent, userspace can still query this msr's value.
index 0a9ea51..1ebecc1 100644 (file)
@@ -166,10 +166,11 @@ MSR_KVM_SYSTEM_TIME: 0x12
 MSR_KVM_ASYNC_PF_EN: 0x4b564d02
        data: Bits 63-6 hold 64-byte aligned physical address of a
        64 byte memory area which must be in guest RAM and must be
-       zeroed. Bits 5-2 are reserved and should be zero. Bit 0 is 1
+       zeroed. Bits 5-3 are reserved and should be zero. Bit 0 is 1
        when asynchronous page faults are enabled on the vcpu 0 when
        disabled. Bit 1 is 1 if asynchronous page faults can be injected
-       when vcpu is in cpl == 0.
+       when vcpu is in cpl == 0. Bit 2 is 1 if asynchronous page faults
+       are delivered to L1 as #PF vmexits.
 
        First 4 byte of 64 byte memory location will be written to by
        the hypervisor at the time of asynchronous page fault (APF)
index 1660145..2446ee3 100644 (file)
@@ -1,12 +1,11 @@
+==========================================
+Xillybus driver for generic FPGA interface
+==========================================
 
-               ==========================================
-               Xillybus driver for generic FPGA interface
-               ==========================================
+:Author: Eli Billauer, Xillybus Ltd. (http://xillybus.com)
+:Email:  eli.billauer@gmail.com or as advertised on Xillybus' site.
 
-Author: Eli Billauer, Xillybus Ltd. (http://xillybus.com)
-Email:  eli.billauer@gmail.com or as advertised on Xillybus' site.
-
-Contents:
+.. Contents:
 
  - Introduction
   -- Background
@@ -17,7 +16,7 @@ Contents:
   -- Synchronization
   -- Seekable pipes
 
-- Internals
+ - Internals
   -- Source code organization
   -- Pipe attributes
   -- Host never reads from the FPGA
@@ -29,7 +28,7 @@ Contents:
   -- The "nonempty" message (supporting poll)
 
 
-INTRODUCTION
+Introduction
 ============
 
 Background
@@ -105,7 +104,7 @@ driver is used to work out of the box with any Xillybus IP core.
 The data structure just mentioned should not be confused with PCI's
 configuration space or the Flattened Device Tree.
 
-USAGE
+Usage
 =====
 
 User interface
@@ -117,11 +116,11 @@ names of these files depend on the IP core that is loaded in the FPGA (see
 Probing below). To communicate with the FPGA, open the device file that
 corresponds to the hardware FIFO you want to send data or receive data from,
 and use plain write() or read() calls, just like with a regular pipe. In
-particular, it makes perfect sense to go:
+particular, it makes perfect sense to go::
 
-$ cat mydata > /dev/xillybus_thisfifo
+       $ cat mydata > /dev/xillybus_thisfifo
 
-$ cat /dev/xillybus_thatfifo > hisdata
+       $ cat /dev/xillybus_thatfifo > hisdata
 
 possibly pressing CTRL-C as some stage, even though the xillybus_* pipes have
 the capability to send an EOF (but may not use it).
@@ -178,7 +177,7 @@ the attached memory is done by seeking to the desired address, and calling
 read() or write() as required.
 
 
-INTERNALS
+Internals
 =========
 
 Source code organization
@@ -365,7 +364,7 @@ into that page. It can be shown that all pages requested from the kernel
 (except possibly for the last) are 100% utilized this way.
 
 The "nonempty" message (supporting poll)
----------------------------------------
+----------------------------------------
 
 In order to support the "poll" method (and hence select() ), there is a small
 catch regarding the FPGA to host direction: The FPGA may have filled a DMA
index 2cf3e26..b2220d0 100644 (file)
-
+============================
 XZ data compression in Linux
 ============================
 
 Introduction
+============
 
-    XZ is a general purpose data compression format with high compression
-    ratio and relatively fast decompression. The primary compression
-    algorithm (filter) is LZMA2. Additional filters can be used to improve
-    compression ratio even further. E.g. Branch/Call/Jump (BCJ) filters
-    improve compression ratio of executable data.
+XZ is a general purpose data compression format with high compression
+ratio and relatively fast decompression. The primary compression
+algorithm (filter) is LZMA2. Additional filters can be used to improve
+compression ratio even further. E.g. Branch/Call/Jump (BCJ) filters
+improve compression ratio of executable data.
 
-    The XZ decompressor in Linux is called XZ Embedded. It supports
-    the LZMA2 filter and optionally also BCJ filters. CRC32 is supported
-    for integrity checking. The home page of XZ Embedded is at
-    <http://tukaani.org/xz/embedded.html>, where you can find the
-    latest version and also information about using the code outside
-    the Linux kernel.
+The XZ decompressor in Linux is called XZ Embedded. It supports
+the LZMA2 filter and optionally also BCJ filters. CRC32 is supported
+for integrity checking. The home page of XZ Embedded is at
+<http://tukaani.org/xz/embedded.html>, where you can find the
+latest version and also information about using the code outside
+the Linux kernel.
 
-    For userspace, XZ Utils provide a zlib-like compression library
-    and a gzip-like command line tool. XZ Utils can be downloaded from
-    <http://tukaani.org/xz/>.
+For userspace, XZ Utils provide a zlib-like compression library
+and a gzip-like command line tool. XZ Utils can be downloaded from
+<http://tukaani.org/xz/>.
 
 XZ related components in the kernel
-
-    The xz_dec module provides XZ decompressor with single-call (buffer
-    to buffer) and multi-call (stateful) APIs. The usage of the xz_dec
-    module is documented in include/linux/xz.h.
-
-    The xz_dec_test module is for testing xz_dec. xz_dec_test is not
-    useful unless you are hacking the XZ decompressor. xz_dec_test
-    allocates a char device major dynamically to which one can write
-    .xz files from userspace. The decompressed output is thrown away.
-    Keep an eye on dmesg to see diagnostics printed by xz_dec_test.
-    See the xz_dec_test source code for the details.
-
-    For decompressing the kernel image, initramfs, and initrd, there
-    is a wrapper function in lib/decompress_unxz.c. Its API is the
-    same as in other decompress_*.c files, which is defined in
-    include/linux/decompress/generic.h.
-
-    scripts/xz_wrap.sh is a wrapper for the xz command line tool found
-    from XZ Utils. The wrapper sets compression options to values suitable
-    for compressing the kernel image.
-
-    For kernel makefiles, two commands are provided for use with
-    $(call if_needed). The kernel image should be compressed with
-    $(call if_needed,xzkern) which will use a BCJ filter and a big LZMA2
-    dictionary. It will also append a four-byte trailer containing the
-    uncompressed size of the file, which is needed by the boot code.
-    Other things should be compressed with $(call if_needed,xzmisc)
-    which will use no BCJ filter and 1 MiB LZMA2 dictionary.
+===================================
+
+The xz_dec module provides XZ decompressor with single-call (buffer
+to buffer) and multi-call (stateful) APIs. The usage of the xz_dec
+module is documented in include/linux/xz.h.
+
+The xz_dec_test module is for testing xz_dec. xz_dec_test is not
+useful unless you are hacking the XZ decompressor. xz_dec_test
+allocates a char device major dynamically to which one can write
+.xz files from userspace. The decompressed output is thrown away.
+Keep an eye on dmesg to see diagnostics printed by xz_dec_test.
+See the xz_dec_test source code for the details.
+
+For decompressing the kernel image, initramfs, and initrd, there
+is a wrapper function in lib/decompress_unxz.c. Its API is the
+same as in other decompress_*.c files, which is defined in
+include/linux/decompress/generic.h.
+
+scripts/xz_wrap.sh is a wrapper for the xz command line tool found
+from XZ Utils. The wrapper sets compression options to values suitable
+for compressing the kernel image.
+
+For kernel makefiles, two commands are provided for use with
+$(call if_needed). The kernel image should be compressed with
+$(call if_needed,xzkern) which will use a BCJ filter and a big LZMA2
+dictionary. It will also append a four-byte trailer containing the
+uncompressed size of the file, which is needed by the boot code.
+Other things should be compressed with $(call if_needed,xzmisc)
+which will use no BCJ filter and 1 MiB LZMA2 dictionary.
 
 Notes on compression options
+============================
 
-    Since the XZ Embedded supports only streams with no integrity check or
-    CRC32, make sure that you don't use some other integrity check type
-    when encoding files that are supposed to be decoded by the kernel. With
-    liblzma, you need to use either LZMA_CHECK_NONE or LZMA_CHECK_CRC32
-    when encoding. With the xz command line tool, use --check=none or
-    --check=crc32.
-
-    Using CRC32 is strongly recommended unless there is some other layer
-    which will verify the integrity of the uncompressed data anyway.
-    Double checking the integrity would probably be waste of CPU cycles.
-    Note that the headers will always have a CRC32 which will be validated
-    by the decoder; you can only change the integrity check type (or
-    disable it) for the actual uncompressed data.
-
-    In userspace, LZMA2 is typically used with dictionary sizes of several
-    megabytes. The decoder needs to have the dictionary in RAM, thus big
-    dictionaries cannot be used for files that are intended to be decoded
-    by the kernel. 1 MiB is probably the maximum reasonable dictionary
-    size for in-kernel use (maybe more is OK for initramfs). The presets
-    in XZ Utils may not be optimal when creating files for the kernel,
-    so don't hesitate to use custom settings. Example:
-
-        xz --check=crc32 --lzma2=dict=512KiB inputfile
-
-    An exception to above dictionary size limitation is when the decoder
-    is used in single-call mode. Decompressing the kernel itself is an
-    example of this situation. In single-call mode, the memory usage
-    doesn't depend on the dictionary size, and it is perfectly fine to
-    use a big dictionary: for maximum compression, the dictionary should
-    be at least as big as the uncompressed data itself.
+Since the XZ Embedded supports only streams with no integrity check or
+CRC32, make sure that you don't use some other integrity check type
+when encoding files that are supposed to be decoded by the kernel. With
+liblzma, you need to use either LZMA_CHECK_NONE or LZMA_CHECK_CRC32
+when encoding. With the xz command line tool, use --check=none or
+--check=crc32.
+
+Using CRC32 is strongly recommended unless there is some other layer
+which will verify the integrity of the uncompressed data anyway.
+Double checking the integrity would probably be waste of CPU cycles.
+Note that the headers will always have a CRC32 which will be validated
+by the decoder; you can only change the integrity check type (or
+disable it) for the actual uncompressed data.
+
+In userspace, LZMA2 is typically used with dictionary sizes of several
+megabytes. The decoder needs to have the dictionary in RAM, thus big
+dictionaries cannot be used for files that are intended to be decoded
+by the kernel. 1 MiB is probably the maximum reasonable dictionary
+size for in-kernel use (maybe more is OK for initramfs). The presets
+in XZ Utils may not be optimal when creating files for the kernel,
+so don't hesitate to use custom settings. Example::
+
+       xz --check=crc32 --lzma2=dict=512KiB inputfile
+
+An exception to above dictionary size limitation is when the decoder
+is used in single-call mode. Decompressing the kernel itself is an
+example of this situation. In single-call mode, the memory usage
+doesn't depend on the dictionary size, and it is perfectly fine to
+use a big dictionary: for maximum compression, the dictionary should
+be at least as big as the uncompressed data itself.
 
 Future plans
+============
 
-    Creating a limited XZ encoder may be considered if people think it is
-    useful. LZMA2 is slower to compress than e.g. Deflate or LZO even at
-    the fastest settings, so it isn't clear if LZMA2 encoder is wanted
-    into the kernel.
+Creating a limited XZ encoder may be considered if people think it is
+useful. LZMA2 is slower to compress than e.g. Deflate or LZO even at
+the fastest settings, so it isn't clear if LZMA2 encoder is wanted
+into the kernel.
 
-    Support for limited random-access reading is planned for the
-    decompression code. I don't know if it could have any use in the
-    kernel, but I know that it would be useful in some embedded projects
-    outside the Linux kernel.
+Support for limited random-access reading is planned for the
+decompression code. I don't know if it could have any use in the
+kernel, but I know that it would be useful in some embedded projects
+outside the Linux kernel.
 
 Conformance to the .xz file format specification
+================================================
 
-    There are a couple of corner cases where things have been simplified
-    at expense of detecting errors as early as possible. These should not
-    matter in practice all, since they don't cause security issues. But
-    it is good to know this if testing the code e.g. with the test files
-    from XZ Utils.
+There are a couple of corner cases where things have been simplified
+at expense of detecting errors as early as possible. These should not
+matter in practice all, since they don't cause security issues. But
+it is good to know this if testing the code e.g. with the test files
+from XZ Utils.
 
 Reporting bugs
+==============
 
-    Before reporting a bug, please check that it's not fixed already
-    at upstream. See <http://tukaani.org/xz/embedded.html> to get the
-    latest code.
+Before reporting a bug, please check that it's not fixed already
+at upstream. See <http://tukaani.org/xz/embedded.html> to get the
+latest code.
 
-    Report bugs to <lasse.collin@tukaani.org> or visit #tukaani on
-    Freenode and talk to Larhzu. I don't actively read LKML or other
-    kernel-related mailing lists, so if there's something I should know,
-    you should email to me personally or use IRC.
+Report bugs to <lasse.collin@tukaani.org> or visit #tukaani on
+Freenode and talk to Larhzu. I don't actively read LKML or other
+kernel-related mailing lists, so if there's something I should know,
+you should email to me personally or use IRC.
 
-    Don't bother Igor Pavlov with questions about the XZ implementation
-    in the kernel or about XZ Utils. While these two implementations
-    include essential code that is directly based on Igor Pavlov's code,
-    these implementations aren't maintained nor supported by him.
+Don't bother Igor Pavlov with questions about the XZ implementation
+in the kernel or about XZ Utils. While these two implementations
+include essential code that is directly based on Igor Pavlov's code,
+these implementations aren't maintained nor supported by him.
index d530971..664072b 100644 (file)
@@ -1,12 +1,13 @@
-               Writing Device Drivers for Zorro Devices
-               ----------------------------------------
+========================================
+Writing Device Drivers for Zorro Devices
+========================================
 
-Written by Geert Uytterhoeven <geert@linux-m68k.org>
-Last revised: September 5, 2003
+:Author: Written by Geert Uytterhoeven <geert@linux-m68k.org>
+:Last revised: September 5, 2003
 
 
-1. Introduction
----------------
+Introduction
+------------
 
 The Zorro bus is the bus used in the Amiga family of computers. Thanks to
 AutoConfig(tm), it's 100% Plug-and-Play.
@@ -20,12 +21,12 @@ There are two types of Zorro buses, Zorro II and Zorro III:
     with Zorro II. The Zorro III address space lies outside the first 16 MB.
 
 
-2. Probing for Zorro Devices
-----------------------------
+Probing for Zorro Devices
+-------------------------
 
-Zorro devices are found by calling `zorro_find_device()', which returns a
-pointer to the `next' Zorro device with the specified Zorro ID. A probe loop
-for the board with Zorro ID `ZORRO_PROD_xxx' looks like:
+Zorro devices are found by calling ``zorro_find_device()``, which returns a
+pointer to the ``next`` Zorro device with the specified Zorro ID. A probe loop
+for the board with Zorro ID ``ZORRO_PROD_xxx`` looks like::
 
     struct zorro_dev *z = NULL;
 
@@ -35,8 +36,8 @@ for the board with Zorro ID `ZORRO_PROD_xxx' looks like:
        ...
     }
 
-`ZORRO_WILDCARD' acts as a wildcard and finds any Zorro device. If your driver
-supports different types of boards, you can use a construct like:
+``ZORRO_WILDCARD`` acts as a wildcard and finds any Zorro device. If your driver
+supports different types of boards, you can use a construct like::
 
     struct zorro_dev *z = NULL;
 
@@ -49,24 +50,24 @@ supports different types of boards, you can use a construct like:
     }
 
 
-3. Zorro Resources
-------------------
+Zorro Resources
+---------------
 
 Before you can access a Zorro device's registers, you have to make sure it's
 not yet in use. This is done using the I/O memory space resource management
-functions:
+functions::
 
     request_mem_region()
     release_mem_region()
 
-Shortcuts to claim the whole device's address space are provided as well:
+Shortcuts to claim the whole device's address space are provided as well::
 
     zorro_request_device
     zorro_release_device
 
 
-4. Accessing the Zorro Address Space
-------------------------------------
+Accessing the Zorro Address Space
+---------------------------------
 
 The address regions in the Zorro device resources are Zorro bus address
 regions. Due to the identity bus-physical address mapping on the Zorro bus,
@@ -78,26 +79,26 @@ The treatment of these regions depends on the type of Zorro space:
     explicitly using z_ioremap().
     
     Conversion from bus/physical Zorro II addresses to kernel virtual addresses
-    and vice versa is done using:
+    and vice versa is done using::
 
        virt_addr = ZTWO_VADDR(bus_addr);
        bus_addr = ZTWO_PADDR(virt_addr);
 
   - Zorro III address space must be mapped explicitly using z_ioremap() first
-    before it can be accessed:
+    before it can be accessed::
  
        virt_addr = z_ioremap(bus_addr, size);
        ...
        z_iounmap(virt_addr);
 
 
-5. References
--------------
+References
+----------
 
-linux/include/linux/zorro.h
-linux/include/uapi/linux/zorro.h
-linux/include/uapi/linux/zorro_ids.h
-linux/arch/m68k/include/asm/zorro.h
-linux/drivers/zorro
-/proc/bus/zorro
+#. linux/include/linux/zorro.h
+#. linux/include/uapi/linux/zorro.h
+#. linux/include/uapi/linux/zorro_ids.h
+#. linux/arch/m68k/include/asm/zorro.h
+#. linux/drivers/zorro
+#. /proc/bus/zorro
 
index 1347726..207e453 100644 (file)
@@ -205,7 +205,6 @@ F:  include/net/9p/
 F:     include/uapi/linux/virtio_9p.h
 F:     include/trace/events/9p.h
 
-
 A8293 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
@@ -492,13 +491,6 @@ S: Maintained
 F:     Documentation/hwmon/adt7475
 F:     drivers/hwmon/adt7475.c
 
-ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
-M:     Michael Hennerich <michael.hennerich@analog.com>
-W:     http://wiki.analog.com/ADXL345
-W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
-F:     drivers/input/misc/adxl34x.c
-
 ADVANSYS SCSI DRIVER
 M:     Matthew Wilcox <matthew@wil.cx>
 M:     Hannes Reinecke <hare@suse.com>
@@ -507,6 +499,13 @@ S: Maintained
 F:     Documentation/scsi/advansys.txt
 F:     drivers/scsi/advansys.c
 
+ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
+M:     Michael Hennerich <michael.hennerich@analog.com>
+W:     http://wiki.analog.com/ADXL345
+W:     http://ez.analog.com/community/linux-device-drivers
+S:     Supported
+F:     drivers/input/misc/adxl34x.c
+
 AEDSP16 DRIVER
 M:     Riccardo Facchetti <fizban@tin.it>
 S:     Maintained
@@ -808,6 +807,12 @@ W: http://blackfin.uclinux.org/
 S:     Supported
 F:     sound/soc/blackfin/*
 
+ANALOG DEVICES INC DMA DRIVERS
+M:     Lars-Peter Clausen <lars@metafoo.de>
+W:     http://ez.analog.com/community/linux-device-drivers
+S:     Supported
+F:     drivers/dma/dma-axi-dmac.c
+
 ANALOG DEVICES INC IIO DRIVERS
 M:     Lars-Peter Clausen <lars@metafoo.de>
 M:     Michael Hennerich <Michael.Hennerich@analog.com>
@@ -820,12 +825,6 @@ X: drivers/iio/*/adjd*
 F:     drivers/staging/iio/*/ad*
 F:     drivers/staging/iio/trigger/iio-trig-bfin-timer.c
 
-ANALOG DEVICES INC DMA DRIVERS
-M:     Lars-Peter Clausen <lars@metafoo.de>
-W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
-F:     drivers/dma/dma-axi-dmac.c
-
 ANDROID CONFIG FRAGMENTS
 M:     Rob Herring <robh@kernel.org>
 S:     Supported
@@ -872,6 +871,15 @@ F: include/linux/apm_bios.h
 F:     include/uapi/linux/apm_bios.h
 F:     drivers/char/apm-emulation.c
 
+APPARMOR SECURITY MODULE
+M:     John Johansen <john.johansen@canonical.com>
+L:     apparmor@lists.ubuntu.com (subscribers-only, general discussion)
+W:     apparmor.wiki.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
+S:     Supported
+F:     security/apparmor/
+F:     Documentation/admin-guide/LSM/apparmor.rst
+
 APPLE BCM5974 MULTITOUCH DRIVER
 M:     Henrik Rydberg <rydberg@bitmath.org>
 L:     linux-input@vger.kernel.org
@@ -895,6 +903,18 @@ M: Duc Dang <dhdang@apm.com>
 S:     Supported
 F:     arch/arm64/boot/dts/apm/
 
+APPLIED MICRO (APM) X-GENE SOC EDAC
+M:     Loc Ho <lho@apm.com>
+S:     Supported
+F:     drivers/edac/xgene_edac.c
+F:     Documentation/devicetree/bindings/edac/apm-xgene-edac.txt
+
+APPLIED MICRO (APM) X-GENE SOC ETHERNET (V2) DRIVER
+M:     Iyappan Subramanian <isubramanian@apm.com>
+M:     Keyur Chudgar <kchudgar@apm.com>
+S:     Supported
+F:     drivers/net/ethernet/apm/xgene-v2/
+
 APPLIED MICRO (APM) X-GENE SOC ETHERNET DRIVER
 M:     Iyappan Subramanian <isubramanian@apm.com>
 M:     Keyur Chudgar <kchudgar@apm.com>
@@ -905,12 +925,6 @@ F: drivers/net/phy/mdio-xgene.c
 F:     Documentation/devicetree/bindings/net/apm-xgene-enet.txt
 F:     Documentation/devicetree/bindings/net/apm-xgene-mdio.txt
 
-APPLIED MICRO (APM) X-GENE SOC ETHERNET (V2) DRIVER
-M:     Iyappan Subramanian <isubramanian@apm.com>
-M:     Keyur Chudgar <kchudgar@apm.com>
-S:     Supported
-F:     drivers/net/ethernet/apm/xgene-v2/
-
 APPLIED MICRO (APM) X-GENE SOC PMU
 M:     Tai Nguyen <ttnguyen@apm.com>
 S:     Supported
@@ -930,6 +944,12 @@ S: Maintained
 F:     drivers/video/fbdev/arcfb.c
 F:     drivers/video/fbdev/core/fb_defio.c
 
+ARC PGU DRM DRIVER
+M:     Alexey Brodkin <abrodkin@synopsys.com>
+S:     Supported
+F:     drivers/gpu/drm/arc/
+F:     Documentation/devicetree/bindings/display/snps,arcpgu.txt
+
 ARCNET NETWORK LAYER
 M:     Michael Grzeschik <m.grzeschik@pengutronix.de>
 L:     netdev@vger.kernel.org
@@ -937,12 +957,6 @@ S: Maintained
 F:     drivers/net/arcnet/
 F:     include/uapi/linux/if_arcnet.h
 
-ARC PGU DRM DRIVER
-M:     Alexey Brodkin <abrodkin@synopsys.com>
-S:     Supported
-F:     drivers/gpu/drm/arc/
-F:     Documentation/devicetree/bindings/display/snps,arcpgu.txt
-
 ARM ARCHITECTED TIMER DRIVER
 M:     Mark Rutland <mark.rutland@arm.com>
 M:     Marc Zyngier <marc.zyngier@arm.com>
@@ -995,18 +1009,17 @@ S:       Maintained
 T:     git git://git.armlinux.org.uk/~rmk/linux-arm.git
 F:     arch/arm/
 
-ARM SUB-ARCHITECTURES
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     arch/arm/mach-*/
-F:     arch/arm/plat-*/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
-
 ARM PRIMECELL AACI PL041 DRIVER
 M:     Russell King <linux@armlinux.org.uk>
 S:     Maintained
 F:     sound/arm/aaci.*
 
+ARM PRIMECELL BUS SUPPORT
+M:     Russell King <linux@armlinux.org.uk>
+S:     Maintained
+F:     drivers/amba/
+F:     include/linux/amba/bus.h
+
 ARM PRIMECELL CLCD PL110 DRIVER
 M:     Russell King <linux@armlinux.org.uk>
 S:     Maintained
@@ -1030,11 +1043,22 @@ S:      Maintained
 F:     drivers/tty/serial/amba-pl01*.c
 F:     include/linux/amba/serial.h
 
-ARM PRIMECELL BUS SUPPORT
-M:     Russell King <linux@armlinux.org.uk>
+ARM SMMU DRIVERS
+M:     Will Deacon <will.deacon@arm.com>
+R:     Robin Murphy <robin.murphy@arm.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     drivers/amba/
-F:     include/linux/amba/bus.h
+F:     drivers/iommu/arm-smmu.c
+F:     drivers/iommu/arm-smmu-v3.c
+F:     drivers/iommu/io-pgtable-arm.c
+F:     drivers/iommu/io-pgtable-arm-v7s.c
+
+ARM SUB-ARCHITECTURES
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/mach-*/
+F:     arch/arm/plat-*/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
 
 ARM/ACTIONS SEMI ARCHITECTURE
 M:     Andreas Färber <afaerber@suse.de>
@@ -1067,6 +1091,11 @@ M:       Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
+ARM/Allwinner SoC Clock Support
+M:     Emilio López <emilio@elopez.com.ar>
+S:     Maintained
+F:     drivers/clk/sunxi/
+
 ARM/Allwinner sunXi SoC support
 M:     Maxime Ripard <maxime.ripard@free-electrons.com>
 M:     Chen-Yu Tsai <wens@csie.org>
@@ -1081,10 +1110,15 @@ F:      drivers/pinctrl/sunxi/
 F:     drivers/soc/sunxi/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git
 
-ARM/Allwinner SoC Clock Support
-M:     Emilio López <emilio@elopez.com.ar>
+ARM/Amlogic Meson SoC CLOCK FRAMEWORK
+M:     Neil Armstrong <narmstrong@baylibre.com>
+M:     Jerome Brunet <jbrunet@baylibre.com>
+L:     linux-amlogic@lists.infradead.org
 S:     Maintained
-F:     drivers/clk/sunxi/
+F:     drivers/clk/meson/
+F:     include/dt-bindings/clock/meson*
+F:     include/dt-bindings/clock/gxbb*
+F:     Documentation/devicetree/bindings/clock/amlogic*
 
 ARM/Amlogic Meson SoC support
 M:     Carlo Caione <carlo@caione.org>
@@ -1096,20 +1130,10 @@ S:      Maintained
 F:     arch/arm/mach-meson/
 F:     arch/arm/boot/dts/meson*
 F:     arch/arm64/boot/dts/amlogic/
-F:     drivers/pinctrl/meson/
+F:     drivers/pinctrl/meson/
 F:     drivers/mmc/host/meson*
 N:     meson
 
-ARM/Amlogic Meson SoC CLOCK FRAMEWORK
-M:     Neil Armstrong <narmstrong@baylibre.com>
-M:     Jerome Brunet <jbrunet@baylibre.com>
-L:     linux-amlogic@lists.infradead.org
-S:     Maintained
-F:     drivers/clk/meson/
-F:     include/dt-bindings/clock/meson*
-F:     include/dt-bindings/clock/gxbb*
-F:     Documentation/devicetree/bindings/clock/amlogic*
-
 ARM/Annapurna Labs ALPINE ARCHITECTURE
 M:     Tsahee Zidenberg <tsahee@annapurnalabs.com>
 M:     Antoine Tenart <antoine.tenart@free-electrons.com>
@@ -1132,13 +1156,6 @@ F:       drivers/clk/axis
 F:     drivers/pinctrl/pinctrl-artpec*
 F:     Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt
 
-ARM/ASPEED MACHINE SUPPORT
-M:     Joel Stanley <joel@jms.id.au>
-S:     Maintained
-F:     arch/arm/mach-aspeed/
-F:     arch/arm/boot/dts/aspeed-*
-F:     drivers/*/*aspeed*
-
 ARM/ASPEED I2C DRIVER
 M:     Brendan Higgins <brendanhiggins@google.com>
 R:     Benjamin Herrenschmidt <benh@kernel.crashing.org>
@@ -1151,6 +1168,18 @@ F:       drivers/i2c/busses/i2c-aspeed.c
 F:     Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2400-i2c-ic.txt
 F:     Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
 
+ARM/ASPEED MACHINE SUPPORT
+M:     Joel Stanley <joel@jms.id.au>
+S:     Maintained
+F:     arch/arm/mach-aspeed/
+F:     arch/arm/boot/dts/aspeed-*
+F:     drivers/*/*aspeed*
+
+ARM/ATMEL AT91 Clock Support
+M:     Boris Brezillon <boris.brezillon@free-electrons.com>
+S:     Maintained
+F:     drivers/clk/at91
+
 ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT
 M:     Nicolas Ferre <nicolas.ferre@microchip.com>
 M:     Alexandre Belloni <alexandre.belloni@free-electrons.com>
@@ -1167,11 +1196,6 @@ F:       arch/arm/boot/dts/sama*.dtsi
 F:     arch/arm/include/debug/at91.S
 F:     drivers/memory/atmel*
 
-ARM/ATMEL AT91 Clock Support
-M:     Boris Brezillon <boris.brezillon@free-electrons.com>
-S:     Maintained
-F:     drivers/clk/at91
-
 ARM/CALXEDA HIGHBANK ARCHITECTURE
 M:     Rob Herring <robh@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1198,6 +1222,11 @@ L:       linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Odd Fixes
 N:     clps711x
 
+ARM/CIRRUS LOGIC EDB9315A MACHINE SUPPORT
+M:     Lennert Buytenhek <kernel@wantstofly.org>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+
 ARM/CIRRUS LOGIC EP93XX ARM ARCHITECTURE
 M:     Hartley Sweeten <hsweeten@visionengravers.com>
 M:     Alexander Sverdlin <alexander.sverdlin@gmail.com>
@@ -1206,11 +1235,6 @@ S:       Maintained
 F:     arch/arm/mach-ep93xx/
 F:     arch/arm/mach-ep93xx/include/mach/
 
-ARM/CIRRUS LOGIC EDB9315A MACHINE SUPPORT
-M:     Lennert Buytenhek <kernel@wantstofly.org>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-
 ARM/CLKDEV SUPPORT
 M:     Russell King <linux@armlinux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1224,6 +1248,13 @@ M:       Mike Rapoport <mike@compulab.co.il>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
+ARM/CONEXANT DIGICOLOR MACHINE SUPPORT
+M:     Baruch Siach <baruch@tkos.co.il>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/boot/dts/cx92755*
+N:     digicolor
+
 ARM/CONTEC MICRO9 MACHINE SUPPORT
 M:     Hubert Feurstein <hubert.feurstein@contec.at>
 S:     Maintained
@@ -1255,7 +1286,7 @@ L:        linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://github.com/ulli-kroll/linux.git
 S:     Maintained
 F:     arch/arm/mach-gemini/
-F:     drivers/rtc/rtc-gemini.c
+F:     drivers/rtc/rtc-ftrtc010.c
 
 ARM/CSR SIRFPRIMA2 MACHINE SUPPORT
 M:     Barry Song <baohua@kernel.org>
@@ -1269,13 +1300,6 @@ F:       drivers/clocksource/timer-prima2.c
 F:     drivers/clocksource/timer-atlas7.c
 N:     [^a-z]sirf
 
-ARM/CONEXANT DIGICOLOR MACHINE SUPPORT
-M:     Baruch Siach <baruch@tkos.co.il>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     arch/arm/boot/dts/cx92755*
-N:     digicolor
-
 ARM/EBSA110 MACHINE SUPPORT
 M:     Russell King <linux@armlinux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1389,6 +1413,11 @@ L:       linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-pxa/colibri-pxa270-income.c
 
+ARM/INTEL IOP13XX ARM ARCHITECTURE
+M:     Lennert Buytenhek <kernel@wantstofly.org>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+
 ARM/INTEL IOP32X ARM ARCHITECTURE
 M:     Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1398,11 +1427,6 @@ ARM/INTEL IOP33X ARM ARCHITECTURE
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Orphan
 
-ARM/INTEL IOP13XX ARM ARCHITECTURE
-M:     Lennert Buytenhek <kernel@wantstofly.org>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-
 ARM/INTEL IQ81342EX MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1437,39 +1461,6 @@ M:       Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
-ARM/TEXAS INSTRUMENT KEYSTONE ARCHITECTURE
-M:     Santosh Shilimkar <ssantosh@kernel.org>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     arch/arm/mach-keystone/
-F:     arch/arm/boot/dts/keystone-*
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
-
-ARM/TEXAS INSTRUMENT KEYSTONE CLOCK FRAMEWORK
-M:     Santosh Shilimkar <ssantosh@kernel.org>
-L:     linux-kernel@vger.kernel.org
-S:     Maintained
-F:     drivers/clk/keystone/
-
-ARM/TEXAS INSTRUMENT KEYSTONE ClOCKSOURCE
-M:     Santosh Shilimkar <ssantosh@kernel.org>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-L:     linux-kernel@vger.kernel.org
-S:     Maintained
-F:     drivers/clocksource/timer-keystone.c
-
-ARM/TEXAS INSTRUMENT KEYSTONE RESET DRIVER
-M:     Santosh Shilimkar <ssantosh@kernel.org>
-L:     linux-kernel@vger.kernel.org
-S:     Maintained
-F:     drivers/power/reset/keystone-reset.c
-
-ARM/TEXAS INSTRUMENT AEMIF/EMIF DRIVERS
-M:     Santosh Shilimkar <ssantosh@kernel.org>
-L:     linux-kernel@vger.kernel.org
-S:     Maintained
-F:     drivers/memory/*emif*
-
 ARM/LG1K ARCHITECTURE
 M:     Chanho Min <chanho.min@lge.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1512,24 +1503,6 @@ ARM/MAGICIAN MACHINE SUPPORT
 M:     Philipp Zabel <philipp.zabel@gmail.com>
 S:     Maintained
 
-ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K SOC support
-M:     Jason Cooper <jason@lakedaemon.net>
-M:     Andrew Lunn <andrew@lunn.ch>
-M:     Gregory Clement <gregory.clement@free-electrons.com>
-M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     arch/arm/boot/dts/armada*
-F:     arch/arm/boot/dts/kirkwood*
-F:     arch/arm/configs/mvebu_*_defconfig
-F:     arch/arm/mach-mvebu/
-F:     arch/arm64/boot/dts/marvell/armada*
-F:     drivers/cpufreq/mvebu-cpufreq.c
-F:     drivers/irqchip/irq-armada-370-xp.c
-F:     drivers/irqchip/irq-mvebu-*
-F:     drivers/pinctrl/mvebu/
-F:     drivers/rtc/rtc-armada38x.c
-
 ARM/Marvell Berlin SoC support
 M:     Jisheng Zhang <jszhang@marvell.com>
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
@@ -1539,7 +1512,6 @@ F:        arch/arm/mach-berlin/
 F:     arch/arm/boot/dts/berlin*
 F:     arch/arm64/boot/dts/marvell/berlin*
 
-
 ARM/Marvell Dove/MV78xx0/Orion SOC support
 M:     Jason Cooper <jason@lakedaemon.net>
 M:     Andrew Lunn <andrew@lunn.ch>
@@ -1555,27 +1527,26 @@ F:      arch/arm/plat-orion/
 F:     arch/arm/boot/dts/dove*
 F:     arch/arm/boot/dts/orion5x*
 
-
-ARM/Orion SoC/Technologic Systems TS-78xx platform support
-M:     Alexander Clouter <alex@digriz.org.uk>
+ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K SOC support
+M:     Jason Cooper <jason@lakedaemon.net>
+M:     Andrew Lunn <andrew@lunn.ch>
+M:     Gregory Clement <gregory.clement@free-electrons.com>
+M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.digriz.org.uk/ts78xx/kernel
 S:     Maintained
-F:     arch/arm/mach-orion5x/ts78xx-*
+F:     arch/arm/boot/dts/armada*
+F:     arch/arm/boot/dts/kirkwood*
+F:     arch/arm/configs/mvebu_*_defconfig
+F:     arch/arm/mach-mvebu/
+F:     arch/arm64/boot/dts/marvell/armada*
+F:     drivers/cpufreq/mvebu-cpufreq.c
+F:     drivers/irqchip/irq-armada-370-xp.c
+F:     drivers/irqchip/irq-mvebu-*
+F:     drivers/pinctrl/mvebu/
+F:     drivers/rtc/rtc-armada38x.c
 
-ARM/OXNAS platform support
-M:     Neil Armstrong <narmstrong@baylibre.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-L:     linux-oxnas@lists.tuxfamily.org (moderated for non-subscribers)
-S:     Maintained
-F:     arch/arm/mach-oxnas/
-F:     arch/arm/boot/dts/ox8*.dtsi
-F:     arch/arm/boot/dts/wd-mbwe.dts
-F:     arch/arm/boot/dts/cloudengines-pogoplug-series-3.dts
-N:     oxnas
-
-ARM/Mediatek RTC DRIVER
-M:     Eddie Huang <eddie.huang@mediatek.com>
+ARM/Mediatek RTC DRIVER
+M:     Eddie Huang <eddie.huang@mediatek.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-mediatek@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
@@ -1627,16 +1598,53 @@ F:      drivers/pinctrl/nomadik/
 F:     drivers/i2c/busses/i2c-nomadik.c
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
 
+ARM/NUVOTON W90X900 ARM ARCHITECTURE
+M:     Wan ZongShun <mcuos.com@gmail.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+W:     http://www.mcuos.com
+S:     Maintained
+F:     arch/arm/mach-w90x900/
+F:     drivers/input/keyboard/w90p910_keypad.c
+F:     drivers/input/touchscreen/w90p910_ts.c
+F:     drivers/watchdog/nuc900_wdt.c
+F:     drivers/net/ethernet/nuvoton/w90p910_ether.c
+F:     drivers/mtd/nand/nuc900_nand.c
+F:     drivers/rtc/rtc-nuc900.c
+F:     drivers/spi/spi-nuc900.c
+F:     drivers/usb/host/ehci-w90x900.c
+F:     drivers/video/fbdev/nuc900fb.c
+
 ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
 M:     Nelson Castillo <arhuaco@freaks-unidos.net>
 L:     openmoko-kernel@lists.openmoko.org (subscribers-only)
 W:     http://wiki.openmoko.org/wiki/Neo_FreeRunner
 S:     Supported
 
-ARM/TOSA MACHINE SUPPORT
-M:     Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
-M:     Dirk Opfer <dirk@opfer-online.de>
+ARM/Orion SoC/Technologic Systems TS-78xx platform support
+M:     Alexander Clouter <alex@digriz.org.uk>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+W:     http://www.digriz.org.uk/ts78xx/kernel
+S:     Maintained
+F:     arch/arm/mach-orion5x/ts78xx-*
+
+ARM/OXNAS platform support
+M:     Neil Armstrong <narmstrong@baylibre.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L:     linux-oxnas@lists.tuxfamily.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/mach-oxnas/
+F:     arch/arm/boot/dts/ox8*.dtsi
+F:     arch/arm/boot/dts/wd-mbwe.dts
+F:     arch/arm/boot/dts/cloudengines-pogoplug-series-3.dts
+N:     oxnas
+
+ARM/PALM TREO SUPPORT
+M:     Tomas Cech <sleep_walker@suse.com>
+L:     linux-arm-kernel@lists.infradead.org
+W:     http://hackndev.com
 S:     Maintained
+F:     arch/arm/mach-pxa/include/mach/palmtreo.h
+F:     arch/arm/mach-pxa/palmtreo.c
 
 ARM/PALMTX,PALMT5,PALMLD,PALMTE2,PALMTC SUPPORT
 M:     Marek Vasut <marek.vasut@gmail.com>
@@ -1654,14 +1662,6 @@ F:       arch/arm/mach-pxa/palmte2.c
 F:     arch/arm/mach-pxa/include/mach/palmtc.h
 F:     arch/arm/mach-pxa/palmtc.c
 
-ARM/PALM TREO SUPPORT
-M:     Tomas Cech <sleep_walker@suse.com>
-L:     linux-arm-kernel@lists.infradead.org
-W:     http://hackndev.com
-S:     Maintained
-F:     arch/arm/mach-pxa/include/mach/palmtreo.h
-F:     arch/arm/mach-pxa/palmtreo.c
-
 ARM/PALMZ72 SUPPORT
 M:     Sergey Lapin <slapin@ossfans.org>
 L:     linux-arm-kernel@lists.infradead.org
@@ -1802,17 +1802,6 @@ L:       linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/platform/s5p-g2d/
 
-ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT
-M:     Kyungmin Park <kyungmin.park@samsung.com>
-M:     Kamil Debski <kamil@wypas.org>
-M:     Jeongtae Park <jtp.park@samsung.com>
-M:     Andrzej Hajda <a.hajda@samsung.com>
-L:     linux-arm-kernel@lists.infradead.org
-L:     linux-media@vger.kernel.org
-S:     Maintained
-F:     arch/arm/plat-samsung/s5p-dev-mfc.c
-F:     drivers/media/platform/s5p-mfc/
-
 ARM/SAMSUNG S5P SERIES HDMI CEC SUBSYSTEM SUPPORT
 M:     Marek Szyprowski <m.szyprowski@samsung.com>
 L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
@@ -1829,6 +1818,17 @@ L:       linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/platform/s5p-jpeg/
 
+ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT
+M:     Kyungmin Park <kyungmin.park@samsung.com>
+M:     Kamil Debski <kamil@wypas.org>
+M:     Jeongtae Park <jtp.park@samsung.com>
+M:     Andrzej Hajda <a.hajda@samsung.com>
+L:     linux-arm-kernel@lists.infradead.org
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     arch/arm/plat-samsung/s5p-dev-mfc.c
+F:     drivers/media/platform/s5p-mfc/
+
 ARM/SHMOBILE ARM ARCHITECTURE
 M:     Simon Horman <horms@verge.net.au>
 M:     Magnus Damm <magnus.damm@gmail.com>
@@ -1922,26 +1922,48 @@ M:      "Mark F. Brown" <mark.brown314@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
+ARM/TEXAS INSTRUMENT AEMIF/EMIF DRIVERS
+M:     Santosh Shilimkar <ssantosh@kernel.org>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+F:     drivers/memory/*emif*
+
+ARM/TEXAS INSTRUMENT KEYSTONE ARCHITECTURE
+M:     Santosh Shilimkar <ssantosh@kernel.org>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/mach-keystone/
+F:     arch/arm/boot/dts/keystone-*
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
+
+ARM/TEXAS INSTRUMENT KEYSTONE CLOCK FRAMEWORK
+M:     Santosh Shilimkar <ssantosh@kernel.org>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+F:     drivers/clk/keystone/
+
+ARM/TEXAS INSTRUMENT KEYSTONE ClOCKSOURCE
+M:     Santosh Shilimkar <ssantosh@kernel.org>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+F:     drivers/clocksource/timer-keystone.c
+
+ARM/TEXAS INSTRUMENT KEYSTONE RESET DRIVER
+M:     Santosh Shilimkar <ssantosh@kernel.org>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+F:     drivers/power/reset/keystone-reset.c
+
 ARM/THECUS N2100 MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
-ARM/NUVOTON W90X900 ARM ARCHITECTURE
-M:     Wan ZongShun <mcuos.com@gmail.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.mcuos.com
+ARM/TOSA MACHINE SUPPORT
+M:     Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+M:     Dirk Opfer <dirk@opfer-online.de>
 S:     Maintained
-F:     arch/arm/mach-w90x900/
-F:     drivers/input/keyboard/w90p910_keypad.c
-F:     drivers/input/touchscreen/w90p910_ts.c
-F:     drivers/watchdog/nuc900_wdt.c
-F:     drivers/net/ethernet/nuvoton/w90p910_ether.c
-F:     drivers/mtd/nand/nuc900_nand.c
-F:     drivers/rtc/rtc-nuc900.c
-F:     drivers/spi/spi-nuc900.c
-F:     drivers/usb/host/ehci-w90x900.c
-F:     drivers/video/fbdev/nuc900fb.c
 
 ARM/U300 MACHINE SUPPORT
 M:     Linus Walleij <linus.walleij@linaro.org>
@@ -2086,16 +2108,6 @@ F:       drivers/i2c/busses/i2c-cadence.c
 F:     drivers/mmc/host/sdhci-of-arasan.c
 F:     drivers/edac/synopsys_edac.c
 
-ARM SMMU DRIVERS
-M:     Will Deacon <will.deacon@arm.com>
-R:     Robin Murphy <robin.murphy@arm.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     drivers/iommu/arm-smmu.c
-F:     drivers/iommu/arm-smmu-v3.c
-F:     drivers/iommu/io-pgtable-arm.c
-F:     drivers/iommu/io-pgtable-arm-v7s.c
-
 ARM64 PORT (AARCH64 ARCHITECTURE)
 M:     Catalin Marinas <catalin.marinas@arm.com>
 M:     Will Deacon <will.deacon@arm.com>
@@ -2207,21 +2219,10 @@ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
 S:     Supported
 F:     drivers/net/wireless/ath/ath6kl/
 
-WILOCITY WIL6210 WIRELESS DRIVER
-M:     Maya Erez <qca_merez@qca.qualcomm.com>
-L:     linux-wireless@vger.kernel.org
-L:     wil6210@qca.qualcomm.com
-S:     Supported
-W:     http://wireless.kernel.org/en/users/Drivers/wil6210
-F:     drivers/net/wireless/ath/wil6210/
-F:     include/uapi/linux/wil6210_uapi.h
-
-CARL9170 LINUX COMMUNITY WIRELESS DRIVER
-M:     Christian Lamparter <chunkeey@googlemail.com>
-L:     linux-wireless@vger.kernel.org
-W:     http://wireless.kernel.org/en/users/Drivers/carl9170
+ATI_REMOTE2 DRIVER
+M:     Ville Syrjala <syrjala@sci.fi>
 S:     Maintained
-F:     drivers/net/wireless/ath/carl9170/
+F:     drivers/input/misc/ati_remote2.c
 
 ATK0110 HWMON DRIVER
 M:     Luca Tettamanti <kronos.it@gmail.com>
@@ -2229,11 +2230,6 @@ L:       linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/asus_atk0110.c
 
-ATI_REMOTE2 DRIVER
-M:     Ville Syrjala <syrjala@sci.fi>
-S:     Maintained
-F:     drivers/input/misc/ati_remote2.c
-
 ATLX ETHERNET DRIVERS
 M:     Jay Cliburn <jcliburn@gmail.com>
 M:     Chris Snook <chris.snook@gmail.com>
@@ -2263,25 +2259,12 @@ M:      Nicolas Ferre <nicolas.ferre@microchip.com>
 S:     Supported
 F:     drivers/power/reset/at91-sama5d2_shdwc.c
 
-ATMEL SAMA5D2 ADC DRIVER
-M:     Ludovic Desroches <ludovic.desroches@microchip.com>
-L:     linux-iio@vger.kernel.org
-S:     Supported
-F:     drivers/iio/adc/at91-sama5d2_adc.c
-
 ATMEL Audio ALSA driver
 M:     Nicolas Ferre <nicolas.ferre@microchip.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
 F:     sound/soc/atmel
 
-ATMEL XDMA DRIVER
-M:     Ludovic Desroches <ludovic.desroches@microchip.com>
-L:     linux-arm-kernel@lists.infradead.org
-L:     dmaengine@vger.kernel.org
-S:     Supported
-F:     drivers/dma/at_xdmac.c
-
 ATMEL I2C DRIVER
 M:     Ludovic Desroches <ludovic.desroches@microchip.com>
 L:     linux-i2c@vger.kernel.org
@@ -2307,6 +2290,14 @@ M:       Nicolas Ferre <nicolas.ferre@microchip.com>
 S:     Supported
 F:     drivers/net/ethernet/cadence/
 
+ATMEL MAXTOUCH DRIVER
+M:     Nick Dyer <nick@shmanahar.org>
+T:     git git://github.com/ndyer/linux.git
+S:     Maintained
+F:     Documentation/devicetree/bindings/input/atmel,maxtouch.txt
+F:     drivers/input/touchscreen/atmel_mxt_ts.c
+F:     include/linux/platform_data/atmel_mxt_ts.h
+
 ATMEL NAND DRIVER
 M:     Wenyou Yang <wenyou.yang@atmel.com>
 M:     Josh Wu <rainyfeeling@outlook.com>
@@ -2314,6 +2305,12 @@ L:       linux-mtd@lists.infradead.org
 S:     Supported
 F:     drivers/mtd/nand/atmel/*
 
+ATMEL SAMA5D2 ADC DRIVER
+M:     Ludovic Desroches <ludovic.desroches@microchip.com>
+L:     linux-iio@vger.kernel.org
+S:     Supported
+F:     drivers/iio/adc/at91-sama5d2_adc.c
+
 ATMEL SDMMC DRIVER
 M:     Ludovic Desroches <ludovic.desroches@microchip.com>
 L:     linux-mmc@vger.kernel.org
@@ -2353,13 +2350,12 @@ W:      http://atmelwlandriver.sourceforge.net/
 S:     Maintained
 F:     drivers/net/wireless/atmel/atmel*
 
-ATMEL MAXTOUCH DRIVER
-M:     Nick Dyer <nick@shmanahar.org>
-T:     git git://github.com/ndyer/linux.git
-S:     Maintained
-F:     Documentation/devicetree/bindings/input/atmel,maxtouch.txt
-F:     drivers/input/touchscreen/atmel_mxt_ts.c
-F:     include/linux/platform_data/atmel_mxt_ts.h
+ATMEL XDMA DRIVER
+M:     Ludovic Desroches <ludovic.desroches@microchip.com>
+L:     linux-arm-kernel@lists.infradead.org
+L:     dmaengine@vger.kernel.org
+S:     Supported
+F:     drivers/dma/at_xdmac.c
 
 ATOMIC INFRASTRUCTURE
 M:     Will Deacon <will.deacon@arm.com>
@@ -2413,13 +2409,6 @@ F:       include/uapi/linux/ax25.h
 F:     include/net/ax25.h
 F:     net/ax25/
 
-AXENTIA ASOC DRIVERS
-M:     Peter Rosin <peda@axentia.se>
-L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-S:     Maintained
-F:     Documentation/devicetree/bindings/sound/axentia,*
-F:     sound/soc/atmel/tse850-pcm5142.c
-
 AXENTIA ARM DEVICES
 M:     Peter Rosin <peda@axentia.se>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -2428,6 +2417,13 @@ F:       Documentation/devicetree/bindings/arm/axentia.txt
 F:     arch/arm/boot/dts/at91-linea.dtsi
 F:     arch/arm/boot/dts/at91-tse850-3.dts
 
+AXENTIA ASOC DRIVERS
+M:     Peter Rosin <peda@axentia.se>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/devicetree/bindings/sound/axentia,*
+F:     sound/soc/atmel/tse850-pcm5142.c
+
 AZ6007 DVB DRIVER
 M:     Mauro Carvalho Chehab <mchehab@s-opensource.com>
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
@@ -2507,27 +2503,27 @@ W:      https://linuxtv.org
 S:     Supported
 F:     drivers/media/platform/sti/bdisp
 
-DELTA ST MEDIA DRIVER
-M:     Hugues Fruchet <hugues.fruchet@st.com>
-L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
-S:     Supported
-F:     drivers/media/platform/sti/delta
+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
 
 BEFS FILE SYSTEM
-M:     Luis de Bethencourt <luisbg@osg.samsung.com>
+M:     Luis de Bethencourt <luisbg@kernel.org>
 M:     Salah Triki <salah.triki@gmail.com>
 S:     Maintained
-T:     git git://github.com/luisbg/linux-befs.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/luisbg/linux-befs.git
 F:     Documentation/filesystems/befs.txt
 F:     fs/befs/
 
-BECKHOFF CX5020 ETHERCAT MASTER DRIVER
-M:     Dariusz Marcinkiewicz <reksio@newterm.pl>
-L:     netdev@vger.kernel.org
+BFQ I/O SCHEDULER
+M:     Paolo Valente <paolo.valente@linaro.org>
+M:     Jens Axboe <axboe@kernel.dk>
+L:     linux-block@vger.kernel.org
 S:     Maintained
-F:     drivers/net/ethernet/ec_bhf.c
+F:     block/bfq-*
+F:     Documentation/block/bfq-iosched.txt
 
 BFS FILE SYSTEM
 M:     "Tigran A. Aivazian" <aivazian.tigran@gmail.com>
@@ -2550,47 +2546,47 @@ W:      http://blackfin.uclinux.org
 S:     Supported
 F:     drivers/net/ethernet/adi/
 
-BLACKFIN RTC DRIVER
+BLACKFIN I2C TWI DRIVER
+M:     Sonic Zhang <sonic.zhang@analog.com>
 L:     adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
-W:     http://blackfin.uclinux.org
+W:     http://blackfin.uclinux.org/
 S:     Supported
-F:     drivers/rtc/rtc-bfin.c
+F:     drivers/i2c/busses/i2c-bfin-twi.c
 
-BLACKFIN SDH DRIVER
-M:     Sonic Zhang <sonic.zhang@analog.com>
+BLACKFIN MEDIA DRIVER
+M:     Scott Jiang <scott.jiang.linux@gmail.com>
 L:     adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
-W:     http://blackfin.uclinux.org
+W:     http://blackfin.uclinux.org/
 S:     Supported
-F:     drivers/mmc/host/bfin_sdh.c
-
-BLACKFIN SERIAL DRIVER
-M:     Sonic Zhang <sonic.zhang@analog.com>
+F:     drivers/media/platform/blackfin/
+F:     drivers/media/i2c/adv7183*
+F:     drivers/media/i2c/vs6624*
+
+BLACKFIN RTC DRIVER
 L:     adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
 W:     http://blackfin.uclinux.org
 S:     Supported
-F:     drivers/tty/serial/bfin_uart.c
+F:     drivers/rtc/rtc-bfin.c
 
-BLACKFIN WATCHDOG DRIVER
+BLACKFIN SDH DRIVER
+M:     Sonic Zhang <sonic.zhang@analog.com>
 L:     adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
 W:     http://blackfin.uclinux.org
 S:     Supported
-F:     drivers/watchdog/bfin_wdt.c
+F:     drivers/mmc/host/bfin_sdh.c
 
-BLACKFIN I2C TWI DRIVER
+BLACKFIN SERIAL DRIVER
 M:     Sonic Zhang <sonic.zhang@analog.com>
 L:     adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
-W:     http://blackfin.uclinux.org/
+W:     http://blackfin.uclinux.org
 S:     Supported
-F:     drivers/i2c/busses/i2c-bfin-twi.c
+F:     drivers/tty/serial/bfin_uart.c
 
-BLACKFIN MEDIA DRIVER
-M:     Scott Jiang <scott.jiang.linux@gmail.com>
+BLACKFIN WATCHDOG DRIVER
 L:     adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
-W:     http://blackfin.uclinux.org/
+W:     http://blackfin.uclinux.org
 S:     Supported
-F:     drivers/media/platform/blackfin/
-F:     drivers/media/i2c/adv7183*
-F:     drivers/media/i2c/vs6624*
+F:     drivers/watchdog/bfin_wdt.c
 
 BLINKM RGB LED DRIVER
 M:     Jan-Simon Moeller <jansimon.moeller@gmx.de>
@@ -2606,14 +2602,6 @@ F:       block/
 F:     kernel/trace/blktrace.c
 F:     lib/sbitmap.c
 
-BFQ I/O SCHEDULER
-M:     Paolo Valente <paolo.valente@linaro.org>
-M:     Jens Axboe <axboe@kernel.dk>
-L:     linux-block@vger.kernel.org
-S:     Maintained
-F:     block/bfq-*
-F:     Documentation/block/bfq-iosched.txt
-
 BLOCK2MTD DRIVER
 M:     Joern Engel <joern@lazybastard.org>
 L:     linux-mtd@lists.infradead.org
@@ -2643,21 +2631,6 @@ S:       Maintained
 F:     net/bluetooth/
 F:     include/net/bluetooth/
 
-DMA MAPPING HELPERS
-M:     Christoph Hellwig <hch@lst.de>
-M:     Marek Szyprowski <m.szyprowski@samsung.com>
-R:     Robin Murphy <robin.murphy@arm.com>
-L:     linux-kernel@vger.kernel.org
-T:     git git://git.infradead.org/users/hch/dma-mapping.git
-W:     http://git.infradead.org/users/hch/dma-mapping.git
-S:     Supported
-F:     lib/dma-debug.c
-F:     lib/dma-noop.c
-F:     lib/dma-virt.c
-F:     drivers/base/dma-mapping.c
-F:     drivers/base/dma-coherent.c
-F:     include/linux/dma-mapping.h
-
 BONDING DRIVER
 M:     Jay Vosburgh <j.vosburgh@gmail.com>
 M:     Veaceslav Falico <vfalico@gmail.com>
@@ -2705,35 +2678,6 @@ S:       Supported
 F:     drivers/net/dsa/b53/*
 F:     include/linux/platform_data/b53.h
 
-BROADCOM GENET ETHERNET DRIVER
-M:     Florian Fainelli <f.fainelli@gmail.com>
-L:     netdev@vger.kernel.org
-S:     Supported
-F:     drivers/net/ethernet/broadcom/genet/
-
-BROADCOM BNX2 GIGABIT ETHERNET DRIVER
-M:     Rasesh Mody <rasesh.mody@cavium.com>
-M:     Harish Patil <harish.patil@cavium.com>
-M:     Dept-GELinuxNICDev@cavium.com
-L:     netdev@vger.kernel.org
-S:     Supported
-F:     drivers/net/ethernet/broadcom/bnx2.*
-F:     drivers/net/ethernet/broadcom/bnx2_*
-
-BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER
-M:     Yuval Mintz <Yuval.Mintz@cavium.com>
-M:     Ariel Elior <ariel.elior@cavium.com>
-M:     everest-linux-l2@cavium.com
-L:     netdev@vger.kernel.org
-S:     Supported
-F:     drivers/net/ethernet/broadcom/bnx2x/
-
-BROADCOM BNXT_EN 50 GIGABIT ETHERNET DRIVER
-M:     Michael Chan <michael.chan@broadcom.com>
-L:     netdev@vger.kernel.org
-S:     Supported
-F:     drivers/net/ethernet/broadcom/bnxt/
-
 BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITECTURE
 M:     Florian Fainelli <f.fainelli@gmail.com>
 M:     Ray Jui <rjui@broadcom.com>
@@ -2812,6 +2756,13 @@ F:       arch/arm/boot/dts/bcm7*.dts*
 F:     drivers/bus/brcmstb_gisb.c
 N:     brcmstb
 
+BROADCOM BMIPS CPUFREQ DRIVER
+M:     Markus Mayer <mmayer@broadcom.com>
+M:     bcm-kernel-feedback-list@broadcom.com
+L:     linux-pm@vger.kernel.org
+S:     Maintained
+F:     drivers/cpufreq/bmips-cpufreq.c
+
 BROADCOM BMIPS MIPS ARCHITECTURE
 M:     Kevin Cernekee <cernekee@gmail.com>
 M:     Florian Fainelli <f.fainelli@gmail.com>
@@ -2828,20 +2779,40 @@ F:      drivers/irqchip/irq-brcmstb*
 F:     include/linux/bcm963xx_nvram.h
 F:     include/linux/bcm963xx_tag.h
 
-BROADCOM BMIPS CPUFREQ DRIVER
-M:     Markus Mayer <mmayer@broadcom.com>
-M:     bcm-kernel-feedback-list@broadcom.com
-L:     linux-pm@vger.kernel.org
-S:     Maintained
-F:     drivers/cpufreq/bmips-cpufreq.c
+BROADCOM BNX2 GIGABIT ETHERNET DRIVER
+M:     Rasesh Mody <rasesh.mody@cavium.com>
+M:     Harish Patil <harish.patil@cavium.com>
+M:     Dept-GELinuxNICDev@cavium.com
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/ethernet/broadcom/bnx2.*
+F:     drivers/net/ethernet/broadcom/bnx2_*
 
-BROADCOM TG3 GIGABIT ETHERNET DRIVER
-M:     Siva Reddy Kallam <siva.kallam@broadcom.com>
-M:     Prashant Sreedharan <prashant@broadcom.com>
-M:     Michael Chan <mchan@broadcom.com>
+BROADCOM BNX2FC 10 GIGABIT FCOE DRIVER
+M:     QLogic-Storage-Upstream@qlogic.com
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+F:     drivers/scsi/bnx2fc/
+
+BROADCOM BNX2I 1/10 GIGABIT iSCSI DRIVER
+M:     QLogic-Storage-Upstream@qlogic.com
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+F:     drivers/scsi/bnx2i/
+
+BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER
+M:     Yuval Mintz <Yuval.Mintz@cavium.com>
+M:     Ariel Elior <ariel.elior@cavium.com>
+M:     everest-linux-l2@cavium.com
 L:     netdev@vger.kernel.org
 S:     Supported
-F:     drivers/net/ethernet/broadcom/tg3.*
+F:     drivers/net/ethernet/broadcom/bnx2x/
+
+BROADCOM BNXT_EN 50 GIGABIT ETHERNET DRIVER
+M:     Michael Chan <michael.chan@broadcom.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/ethernet/broadcom/bnxt/
 
 BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER
 M:     Arend van Spriel <arend.vanspriel@broadcom.com>
@@ -2855,17 +2826,18 @@ L:      brcm80211-dev-list@cypress.com
 S:     Supported
 F:     drivers/net/wireless/broadcom/brcm80211/
 
-BROADCOM BNX2FC 10 GIGABIT FCOE DRIVER
-M:     QLogic-Storage-Upstream@qlogic.com
-L:     linux-scsi@vger.kernel.org
+BROADCOM BRCMSTB GPIO DRIVER
+M:     Gregory Fong <gregory.0xf0@gmail.com>
+L:     bcm-kernel-feedback-list@broadcom.com
 S:     Supported
-F:     drivers/scsi/bnx2fc/
+F:     drivers/gpio/gpio-brcmstb.c
+F:     Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
 
-BROADCOM BNX2I 1/10 GIGABIT iSCSI DRIVER
-M:     QLogic-Storage-Upstream@qlogic.com
-L:     linux-scsi@vger.kernel.org
+BROADCOM GENET ETHERNET DRIVER
+M:     Florian Fainelli <f.fainelli@gmail.com>
+L:     netdev@vger.kernel.org
 S:     Supported
-F:     drivers/scsi/bnx2i/
+F:     drivers/net/ethernet/broadcom/genet/
 
 BROADCOM IPROC ARM ARCHITECTURE
 M:     Ray Jui <rjui@broadcom.com>
@@ -2892,13 +2864,6 @@ F:       arch/arm64/boot/dts/broadcom/ns2*
 F:     drivers/clk/bcm/clk-ns*
 F:     drivers/pinctrl/bcm/pinctrl-ns*
 
-BROADCOM BRCMSTB GPIO DRIVER
-M:     Gregory Fong <gregory.0xf0@gmail.com>
-L:     bcm-kernel-feedback-list@broadcom.com
-S:     Supported
-F:     drivers/gpio/gpio-brcmstb.c
-F:     Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
-
 BROADCOM KONA GPIO DRIVER
 M:     Ray Jui <rjui@broadcom.com>
 L:     bcm-kernel-feedback-list@broadcom.com
@@ -2906,19 +2871,29 @@ S:      Supported
 F:     drivers/gpio/gpio-bcm-kona.c
 F:     Documentation/devicetree/bindings/gpio/brcm,kona-gpio.txt
 
+BROADCOM NETXTREME-E ROCE DRIVER
+M:     Selvin Xavier <selvin.xavier@broadcom.com>
+M:     Devesh Sharma <devesh.sharma@broadcom.com>
+M:     Somnath Kotur <somnath.kotur@broadcom.com>
+M:     Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
+L:     linux-rdma@vger.kernel.org
+W:     http://www.broadcom.com
+S:     Supported
+F:     drivers/infiniband/hw/bnxt_re/
+F:     include/uapi/rdma/bnxt_re-abi.h
+
 BROADCOM NVRAM DRIVER
 M:     Rafał Miłecki <zajec5@gmail.com>
 L:     linux-mips@linux-mips.org
 S:     Maintained
 F:     drivers/firmware/broadcom/*
 
-BROADCOM STB NAND FLASH DRIVER
-M:     Brian Norris <computersforpeace@gmail.com>
-M:     Kamal Dasu <kdasu.kdev@gmail.com>
-L:     linux-mtd@lists.infradead.org
-L:     bcm-kernel-feedback-list@broadcom.com
+BROADCOM SPECIFIC AMBA DRIVER (BCMA)
+M:     Rafał Miłecki <zajec5@gmail.com>
+L:     linux-wireless@vger.kernel.org
 S:     Maintained
-F:     drivers/mtd/nand/brcmnand/
+F:     drivers/bcma/
+F:     include/linux/bcma/
 
 BROADCOM STB AVS CPUFREQ DRIVER
 M:     Markus Mayer <mmayer@broadcom.com>
@@ -2928,12 +2903,13 @@ S:      Maintained
 F:     Documentation/devicetree/bindings/cpufreq/brcm,stb-avs-cpu-freq.txt
 F:     drivers/cpufreq/brcmstb*
 
-BROADCOM SPECIFIC AMBA DRIVER (BCMA)
-M:     Rafał Miłecki <zajec5@gmail.com>
-L:     linux-wireless@vger.kernel.org
+BROADCOM STB NAND FLASH DRIVER
+M:     Brian Norris <computersforpeace@gmail.com>
+M:     Kamal Dasu <kdasu.kdev@gmail.com>
+L:     linux-mtd@lists.infradead.org
+L:     bcm-kernel-feedback-list@broadcom.com
 S:     Maintained
-F:     drivers/bcma/
-F:     include/linux/bcma/
+F:     drivers/mtd/nand/brcmnand/
 
 BROADCOM SYSTEMPORT ETHERNET DRIVER
 M:     Florian Fainelli <f.fainelli@gmail.com>
@@ -2941,16 +2917,13 @@ L:      netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/broadcom/bcmsysport.*
 
-BROADCOM NETXTREME-E ROCE DRIVER
-M:     Selvin Xavier <selvin.xavier@broadcom.com>
-M:     Devesh Sharma <devesh.sharma@broadcom.com>
-M:     Somnath Kotur <somnath.kotur@broadcom.com>
-M:     Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
-L:     linux-rdma@vger.kernel.org
-W:     http://www.broadcom.com
+BROADCOM TG3 GIGABIT ETHERNET DRIVER
+M:     Siva Reddy Kallam <siva.kallam@broadcom.com>
+M:     Prashant Sreedharan <prashant@broadcom.com>
+M:     Michael Chan <mchan@broadcom.com>
+L:     netdev@vger.kernel.org
 S:     Supported
-F:     drivers/infiniband/hw/bnxt_re/
-F:     include/uapi/rdma/bnxt_re-abi.h
+F:     drivers/net/ethernet/broadcom/tg3.*
 
 BROCADE BFA FC SCSI DRIVER
 M:     Anil Gurumurthy <anil.gurumurthy@qlogic.com>
@@ -3013,6 +2986,15 @@ S:       Odd fixes
 F:     Documentation/media/v4l-drivers/bttv*
 F:     drivers/media/pci/bt8xx/bttv*
 
+BUS FREQUENCY DRIVER FOR SAMSUNG EXYNOS
+M:     Chanwoo Choi <cw00.choi@samsung.com>
+L:     linux-pm@vger.kernel.org
+L:     linux-samsung-soc@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq.git
+S:     Maintained
+F:     drivers/devfreq/exynos-bus.c
+F:     Documentation/devicetree/bindings/devfreq/exynos-bus.txt
+
 BUSLOGIC SCSI DRIVER
 M:     Khalid Aziz <khalid@gonehiking.org>
 L:     linux-scsi@vger.kernel.org
@@ -3087,6 +3069,21 @@ F:       arch/x86/kernel/tce_64.c
 F:     arch/x86/include/asm/calgary.h
 F:     arch/x86/include/asm/tce.h
 
+CAN NETWORK DRIVERS
+M:     Wolfgang Grandegger <wg@grandegger.com>
+M:     Marc Kleine-Budde <mkl@pengutronix.de>
+L:     linux-can@vger.kernel.org
+W:     https://github.com/linux-can
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
+S:     Maintained
+F:     Documentation/devicetree/bindings/net/can/
+F:     drivers/net/can/
+F:     include/linux/can/dev.h
+F:     include/linux/can/platform/
+F:     include/uapi/linux/can/error.h
+F:     include/uapi/linux/can/netlink.h
+
 CAN NETWORK LAYER
 M:     Oliver Hartkopp <socketcan@hartkopp.net>
 M:     Marc Kleine-Budde <mkl@pengutronix.de>
@@ -3103,21 +3100,6 @@ F:       include/uapi/linux/can/bcm.h
 F:     include/uapi/linux/can/raw.h
 F:     include/uapi/linux/can/gw.h
 
-CAN NETWORK DRIVERS
-M:     Wolfgang Grandegger <wg@grandegger.com>
-M:     Marc Kleine-Budde <mkl@pengutronix.de>
-L:     linux-can@vger.kernel.org
-W:     https://github.com/linux-can
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
-S:     Maintained
-F:     Documentation/devicetree/bindings/net/can/
-F:     drivers/net/can/
-F:     include/linux/can/dev.h
-F:     include/linux/can/platform/
-F:     include/uapi/linux/can/error.h
-F:     include/uapi/linux/can/netlink.h
-
 CAPABILITIES
 M:     Serge Hallyn <serge@hallyn.com>
 L:     linux-security-module@vger.kernel.org
@@ -3132,12 +3114,12 @@ M:      Kevin Tsai <ktsai@capellamicro.com>
 S:     Maintained
 F:     drivers/iio/light/cm*
 
-CAVIUM THUNDERX2 ARM64 SOC
-M:     Jayachandran C <jnair@caviumnetworks.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+CARL9170 LINUX COMMUNITY WIRELESS DRIVER
+M:     Christian Lamparter <chunkeey@googlemail.com>
+L:     linux-wireless@vger.kernel.org
+W:     http://wireless.kernel.org/en/users/Drivers/carl9170
 S:     Maintained
-F:     arch/arm64/boot/dts/cavium/thunder2-99xx*
-F:     Documentation/devicetree/bindings/arm/cavium-thunder2.txt
+F:     drivers/net/wireless/ath/carl9170/
 
 CAVIUM I2C DRIVER
 M:     Jan Glauber <jglauber@cavium.com>
@@ -3147,6 +3129,16 @@ S:       Supported
 F:     drivers/i2c/busses/i2c-octeon*
 F:     drivers/i2c/busses/i2c-thunderx*
 
+CAVIUM LIQUIDIO NETWORK DRIVER
+M:     Derek Chickles <derek.chickles@caviumnetworks.com>
+M:     Satanand Burla <satananda.burla@caviumnetworks.com>
+M:     Felix Manlunas <felix.manlunas@caviumnetworks.com>
+M:     Raghu Vatsavayi <raghu.vatsavayi@caviumnetworks.com>
+L:     netdev@vger.kernel.org
+W:     http://www.cavium.com
+S:     Supported
+F:     drivers/net/ethernet/cavium/liquidio/
+
 CAVIUM MMC DRIVER
 M:     Jan Glauber <jglauber@cavium.com>
 M:     David Daney <david.daney@cavium.com>
@@ -3155,16 +3147,6 @@ W:       http://www.cavium.com
 S:     Supported
 F:     drivers/mmc/host/cavium*
 
-CAVIUM LIQUIDIO NETWORK DRIVER
-M:     Derek Chickles <derek.chickles@caviumnetworks.com>
-M:     Satanand Burla <satananda.burla@caviumnetworks.com>
-M:     Felix Manlunas <felix.manlunas@caviumnetworks.com>
-M:     Raghu Vatsavayi <raghu.vatsavayi@caviumnetworks.com>
-L:     netdev@vger.kernel.org
-W:     http://www.cavium.com
-S:     Supported
-F:     drivers/net/ethernet/cavium/liquidio/
-
 CAVIUM OCTEON-TX CRYPTO DRIVER
 M:     George Cherian <george.cherian@cavium.com>
 L:     linux-crypto@vger.kernel.org
@@ -3172,6 +3154,13 @@ W:       http://www.cavium.com
 S:     Supported
 F:     drivers/crypto/cavium/cpt/
 
+CAVIUM THUNDERX2 ARM64 SOC
+M:     Jayachandran C <jnair@caviumnetworks.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm64/boot/dts/cavium/thunder2-99xx*
+F:     Documentation/devicetree/bindings/arm/cavium-thunder2.txt
+
 CC2520 IEEE-802.15.4 RADIO DRIVER
 M:     Varka Bhadram <varkabhadram@gmail.com>
 L:     linux-wpan@vger.kernel.org
@@ -3260,12 +3249,6 @@ F:       drivers/usb/host/whci/
 F:     drivers/usb/wusbcore/
 F:     include/linux/usb/wusb*
 
-HT16K33 LED CONTROLLER DRIVER
-M:     Robin van der Gracht <robin@protonic.nl>
-S:     Maintained
-F:     drivers/auxdisplay/ht16k33.c
-F:     Documentation/devicetree/bindings/display/ht16k33.txt
-
 CFAG12864B LCD DRIVER
 M:     Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
 W:     http://miguelojeda.es/auxdisplay.htm
@@ -3337,6 +3320,34 @@ S:       Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bleung/chrome-platform.git
 F:     drivers/platform/chrome/
 
+CIRRUS LOGIC AUDIO CODEC DRIVERS
+M:     Brian Austin <brian.austin@cirrus.com>
+M:     Paul Handrigan <Paul.Handrigan@cirrus.com>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     sound/soc/codecs/cs*
+
+CIRRUS LOGIC EP93XX ETHERNET DRIVER
+M:     Hartley Sweeten <hsweeten@visionengravers.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ethernet/cirrus/ep93xx_eth.c
+
+CISCO FCOE HBA DRIVER
+M:     Satish Kharat <satishkh@cisco.com>
+M:     Sesidhar Baddela <sebaddel@cisco.com>
+M:     Karan Tilak Kumar <kartilak@cisco.com>
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+F:     drivers/scsi/fnic/
+
+CISCO SCSI HBA DRIVER
+M:     Karan Tilak Kumar <kartilak@cisco.com>
+M:     Sesidhar Baddela <sebaddel@cisco.com>
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+F:     drivers/scsi/snic/
+
 CISCO VIC ETHERNET NIC DRIVER
 M:     Christian Benvenuti <benve@cisco.com>
 M:     Govindarajulu Varadarajan <_govind@gmx.com>
@@ -3350,19 +3361,6 @@ M:       Dave Goodell <dgoodell@cisco.com>
 S:     Supported
 F:     drivers/infiniband/hw/usnic/
 
-CIRRUS LOGIC EP93XX ETHERNET DRIVER
-M:     Hartley Sweeten <hsweeten@visionengravers.com>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/net/ethernet/cirrus/ep93xx_eth.c
-
-CIRRUS LOGIC AUDIO CODEC DRIVERS
-M:     Brian Austin <brian.austin@cirrus.com>
-M:     Paul Handrigan <Paul.Handrigan@cirrus.com>
-L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-S:     Maintained
-F:     sound/soc/codecs/cs*
-
 CLEANCACHE API
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 L:     linux-kernel@vger.kernel.org
@@ -3384,21 +3382,6 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 S:     Supported
 F:     drivers/clocksource
 
-CISCO FCOE HBA DRIVER
-M:     Satish Kharat <satishkh@cisco.com>
-M:     Sesidhar Baddela <sebaddel@cisco.com>
-M:     Karan Tilak Kumar <kartilak@cisco.com>
-L:     linux-scsi@vger.kernel.org
-S:     Supported
-F:     drivers/scsi/fnic/
-
-CISCO SCSI HBA DRIVER
-M:     Karan Tilak Kumar <kartilak@cisco.com>
-M:     Sesidhar Baddela <sebaddel@cisco.com>
-L:     linux-scsi@vger.kernel.org
-S:     Supported
-F:     drivers/scsi/snic/
-
 CMPC ACPI DRIVER
 M:     Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
 M:     Daniel Oliveira Nascimento <don@syst.com.br>
@@ -3474,17 +3457,17 @@ L:      linux-pci@vger.kernel.org
 S:     Maintained
 F:     drivers/pci/hotplug/cpci_hotplug*
 
-COMPACTPCI HOTPLUG ZIATECH ZT5550 DRIVER
+COMPACTPCI HOTPLUG GENERIC DRIVER
 M:     Scott Murray <scott@spiteful.org>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
-F:     drivers/pci/hotplug/cpcihp_zt5550.*
+F:     drivers/pci/hotplug/cpcihp_generic.c
 
-COMPACTPCI HOTPLUG GENERIC DRIVER
+COMPACTPCI HOTPLUG ZIATECH ZT5550 DRIVER
 M:     Scott Murray <scott@spiteful.org>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
-F:     drivers/pci/hotplug/cpcihp_generic.c
+F:     drivers/pci/hotplug/cpcihp_zt5550.*
 
 COMPAL LAPTOP SUPPORT
 M:     Cezary Jackiewicz <cezary.jackiewicz@gmail.com>
@@ -3587,6 +3570,18 @@ F:       drivers/cpufreq/arm_big_little.h
 F:     drivers/cpufreq/arm_big_little.c
 F:     drivers/cpufreq/arm_big_little_dt.c
 
+CPU POWER MONITORING SUBSYSTEM
+M:     Thomas Renninger <trenn@suse.com>
+L:     linux-pm@vger.kernel.org
+S:     Maintained
+F:     tools/power/cpupower/
+
+CPUID/MSR DRIVER
+M:     "H. Peter Anvin" <hpa@zytor.com>
+S:     Maintained
+F:     arch/x86/kernel/cpuid.c
+F:     arch/x86/kernel/msr.c
+
 CPUIDLE DRIVER - ARM BIG LITTLE
 M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
 M:     Daniel Lezcano <daniel.lezcano@linaro.org>
@@ -3616,18 +3611,6 @@ B:       https://bugzilla.kernel.org
 F:     drivers/cpuidle/*
 F:     include/linux/cpuidle.h
 
-CPUID/MSR DRIVER
-M:     "H. Peter Anvin" <hpa@zytor.com>
-S:     Maintained
-F:     arch/x86/kernel/cpuid.c
-F:     arch/x86/kernel/msr.c
-
-CPU POWER MONITORING SUBSYSTEM
-M:     Thomas Renninger <trenn@suse.com>
-L:     linux-pm@vger.kernel.org
-S:     Maintained
-F:     tools/power/cpupower/
-
 CRAMFS FILESYSTEM
 W:     http://sourceforge.net/projects/cramfs/
 S:     Orphan / Obsolete
@@ -3757,6 +3740,13 @@ S:       Supported
 F:     drivers/infiniband/hw/cxgb3/
 F:     include/uapi/rdma/cxgb3-abi.h
 
+CXGB4 CRYPTO DRIVER (chcr)
+M:     Harsh Jain <harsh@chelsio.com>
+L:     linux-crypto@vger.kernel.org
+W:     http://www.chelsio.com
+S:     Supported
+F:     drivers/crypto/chelsio
+
 CXGB4 ETHERNET DRIVER (CXGB4)
 M:     Ganesh Goudar <ganeshgr@chelsio.com>
 L:     netdev@vger.kernel.org
@@ -3779,13 +3769,6 @@ S:       Supported
 F:     drivers/infiniband/hw/cxgb4/
 F:     include/uapi/rdma/cxgb4-abi.h
 
-CXGB4 CRYPTO DRIVER (chcr)
-M:     Harsh Jain <harsh@chelsio.com>
-L:     linux-crypto@vger.kernel.org
-W:     http://www.chelsio.com
-S:     Supported
-F:     drivers/crypto/chelsio
-
 CXGB4VF ETHERNET DRIVER (CXGB4VF)
 M:     Casey Leedom <leedom@chelsio.com>
 L:     netdev@vger.kernel.org
@@ -3815,14 +3798,6 @@ F:       drivers/scsi/cxlflash/
 F:     include/uapi/scsi/cxlflash_ioctls.h
 F:     Documentation/powerpc/cxlflash.txt
 
-STMMAC ETHERNET DRIVER
-M:     Giuseppe Cavallaro <peppe.cavallaro@st.com>
-M:     Alexandre Torgue <alexandre.torgue@st.com>
-L:     netdev@vger.kernel.org
-W:     http://www.stlinux.com
-S:     Supported
-F:     drivers/net/ethernet/stmicro/stmmac/
-
 CYBERPRO FB DRIVER
 M:     Russell King <linux@armlinux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -3946,15 +3921,15 @@ L:      platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     drivers/platform/x86/dell-laptop.c
 
-DELL LAPTOP RBTN DRIVER
+DELL LAPTOP FREEFALL DRIVER
 M:     Pali Rohár <pali.rohar@gmail.com>
 S:     Maintained
-F:     drivers/platform/x86/dell-rbtn.*
+F:     drivers/platform/x86/dell-smo8800.c
 
-DELL LAPTOP FREEFALL DRIVER
+DELL LAPTOP RBTN DRIVER
 M:     Pali Rohár <pali.rohar@gmail.com>
 S:     Maintained
-F:     drivers/platform/x86/dell-smo8800.c
+F:     drivers/platform/x86/dell-rbtn.*
 
 DELL LAPTOP SMM DRIVER
 M:     Pali Rohár <pali.rohar@gmail.com>
@@ -3974,6 +3949,20 @@ M:       Pali Rohár <pali.rohar@gmail.com>
 S:     Maintained
 F:     drivers/platform/x86/dell-wmi.c
 
+DELTA ST MEDIA DRIVER
+M:     Hugues Fruchet <hugues.fruchet@st.com>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+W:     https://linuxtv.org
+S:     Supported
+F:     drivers/media/platform/sti/delta
+
+DENALI NAND DRIVER
+M:     Masahiro Yamada <yamada.masahiro@socionext.com>
+L:     linux-mtd@lists.infradead.org
+S:     Supported
+F:     drivers/mtd/nand/denali*
+
 DESIGNWARE USB2 DRD IP DRIVER
 M:     John Youn <johnyoun@synopsys.com>
 L:     linux-usb@vger.kernel.org
@@ -4022,15 +4011,6 @@ F:       drivers/devfreq/devfreq-event.c
 F:     include/linux/devfreq-event.h
 F:     Documentation/devicetree/bindings/devfreq/event/
 
-BUS FREQUENCY DRIVER FOR SAMSUNG EXYNOS
-M:     Chanwoo Choi <cw00.choi@samsung.com>
-L:     linux-pm@vger.kernel.org
-L:     linux-samsung-soc@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq.git
-S:     Maintained
-F:     drivers/devfreq/exynos-bus.c
-F:     Documentation/devicetree/bindings/devfreq/exynos-bus.txt
-
 DEVICE NUMBER REGISTRY
 M:     Torben Mathiasen <device@lanana.org>
 W:     http://lanana.org/docs/device-list/index.html
@@ -4180,20 +4160,6 @@ F:       include/linux/*fence.h
 F:     Documentation/driver-api/dma-buf.rst
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 
-SYNC FILE FRAMEWORK
-M:     Sumit Semwal <sumit.semwal@linaro.org>
-R:     Gustavo Padovan <gustavo@padovan.org>
-S:     Maintained
-L:     linux-media@vger.kernel.org
-L:     dri-devel@lists.freedesktop.org
-F:     drivers/dma-buf/sync_*
-F:     drivers/dma-buf/dma-fence*
-F:     drivers/dma-buf/sw_sync.c
-F:     include/linux/sync_file.h
-F:     include/uapi/linux/sync_file.h
-F:     Documentation/sync_file.txt
-T:     git git://anongit.freedesktop.org/drm/drm-misc
-
 DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
 M:     Vinod Koul <vinod.koul@intel.com>
 L:     dmaengine@vger.kernel.org
@@ -4205,6 +4171,21 @@ F:       Documentation/devicetree/bindings/dma/
 F:     Documentation/dmaengine/
 T:     git git://git.infradead.org/users/vkoul/slave-dma.git
 
+DMA MAPPING HELPERS
+M:     Christoph Hellwig <hch@lst.de>
+M:     Marek Szyprowski <m.szyprowski@samsung.com>
+R:     Robin Murphy <robin.murphy@arm.com>
+L:     linux-kernel@vger.kernel.org
+T:     git git://git.infradead.org/users/hch/dma-mapping.git
+W:     http://git.infradead.org/users/hch/dma-mapping.git
+S:     Supported
+F:     lib/dma-debug.c
+F:     lib/dma-noop.c
+F:     lib/dma-virt.c
+F:     drivers/base/dma-mapping.c
+F:     drivers/base/dma-coherent.c
+F:     include/linux/dma-mapping.h
+
 DME1737 HARDWARE MONITOR DRIVER
 M:     Juerg Haefliger <juergh@gmail.com>
 L:     linux-hwmon@vger.kernel.org
@@ -4235,6 +4216,13 @@ X:       Documentation/spi
 X:     Documentation/media
 T:     git git://git.lwn.net/linux.git docs-next
 
+DONGWOON DW9714 LENS VOICE COIL DRIVER
+M:     Sakari Ailus <sakari.ailus@linux.intel.com>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Maintained
+F:     drivers/media/i2c/dw9714.c
+
 DOUBLETALK DRIVER
 M:     "James R. Van Zandt" <jrv@vanzandt.mv.com>
 L:     blinux-list@redhat.com
@@ -4286,36 +4274,13 @@ F:      include/linux/debugfs.h
 F:     include/linux/kobj*
 F:     lib/kobj*
 
-DRM DRIVERS
-M:     David Airlie <airlied@linux.ie>
-L:     dri-devel@lists.freedesktop.org
-T:     git git://people.freedesktop.org/~airlied/linux
-B:     https://bugs.freedesktop.org/
-C:     irc://chat.freenode.net/dri-devel
-S:     Maintained
-F:     drivers/gpu/drm/
-F:     drivers/gpu/vga/
-F:     Documentation/devicetree/bindings/display/
-F:     Documentation/devicetree/bindings/gpu/
-F:     Documentation/devicetree/bindings/video/
-F:     Documentation/gpu/
-F:     include/drm/
-F:     include/uapi/drm/
-F:     include/linux/vga*
-
-DRM DRIVERS AND MISC GPU PATCHES
-M:     Daniel Vetter <daniel.vetter@intel.com>
-M:     Jani Nikula <jani.nikula@linux.intel.com>
-M:     Sean Paul <seanpaul@chromium.org>
-W:     https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html
+DRIVERS FOR ADAPTIVE VOLTAGE SCALING (AVS)
+M:     Kevin Hilman <khilman@kernel.org>
+M:     Nishanth Menon <nm@ti.com>
 S:     Maintained
-T:     git git://anongit.freedesktop.org/drm/drm-misc
-F:     Documentation/gpu/
-F:     drivers/gpu/vga/
-F:     drivers/gpu/drm/*
-F:     include/drm/drm*
-F:     include/uapi/drm/drm*
-F:     include/linux/vga*
+F:     drivers/power/avs/
+F:     include/linux/power/smartreflex.h
+L:     linux-pm@vger.kernel.org
 
 DRM DRIVER FOR ARM PL111 CLCD
 M:     Eric Anholt <eric@anholt.net>
@@ -4328,14 +4293,6 @@ M:       Dave Airlie <airlied@redhat.com>
 S:     Odd Fixes
 F:     drivers/gpu/drm/ast/
 
-DRM DRIVERS FOR BRIDGE CHIPS
-M:     Archit Taneja <architt@codeaurora.org>
-M:     Andrzej Hajda <a.hajda@samsung.com>
-R:     Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
-S:     Maintained
-T:     git git://anongit.freedesktop.org/drm/drm-misc
-F:     drivers/gpu/drm/bridge/
-
 DRM DRIVER FOR BOCHS VIRTUAL GPU
 M:     Gerd Hoffmann <kraxel@redhat.com>
 L:     virtualization@lists.linux-foundation.org
@@ -4343,68 +4300,130 @@ T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
 F:     drivers/gpu/drm/bochs/
 
-DRM DRIVER FOR QEMU'S CIRRUS DEVICE
+DRM DRIVER FOR INTEL I810 VIDEO CARDS
+S:     Orphan / Obsolete
+F:     drivers/gpu/drm/i810/
+F:     include/uapi/drm/i810_drm.h
+
+DRM DRIVER FOR MATROX G200/G400 GRAPHICS CARDS
+S:     Orphan / Obsolete
+F:     drivers/gpu/drm/mga/
+F:     include/uapi/drm/mga_drm.h
+
+DRM DRIVER FOR MGA G200 SERVER GRAPHICS CHIPS
 M:     Dave Airlie <airlied@redhat.com>
-M:     Gerd Hoffmann <kraxel@redhat.com>
-L:     virtualization@lists.linux-foundation.org
-T:     git git://anongit.freedesktop.org/drm/drm-misc
-S:     Obsolete
-W:     https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
-F:     drivers/gpu/drm/cirrus/
+S:     Odd Fixes
+F:     drivers/gpu/drm/mgag200/
 
-RADEON and AMDGPU DRM DRIVERS
-M:     Alex Deucher <alexander.deucher@amd.com>
-M:     Christian König <christian.koenig@amd.com>
-L:     amd-gfx@lists.freedesktop.org
-T:     git git://people.freedesktop.org/~agd5f/linux
-S:     Supported
-F:     drivers/gpu/drm/radeon/
-F:     include/uapi/drm/radeon_drm.h
-F:     drivers/gpu/drm/amd/
-F:     include/uapi/drm/amdgpu_drm.h
+DRM DRIVER FOR MI0283QT
+M:     Noralf Trønnes <noralf@tronnes.org>
+S:     Maintained
+F:     drivers/gpu/drm/tinydrm/mi0283qt.c
+F:     Documentation/devicetree/bindings/display/multi-inno,mi0283qt.txt
 
-DRM PANEL DRIVERS
-M:     Thierry Reding <thierry.reding@gmail.com>
+DRM DRIVER FOR MSM ADRENO GPU
+M:     Rob Clark <robdclark@gmail.com>
+L:     linux-arm-msm@vger.kernel.org
 L:     dri-devel@lists.freedesktop.org
-T:     git git://anongit.freedesktop.org/tegra/linux.git
+L:     freedreno@lists.freedesktop.org
+T:     git git://people.freedesktop.org/~robclark/linux
 S:     Maintained
-F:     drivers/gpu/drm/drm_panel.c
-F:     drivers/gpu/drm/panel/
-F:     include/drm/drm_panel.h
-F:     Documentation/devicetree/bindings/display/panel/
+F:     drivers/gpu/drm/msm/
+F:     include/uapi/drm/msm_drm.h
+F:     Documentation/devicetree/bindings/display/msm/
 
-INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
-M:     Daniel Vetter <daniel.vetter@intel.com>
-M:     Jani Nikula <jani.nikula@linux.intel.com>
-L:     intel-gfx@lists.freedesktop.org
-W:     https://01.org/linuxgraphics/
-B:     https://01.org/linuxgraphics/documentation/how-report-bugs
-C:     irc://chat.freenode.net/intel-gfx
-Q:     http://patchwork.freedesktop.org/project/intel-gfx/
-T:     git git://anongit.freedesktop.org/drm-intel
+DRM DRIVER FOR NVIDIA GEFORCE/QUADRO GPUS
+M:     Ben Skeggs <bskeggs@redhat.com>
+L:     dri-devel@lists.freedesktop.org
+L:     nouveau@lists.freedesktop.org
+T:     git git://github.com/skeggsb/linux
 S:     Supported
-F:     drivers/gpu/drm/i915/
-F:     include/drm/i915*
-F:     include/uapi/drm/i915_drm.h
-F:     Documentation/gpu/i915.rst
+F:     drivers/gpu/drm/nouveau/
+F:     include/uapi/drm/nouveau_drm.h
 
-INTEL GVT-g DRIVERS (Intel GPU Virtualization)
-M:      Zhenyu Wang <zhenyuw@linux.intel.com>
-M:      Zhi Wang <zhi.a.wang@intel.com>
-L:      intel-gvt-dev@lists.freedesktop.org
-L:      intel-gfx@lists.freedesktop.org
-W:      https://01.org/igvt-g
-T:      git https://github.com/01org/gvt-linux.git
-S:      Supported
-F:      drivers/gpu/drm/i915/gvt/
+DRM DRIVER FOR QEMU'S CIRRUS DEVICE
+M:     Dave Airlie <airlied@redhat.com>
+M:     Gerd Hoffmann <kraxel@redhat.com>
+L:     virtualization@lists.linux-foundation.org
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+S:     Obsolete
+W:     https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
+F:     drivers/gpu/drm/cirrus/
 
-DRM DRIVERS FOR ATMEL HLCDC
-M:     Boris Brezillon <boris.brezillon@free-electrons.com>
+DRM DRIVER FOR QXL VIRTUAL GPU
+M:     Dave Airlie <airlied@redhat.com>
+M:     Gerd Hoffmann <kraxel@redhat.com>
+L:     virtualization@lists.linux-foundation.org
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+S:     Maintained
+F:     drivers/gpu/drm/qxl/
+F:     include/uapi/drm/qxl_drm.h
+
+DRM DRIVER FOR RAGE 128 VIDEO CARDS
+S:     Orphan / Obsolete
+F:     drivers/gpu/drm/r128/
+F:     include/uapi/drm/r128_drm.h
+
+DRM DRIVER FOR SAVAGE VIDEO CARDS
+S:     Orphan / Obsolete
+F:     drivers/gpu/drm/savage/
+F:     include/uapi/drm/savage_drm.h
+
+DRM DRIVER FOR SIS VIDEO CARDS
+S:     Orphan / Obsolete
+F:     drivers/gpu/drm/sis/
+F:     include/uapi/drm/sis_drm.h
+
+DRM DRIVER FOR TDFX VIDEO CARDS
+S:     Orphan / Obsolete
+F:     drivers/gpu/drm/tdfx/
+
+DRM DRIVER FOR USB DISPLAYLINK VIDEO ADAPTERS
+M:     Dave Airlie <airlied@redhat.com>
+S:     Odd Fixes
+F:     drivers/gpu/drm/udl/
+
+DRM DRIVER FOR VMWARE VIRTUAL GPU
+M:     "VMware Graphics" <linux-graphics-maintainer@vmware.com>
+M:     Sinclair Yeh <syeh@vmware.com>
+M:     Thomas Hellstrom <thellstrom@vmware.com>
 L:     dri-devel@lists.freedesktop.org
+T:     git git://people.freedesktop.org/~syeh/repos_linux
+T:     git git://people.freedesktop.org/~thomash/linux
 S:     Supported
-F:     drivers/gpu/drm/atmel-hlcdc/
-F:     Documentation/devicetree/bindings/drm/atmel/
+F:     drivers/gpu/drm/vmwgfx/
+F:     include/uapi/drm/vmwgfx_drm.h
+
+DRM DRIVERS
+M:     David Airlie <airlied@linux.ie>
+L:     dri-devel@lists.freedesktop.org
+T:     git git://people.freedesktop.org/~airlied/linux
+B:     https://bugs.freedesktop.org/
+C:     irc://chat.freenode.net/dri-devel
+S:     Maintained
+F:     drivers/gpu/drm/
+F:     drivers/gpu/vga/
+F:     Documentation/devicetree/bindings/display/
+F:     Documentation/devicetree/bindings/gpu/
+F:     Documentation/devicetree/bindings/video/
+F:     Documentation/gpu/
+F:     include/drm/
+F:     include/uapi/drm/
+F:     include/linux/vga*
+
+DRM DRIVERS AND MISC GPU PATCHES
+M:     Daniel Vetter <daniel.vetter@intel.com>
+M:     Jani Nikula <jani.nikula@linux.intel.com>
+M:     Sean Paul <seanpaul@chromium.org>
+W:     https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html
+S:     Maintained
 T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/gpu/
+F:     drivers/gpu/vga/
+F:     drivers/gpu/drm/*
+F:     include/drm/drm*
+F:     include/uapi/drm/drm*
+F:     include/linux/vga*
 
 DRM DRIVERS FOR ALLWINNER A10
 M:     Maxime Ripard  <maxime.ripard@free-electrons.com>
@@ -4426,6 +4445,22 @@ F:       Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
 F:     Documentation/gpu/meson.rst
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 
+DRM DRIVERS FOR ATMEL HLCDC
+M:     Boris Brezillon <boris.brezillon@free-electrons.com>
+L:     dri-devel@lists.freedesktop.org
+S:     Supported
+F:     drivers/gpu/drm/atmel-hlcdc/
+F:     Documentation/devicetree/bindings/drm/atmel/
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+
+DRM DRIVERS FOR BRIDGE CHIPS
+M:     Archit Taneja <architt@codeaurora.org>
+M:     Andrzej Hajda <a.hajda@samsung.com>
+R:     Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
+S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     drivers/gpu/drm/bridge/
+
 DRM DRIVERS FOR EXYNOS
 M:     Inki Dae <inki.dae@samsung.com>
 M:     Joonyoung Shim <jy0922.shim@samsung.com>
@@ -4474,11 +4509,6 @@ S:       Maintained
 F:     drivers/gpu/drm/hisilicon/
 F:     Documentation/devicetree/bindings/display/hisilicon/
 
-DRM DRIVER FOR INTEL I810 VIDEO CARDS
-S:     Orphan / Obsolete
-F:     drivers/gpu/drm/i810/
-F:     include/uapi/drm/i810_drm.h
-
 DRM DRIVERS FOR MEDIATEK
 M:     CK Hu <ck.hu@mediatek.com>
 M:     Philipp Zabel <p.zabel@pengutronix.de>
@@ -4487,32 +4517,6 @@ S:       Supported
 F:     drivers/gpu/drm/mediatek/
 F:     Documentation/devicetree/bindings/display/mediatek/
 
-DRM DRIVER FOR MI0283QT
-M:     Noralf Trønnes <noralf@tronnes.org>
-S:     Maintained
-F:     drivers/gpu/drm/tinydrm/mi0283qt.c
-F:     Documentation/devicetree/bindings/display/multi-inno,mi0283qt.txt
-
-DRM DRIVER FOR MSM ADRENO GPU
-M:     Rob Clark <robdclark@gmail.com>
-L:     linux-arm-msm@vger.kernel.org
-L:     dri-devel@lists.freedesktop.org
-L:     freedreno@lists.freedesktop.org
-T:     git git://people.freedesktop.org/~robclark/linux
-S:     Maintained
-F:     drivers/gpu/drm/msm/
-F:     include/uapi/drm/msm_drm.h
-F:     Documentation/devicetree/bindings/display/msm/
-
-DRM DRIVER FOR NVIDIA GEFORCE/QUADRO GPUS
-M:     Ben Skeggs <bskeggs@redhat.com>
-L:     dri-devel@lists.freedesktop.org
-L:     nouveau@lists.freedesktop.org
-T:     git git://github.com/skeggsb/linux
-S:     Supported
-F:     drivers/gpu/drm/nouveau/
-F:     include/uapi/drm/nouveau_drm.h
-
 DRM DRIVERS FOR NVIDIA TEGRA
 M:     Thierry Reding <thierry.reding@gmail.com>
 L:     dri-devel@lists.freedesktop.org
@@ -4525,21 +4529,6 @@ F:       include/linux/host1x.h
 F:     include/uapi/drm/tegra_drm.h
 F:     Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
 
-DRM DRIVER FOR MATROX G200/G400 GRAPHICS CARDS
-S:     Orphan / Obsolete
-F:     drivers/gpu/drm/mga/
-F:     include/uapi/drm/mga_drm.h
-
-DRM DRIVER FOR MGA G200 SERVER GRAPHICS CHIPS
-M:     Dave Airlie <airlied@redhat.com>
-S:     Odd Fixes
-F:     drivers/gpu/drm/mgag200/
-
-DRM DRIVER FOR RAGE 128 VIDEO CARDS
-S:     Orphan / Obsolete
-F:     drivers/gpu/drm/r128/
-F:     include/uapi/drm/r128_drm.h
-
 DRM DRIVERS FOR RENESAS
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     dri-devel@lists.freedesktop.org
@@ -4552,15 +4541,6 @@ F:       include/linux/platform_data/shmob_drm.h
 F:     Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt
 F:     Documentation/devicetree/bindings/display/renesas,du.txt
 
-DRM DRIVER FOR QXL VIRTUAL GPU
-M:     Dave Airlie <airlied@redhat.com>
-M:     Gerd Hoffmann <kraxel@redhat.com>
-L:     virtualization@lists.linux-foundation.org
-T:     git git://anongit.freedesktop.org/drm/drm-misc
-S:     Maintained
-F:     drivers/gpu/drm/qxl/
-F:     include/uapi/drm/qxl_drm.h
-
 DRM DRIVERS FOR ROCKCHIP
 M:     Mark Yao <mark.yao@rock-chips.com>
 L:     dri-devel@lists.freedesktop.org
@@ -4569,16 +4549,6 @@ F:       drivers/gpu/drm/rockchip/
 F:     Documentation/devicetree/bindings/display/rockchip/
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 
-DRM DRIVER FOR SAVAGE VIDEO CARDS
-S:     Orphan / Obsolete
-F:     drivers/gpu/drm/savage/
-F:     include/uapi/drm/savage_drm.h
-
-DRM DRIVER FOR SIS VIDEO CARDS
-S:     Orphan / Obsolete
-F:     drivers/gpu/drm/sis/
-F:     include/uapi/drm/sis_drm.h
-
 DRM DRIVERS FOR STI
 M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
 M:     Vincent Abriou <vincent.abriou@st.com>
@@ -4599,36 +4569,20 @@ S:      Maintained
 F:     drivers/gpu/drm/stm
 F:     Documentation/devicetree/bindings/display/st,stm32-ltdc.txt
 
-DRM DRIVER FOR TDFX VIDEO CARDS
-S:     Orphan / Obsolete
-F:     drivers/gpu/drm/tdfx/
-
-DRM DRIVER FOR USB DISPLAYLINK VIDEO ADAPTERS
-M:     Dave Airlie <airlied@redhat.com>
-S:     Odd Fixes
-F:     drivers/gpu/drm/udl/
-
-DRM DRIVERS FOR VIVANTE GPU IP
-M:     Lucas Stach <l.stach@pengutronix.de>
-R:     Russell King <linux+etnaviv@armlinux.org.uk>
-R:     Christian Gmeiner <christian.gmeiner@gmail.com>
-L:     etnaviv@lists.freedesktop.org
+DRM DRIVERS FOR TI LCDC
+M:     Jyri Sarha <jsarha@ti.com>
+R:     Tomi Valkeinen <tomi.valkeinen@ti.com>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
-F:     drivers/gpu/drm/etnaviv/
-F:     include/uapi/drm/etnaviv_drm.h
-F:     Documentation/devicetree/bindings/display/etnaviv/
+F:     drivers/gpu/drm/tilcdc/
+F:     Documentation/devicetree/bindings/display/tilcdc/
 
-DRM DRIVER FOR VMWARE VIRTUAL GPU
-M:     "VMware Graphics" <linux-graphics-maintainer@vmware.com>
-M:     Sinclair Yeh <syeh@vmware.com>
-M:     Thomas Hellstrom <thellstrom@vmware.com>
+DRM DRIVERS FOR TI OMAP
+M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://people.freedesktop.org/~syeh/repos_linux
-T:     git git://people.freedesktop.org/~thomash/linux
-S:     Supported
-F:     drivers/gpu/drm/vmwgfx/
-F:     include/uapi/drm/vmwgfx_drm.h
+S:     Maintained
+F:     drivers/gpu/drm/omapdrm/
+F:     Documentation/devicetree/bindings/display/ti/
 
 DRM DRIVERS FOR VC4
 M:     Eric Anholt <eric@anholt.net>
@@ -4639,20 +4593,16 @@ F:      include/uapi/drm/vc4_drm.h
 F:     Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 
-DRM DRIVERS FOR TI OMAP
-M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
-L:     dri-devel@lists.freedesktop.org
-S:     Maintained
-F:     drivers/gpu/drm/omapdrm/
-F:     Documentation/devicetree/bindings/display/ti/
-
-DRM DRIVERS FOR TI LCDC
-M:     Jyri Sarha <jsarha@ti.com>
-R:     Tomi Valkeinen <tomi.valkeinen@ti.com>
+DRM DRIVERS FOR VIVANTE GPU IP
+M:     Lucas Stach <l.stach@pengutronix.de>
+R:     Russell King <linux+etnaviv@armlinux.org.uk>
+R:     Christian Gmeiner <christian.gmeiner@gmail.com>
+L:     etnaviv@lists.freedesktop.org
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
-F:     drivers/gpu/drm/tilcdc/
-F:     Documentation/devicetree/bindings/display/tilcdc/
+F:     drivers/gpu/drm/etnaviv/
+F:     include/uapi/drm/etnaviv_drm.h
+F:     Documentation/devicetree/bindings/display/etnaviv/
 
 DRM DRIVERS FOR ZTE ZX
 M:     Shawn Guo <shawnguo@kernel.org>
@@ -4662,6 +4612,16 @@ F:       drivers/gpu/drm/zte/
 F:     Documentation/devicetree/bindings/display/zte,vou.txt
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 
+DRM PANEL DRIVERS
+M:     Thierry Reding <thierry.reding@gmail.com>
+L:     dri-devel@lists.freedesktop.org
+T:     git git://anongit.freedesktop.org/tegra/linux.git
+S:     Maintained
+F:     drivers/gpu/drm/drm_panel.c
+F:     drivers/gpu/drm/panel/
+F:     include/drm/drm_panel.h
+F:     Documentation/devicetree/bindings/display/panel/
+
 DSBR100 USB FM RADIO DRIVER
 M:     Alexey Klimov <klimov.linux@gmail.com>
 L:     linux-media@vger.kernel.org
@@ -4793,13 +4753,6 @@ S:       Maintained
 F:     drivers/media/usb/dvb-usb-v2/dvb_usb*
 F:     drivers/media/usb/dvb-usb-v2/usb_urb.c
 
-DONGWOON DW9714 LENS VOICE COIL DRIVER
-M:     Sakari Ailus <sakari.ailus@linux.intel.com>
-L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
-F:     drivers/media/i2c/dw9714.c
-
 DYNAMIC DEBUG
 M:     Jason Baron <jbaron@akamai.com>
 S:     Maintained
@@ -4855,19 +4808,6 @@ S:       Supported
 F:     Documentation/filesystems/ecryptfs.txt
 F:     fs/ecryptfs/
 
-EDAC-CORE
-M:     Borislav Petkov <bp@alien8.de>
-M:     Mauro Carvalho Chehab <mchehab@s-opensource.com>
-M:     Mauro Carvalho Chehab <mchehab@kernel.org>
-L:     linux-edac@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git for-next
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git linux_next
-S:     Supported
-F:     Documentation/admin-guide/ras.rst
-F:     Documentation/driver-api/edac.rst
-F:     drivers/edac/
-F:     include/linux/edac.h
-
 EDAC-AMD64
 M:     Borislav Petkov <bp@alien8.de>
 L:     linux-edac@vger.kernel.org
@@ -4889,6 +4829,19 @@ S:       Supported
 F:     drivers/edac/octeon_edac*
 F:     drivers/edac/thunderx_edac*
 
+EDAC-CORE
+M:     Borislav Petkov <bp@alien8.de>
+M:     Mauro Carvalho Chehab <mchehab@s-opensource.com>
+M:     Mauro Carvalho Chehab <mchehab@kernel.org>
+L:     linux-edac@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git for-next
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git linux_next
+S:     Supported
+F:     Documentation/admin-guide/ras.rst
+F:     Documentation/driver-api/edac.rst
+F:     drivers/edac/
+F:     include/linux/edac.h
+
 EDAC-E752X
 M:     Mark Gross <mark.gross@intel.com>
 L:     linux-edac@vger.kernel.org
@@ -4913,12 +4866,6 @@ L:       linux-edac@vger.kernel.org
 S:     Maintained
 F:     drivers/edac/ghes_edac.c
 
-EDAC-I82443BXGX
-M:     Tim Small <tim@buttersideup.com>
-L:     linux-edac@vger.kernel.org
-S:     Maintained
-F:     drivers/edac/i82443bxgx_edac.c
-
 EDAC-I3000
 L:     linux-edac@vger.kernel.org
 S:     Orphan
@@ -4950,6 +4897,12 @@ L:       linux-edac@vger.kernel.org
 S:     Maintained
 F:     drivers/edac/i7core_edac.c
 
+EDAC-I82443BXGX
+M:     Tim Small <tim@buttersideup.com>
+L:     linux-edac@vger.kernel.org
+S:     Maintained
+F:     drivers/edac/i82443bxgx_edac.c
+
 EDAC-I82975X
 M:     Ranganathan Desikan <ravi@jetztechnologies.com>
 M:     "Arvind R." <arvino55@gmail.com>
@@ -4969,18 +4922,18 @@ L:      linux-edac@vger.kernel.org
 S:     Maintained
 F:     drivers/edac/mpc85xx_edac.[ch]
 
-EDAC-PND2
-M:     Tony Luck <tony.luck@intel.com>
-L:     linux-edac@vger.kernel.org
-S:     Maintained
-F:     drivers/edac/pnd2_edac.[ch]
-
 EDAC-PASEMI
 M:     Egor Martovetsky <egor@pasemi.com>
 L:     linux-edac@vger.kernel.org
 S:     Maintained
 F:     drivers/edac/pasemi_edac.c
 
+EDAC-PND2
+M:     Tony Luck <tony.luck@intel.com>
+L:     linux-edac@vger.kernel.org
+S:     Maintained
+F:     drivers/edac/pnd2_edac.[ch]
+
 EDAC-R82600
 M:     Tim Small <tim@buttersideup.com>
 L:     linux-edac@vger.kernel.org
@@ -5000,13 +4953,6 @@ L:       linux-edac@vger.kernel.org
 S:     Maintained
 F:     drivers/edac/skx_edac.c
 
-EDAC-XGENE
-APPLIED MICRO (APM) X-GENE SOC EDAC
-M:     Loc Ho <lho@apm.com>
-S:     Supported
-F:     drivers/edac/xgene_edac.c
-F:     Documentation/devicetree/bindings/edac/apm-xgene-edac.txt
-
 EDIROL UA-101/UA-1000 DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -5014,21 +4960,12 @@ T:      git git://git.alsa-project.org/alsa-kernel.git
 S:     Maintained
 F:     sound/usb/misc/ua101.c
 
-EXTENSIBLE FIRMWARE INTERFACE (EFI)
-M:     Matt Fleming <matt@codeblueprint.co.uk>
-M:     Ard Biesheuvel <ard.biesheuvel@linaro.org>
+EFI TEST DRIVER
 L:     linux-efi@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
+M:     Ivan Hu <ivan.hu@canonical.com>
+M:     Matt Fleming <matt@codeblueprint.co.uk>
 S:     Maintained
-F:     Documentation/efi-stub.txt
-F:     arch/*/kernel/efi.c
-F:     arch/x86/boot/compressed/eboot.[ch]
-F:     arch/*/include/asm/efi.h
-F:     arch/x86/platform/efi/
-F:     drivers/firmware/efi/
-F:     include/linux/efi*.h
-F:     arch/arm/boot/compressed/efi-header.S
-F:     arch/arm64/kernel/efi-entry.S
+F:     drivers/firmware/efi/test/
 
 EFI VARIABLE FILESYSTEM
 M:     Matthew Garrett <matthew.garrett@nebula.com>
@@ -5045,13 +4982,6 @@ M:       Peter Jones <pjones@redhat.com>
 S:     Maintained
 F:     drivers/video/fbdev/efifb.c
 
-EFI TEST DRIVER
-L:     linux-efi@vger.kernel.org
-M:     Ivan Hu <ivan.hu@canonical.com>
-M:     Matt Fleming <matt@codeblueprint.co.uk>
-S:     Maintained
-F:     drivers/firmware/efi/test/
-
 EFS FILESYSTEM
 W:     http://aeschi.ch.eu.org/efs/
 S:     Orphan
@@ -5080,6 +5010,34 @@ M:       David Woodhouse <dwmw2@infradead.org>
 L:     linux-embedded@vger.kernel.org
 S:     Maintained
 
+Emulex 10Gbps iSCSI - OneConnect DRIVER
+M:     Subbu Seetharaman <subbu.seetharaman@broadcom.com>
+M:     Ketan Mukadam <ketan.mukadam@broadcom.com>
+M:     Jitendra Bhivare <jitendra.bhivare@broadcom.com>
+L:     linux-scsi@vger.kernel.org
+W:     http://www.broadcom.com
+S:     Supported
+F:     drivers/scsi/be2iscsi/
+
+Emulex 10Gbps NIC BE2, BE3-R, Lancer, Skyhawk-R DRIVER (be2net)
+M:     Sathya Perla <sathya.perla@broadcom.com>
+M:     Ajit Khaparde <ajit.khaparde@broadcom.com>
+M:     Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
+M:     Somnath Kotur <somnath.kotur@broadcom.com>
+L:     netdev@vger.kernel.org
+W:     http://www.emulex.com
+S:     Supported
+F:     drivers/net/ethernet/emulex/benet/
+
+EMULEX ONECONNECT ROCE DRIVER
+M:     Selvin Xavier <selvin.xavier@broadcom.com>
+M:     Devesh Sharma <devesh.sharma@broadcom.com>
+L:     linux-rdma@vger.kernel.org
+W:     http://www.broadcom.com
+S:     Odd Fixes
+F:     drivers/infiniband/hw/ocrdma/
+F:     include/uapi/rdma/ocrdma-abi.h
+
 EMULEX/BROADCOM LPFC FC/FCOE SCSI DRIVER
 M:     James Smart <james.smart@broadcom.com>
 M:     Dick Kennedy <dick.kennedy@broadcom.com>
@@ -5132,12 +5090,21 @@ M:      Andrew Lunn <andrew@lunn.ch>
 M:     Florian Fainelli <f.fainelli@gmail.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     include/linux/phy.h
-F:     include/linux/phy_fixed.h
-F:     drivers/net/phy/
+F:     Documentation/ABI/testing/sysfs-bus-mdio
+F:     Documentation/devicetree/bindings/net/mdio*
 F:     Documentation/networking/phy.txt
+F:     drivers/net/phy/
 F:     drivers/of/of_mdio.c
 F:     drivers/of/of_net.c
+F:     include/linux/*mdio*.h
+F:     include/linux/of_net.h
+F:     include/linux/phy.h
+F:     include/linux/phy_fixed.h
+F:     include/linux/platform_data/mdio-gpio.h
+F:     include/linux/platform_data/mdio-bcm-unimac.h
+F:     include/trace/events/mdio.h
+F:     include/uapi/linux/mdio.h
+F:     include/uapi/linux/mii.h
 
 EXT2 FILE SYSTEM
 M:     Jan Kara <jack@suse.com>
@@ -5165,6 +5132,22 @@ L:       linux-security-module@vger.kernel.org
 S:     Supported
 F:     security/integrity/evm/
 
+EXTENSIBLE FIRMWARE INTERFACE (EFI)
+M:     Matt Fleming <matt@codeblueprint.co.uk>
+M:     Ard Biesheuvel <ard.biesheuvel@linaro.org>
+L:     linux-efi@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
+S:     Maintained
+F:     Documentation/efi-stub.txt
+F:     arch/*/kernel/efi.c
+F:     arch/x86/boot/compressed/eboot.[ch]
+F:     arch/*/include/asm/efi.h
+F:     arch/x86/platform/efi/
+F:     drivers/firmware/efi/
+F:     include/linux/efi*.h
+F:     arch/arm/boot/compressed/efi-header.S
+F:     arch/arm64/kernel/efi-entry.S
+
 EXTERNAL CONNECTOR SUBSYSTEM (EXTCON)
 M:     MyungJoo Ham <myungjoo.ham@samsung.com>
 M:     Chanwoo Choi <cw00.choi@samsung.com>
@@ -5195,6 +5178,19 @@ S:       Supported
 F:     arch/arc/plat-eznps
 F:     arch/arc/boot/dts/eznps.dts
 
+F2FS FILE SYSTEM
+M:     Jaegeuk Kim <jaegeuk@kernel.org>
+M:     Chao Yu <yuchao0@huawei.com>
+L:     linux-f2fs-devel@lists.sourceforge.net
+W:     https://f2fs.wiki.kernel.org/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
+S:     Maintained
+F:     Documentation/filesystems/f2fs.txt
+F:     Documentation/ABI/testing/sysfs-fs-f2fs
+F:     fs/f2fs/
+F:     include/linux/f2fs_fs.h
+F:     include/trace/events/f2fs.h
+
 F71805F HARDWARE MONITORING DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
 L:     linux-hwmon@vger.kernel.org
@@ -5202,23 +5198,6 @@ S:       Maintained
 F:     Documentation/hwmon/f71805f
 F:     drivers/hwmon/f71805f.c
 
-FC0011 TUNER DRIVER
-M:     Michael Buesch <m@bues.ch>
-L:     linux-media@vger.kernel.org
-S:     Maintained
-F:     drivers/media/tuners/fc0011.h
-F:     drivers/media/tuners/fc0011.c
-
-FC2580 MEDIA DRIVER
-M:     Antti Palosaari <crope@iki.fi>
-L:     linux-media@vger.kernel.org
-W:     https://linuxtv.org
-W:     http://palosaari.fi/linux/
-Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
-F:     drivers/media/tuners/fc2580*
-
 FANOTIFY
 M:     Eric Paris <eparis@redhat.com>
 S:     Maintained
@@ -5243,6 +5222,23 @@ M:       Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
 S:     Maintained
 F:     drivers/staging/fbtft/
 
+FC0011 TUNER DRIVER
+M:     Michael Buesch <m@bues.ch>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     drivers/media/tuners/fc0011.h
+F:     drivers/media/tuners/fc0011.c
+
+FC2580 MEDIA DRIVER
+M:     Antti Palosaari <crope@iki.fi>
+L:     linux-media@vger.kernel.org
+W:     https://linuxtv.org
+W:     http://palosaari.fi/linux/
+Q:     http://patchwork.linuxtv.org/project/linux-media/list/
+T:     git git://linuxtv.org/anttip/media_tree.git
+S:     Maintained
+F:     drivers/media/tuners/fc2580*
+
 FCOE SUBSYSTEM (libfc, libfcoe, fcoe)
 M:     Johannes Thumshirn <jth@kernel.org>
 L:     fcoe-devel@open-fcoe.org
@@ -5402,6 +5398,14 @@ L:       linuxppc-dev@lists.ozlabs.org
 S:     Maintained
 F:     drivers/dma/fsldma.*
 
+FREESCALE eTSEC ETHERNET DRIVER (GIANFAR)
+M:     Claudiu Manoil <claudiu.manoil@freescale.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ethernet/freescale/gianfar*
+X:     drivers/net/ethernet/freescale/gianfar_ptp.c
+F:     Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
+
 FREESCALE GPMI NAND DRIVER
 M:     Han Xu <han.xu@nxp.com>
 L:     linux-mtd@lists.infradead.org
@@ -5415,6 +5419,15 @@ L:       linux-i2c@vger.kernel.org
 S:     Maintained
 F:     drivers/i2c/busses/i2c-cpm.c
 
+FREESCALE IMX / MXC FEC DRIVER
+M:     Fugang Duan <fugang.duan@nxp.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ethernet/freescale/fec_main.c
+F:     drivers/net/ethernet/freescale/fec_ptp.c
+F:     drivers/net/ethernet/freescale/fec.h
+F:     Documentation/devicetree/bindings/net/fsl-fec.txt
+
 FREESCALE IMX / MXC FRAMEBUFFER DRIVER
 M:     Sascha Hauer <kernel@pengutronix.de>
 L:     linux-fbdev@vger.kernel.org
@@ -5423,29 +5436,11 @@ S:      Maintained
 F:     include/linux/platform_data/video-imxfb.h
 F:     drivers/video/fbdev/imxfb.c
 
-FREESCALE QUAD SPI DRIVER
-M:     Han Xu <han.xu@nxp.com>
-L:     linux-mtd@lists.infradead.org
-S:     Maintained
-F:     drivers/mtd/spi-nor/fsl-quadspi.c
-
-FREESCALE SOC FS_ENET DRIVER
-M:     Pantelis Antoniou <pantelis.antoniou@gmail.com>
-M:     Vitaly Bordug <vbordug@ru.mvista.com>
-L:     linuxppc-dev@lists.ozlabs.org
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/net/ethernet/freescale/fs_enet/
-F:     include/linux/fs_enet_pd.h
-
-FREESCALE IMX / MXC FEC DRIVER
-M:     Fugang Duan <fugang.duan@nxp.com>
+FREESCALE QORIQ DPAA ETHERNET DRIVER
+M:     Madalin Bucur <madalin.bucur@nxp.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/ethernet/freescale/fec_main.c
-F:     drivers/net/ethernet/freescale/fec_ptp.c
-F:     drivers/net/ethernet/freescale/fec.h
-F:     Documentation/devicetree/bindings/net/fsl-fec.txt
+F:     drivers/net/ethernet/freescale/dpaa
 
 FREESCALE QORIQ DPAA FMAN DRIVER
 M:     Madalin Bucur <madalin.bucur@nxp.com>
@@ -5454,20 +5449,11 @@ S:      Maintained
 F:     drivers/net/ethernet/freescale/fman
 F:     Documentation/devicetree/bindings/powerpc/fsl/fman.txt
 
-FREESCALE QORIQ DPAA ETHERNET DRIVER
-M:     Madalin Bucur <madalin.bucur@nxp.com>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/net/ethernet/freescale/dpaa
-
-FREESCALE SOC DRIVERS
-M:     Li Yang <leoyang.li@nxp.com>
-L:     linuxppc-dev@lists.ozlabs.org
-L:     linux-arm-kernel@lists.infradead.org
+FREESCALE QUAD SPI DRIVER
+M:     Han Xu <han.xu@nxp.com>
+L:     linux-mtd@lists.infradead.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/soc/fsl/
-F:     drivers/soc/fsl/
-F:     include/linux/fsl/
+F:     drivers/mtd/spi-nor/fsl-quadspi.c
 
 FREESCALE QUICC ENGINE LIBRARY
 M:     Qiang Zhao <qiang.zhao@nxp.com>
@@ -5477,13 +5463,6 @@ F:       drivers/soc/fsl/qe/
 F:     include/soc/fsl/*qe*.h
 F:     include/soc/fsl/*ucc*.h
 
-FREESCALE USB PERIPHERAL DRIVERS
-M:     Li Yang <leoyang.li@nxp.com>
-L:     linux-usb@vger.kernel.org
-L:     linuxppc-dev@lists.ozlabs.org
-S:     Maintained
-F:     drivers/usb/gadget/udc/fsl*
-
 FREESCALE QUICC ENGINE UCC ETHERNET DRIVER
 M:     Li Yang <leoyang.li@nxp.com>
 L:     netdev@vger.kernel.org
@@ -5491,14 +5470,6 @@ L:       linuxppc-dev@lists.ozlabs.org
 S:     Maintained
 F:     drivers/net/ethernet/freescale/ucc_geth*
 
-FREESCALE eTSEC ETHERNET DRIVER (GIANFAR)
-M:     Claudiu Manoil <claudiu.manoil@freescale.com>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/net/ethernet/freescale/gianfar*
-X:     drivers/net/ethernet/freescale/gianfar_ptp.c
-F:     Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
-
 FREESCALE QUICC ENGINE UCC HDLC DRIVER
 M:     Zhao Qiang <qiang.zhao@nxp.com>
 L:     netdev@vger.kernel.org
@@ -5512,6 +5483,24 @@ L:       linuxppc-dev@lists.ozlabs.org
 S:     Maintained
 F:     drivers/tty/serial/ucc_uart.c
 
+FREESCALE SOC DRIVERS
+M:     Li Yang <leoyang.li@nxp.com>
+L:     linuxppc-dev@lists.ozlabs.org
+L:     linux-arm-kernel@lists.infradead.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/soc/fsl/
+F:     drivers/soc/fsl/
+F:     include/linux/fsl/
+
+FREESCALE SOC FS_ENET DRIVER
+M:     Pantelis Antoniou <pantelis.antoniou@gmail.com>
+M:     Vitaly Bordug <vbordug@ru.mvista.com>
+L:     linuxppc-dev@lists.ozlabs.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ethernet/freescale/fs_enet/
+F:     include/linux/fs_enet_pd.h
+
 FREESCALE SOC SOUND DRIVERS
 M:     Timur Tabi <timur@tabi.org>
 M:     Nicolin Chen <nicoleotsuka@gmail.com>
@@ -5524,6 +5513,13 @@ F:       sound/soc/fsl/fsl*
 F:     sound/soc/fsl/imx*
 F:     sound/soc/fsl/mpc8610_hpcd.c
 
+FREESCALE USB PERIPHERAL DRIVERS
+M:     Li Yang <leoyang.li@nxp.com>
+L:     linux-usb@vger.kernel.org
+L:     linuxppc-dev@lists.ozlabs.org
+S:     Maintained
+F:     drivers/usb/gadget/udc/fsl*
+
 FREEVXFS FILESYSTEM
 M:     Christoph Hellwig <hch@infradead.org>
 W:     ftp://ftp.openlinux.org/pub/people/hch/vxfs
@@ -5564,19 +5560,6 @@ S:       Supported
 F:     fs/crypto/
 F:     include/linux/fscrypt*.h
 
-F2FS FILE SYSTEM
-M:     Jaegeuk Kim <jaegeuk@kernel.org>
-M:     Chao Yu <yuchao0@huawei.com>
-L:     linux-f2fs-devel@lists.sourceforge.net
-W:     https://f2fs.wiki.kernel.org/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
-S:     Maintained
-F:     Documentation/filesystems/f2fs.txt
-F:     Documentation/ABI/testing/sysfs-fs-f2fs
-F:     fs/f2fs/
-F:     include/linux/f2fs_fs.h
-F:     include/trace/events/f2fs.h
-
 FUJITSU FR-V (FRV) PORT
 S:     Orphan
 F:     arch/frv/
@@ -5650,6 +5633,12 @@ S:       Maintained
 F:     kernel/gcov/
 F:     Documentation/dev-tools/gcov.rst
 
+GDB KERNEL DEBUGGING HELPER SCRIPTS
+M:     Jan Kiszka <jan.kiszka@siemens.com>
+M:     Kieran Bingham <kieran@bingham.xyz>
+S:     Supported
+F:     scripts/gdb/
+
 GDT SCSI DISK ARRAY CONTROLLER DRIVER
 M:     Achim Leubner <achim_leubner@adaptec.com>
 L:     linux-scsi@vger.kernel.org
@@ -5657,12 +5646,6 @@ W:       http://www.icp-vortex.com/
 S:     Supported
 F:     drivers/scsi/gdt*
 
-GDB KERNEL DEBUGGING HELPER SCRIPTS
-M:     Jan Kiszka <jan.kiszka@siemens.com>
-M:     Kieran Bingham <kieran@bingham.xyz>
-S:     Supported
-F:     scripts/gdb/
-
 GEMTEK FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
@@ -5729,17 +5712,17 @@ L:      kvm@vger.kernel.org
 S:     Supported
 F:     drivers/uio/uio_pci_generic.c
 
-GET_MAINTAINER SCRIPT
-M:     Joe Perches <joe@perches.com>
-S:     Maintained
-F:     scripts/get_maintainer.pl
-
 GENWQE (IBM Generic Workqueue Card)
 M:     Frank Haverkamp <haver@linux.vnet.ibm.com>
 M:     Guilherme G. Piccoli <gpiccoli@linux.vnet.ibm.com>
 S:     Supported
 F:     drivers/misc/genwqe/
 
+GET_MAINTAINER SCRIPT
+M:     Joe Perches <joe@perches.com>
+S:     Maintained
+F:     scripts/get_maintainer.pl
+
 GFS2 FILE SYSTEM
 M:     Steven Whitehouse <swhiteho@redhat.com>
 M:     Bob Peterson <rpeterso@redhat.com>
@@ -5772,6 +5755,15 @@ L:       linux-input@vger.kernel.org
 S:     Maintained
 F:     drivers/input/touchscreen/goodix.c
 
+GPIO ACPI SUPPORT
+M:     Mika Westerberg <mika.westerberg@linux.intel.com>
+M:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+L:     linux-gpio@vger.kernel.org
+L:     linux-acpi@vger.kernel.org
+S:     Maintained
+F:     Documentation/acpi/gpio-properties.txt
+F:     drivers/gpio/gpiolib-acpi.c
+
 GPIO MOCKUP DRIVER
 M:     Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
 L:     linux-gpio@vger.kernel.org
@@ -5795,15 +5787,6 @@ F:       include/asm-generic/gpio.h
 F:     include/uapi/linux/gpio.h
 F:     tools/gpio/
 
-GPIO ACPI SUPPORT
-M:     Mika Westerberg <mika.westerberg@linux.intel.com>
-M:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
-L:     linux-gpio@vger.kernel.org
-L:     linux-acpi@vger.kernel.org
-S:     Maintained
-F:     Documentation/acpi/gpio-properties.txt
-F:     drivers/gpio/gpiolib-acpi.c
-
 GRE DEMULTIPLEXER DRIVER
 M:     Dmitry Kozlov <xeb@mail.ru>
 L:     netdev@vger.kernel.org
@@ -5818,14 +5801,6 @@ L:       netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/aeroflex/
 
-GREYBUS SUBSYSTEM
-M:     Johan Hovold <johan@kernel.org>
-M:     Alex Elder <elder@kernel.org>
-M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-S:     Maintained
-F:     drivers/staging/greybus/
-L:     greybus-dev@lists.linaro.org (moderated for non-subscribers)
-
 GREYBUS AUDIO PROTOCOLS DRIVERS
 M:     Vaibhav Agarwal <vaibhav.sr@gmail.com>
 M:     Mark Greer <mgreer@animalcreek.com>
@@ -5843,24 +5818,7 @@ F:       drivers/staging/greybus/audio_manager_sysfs.c
 F:     drivers/staging/greybus/audio_module.c
 F:     drivers/staging/greybus/audio_topology.c
 
-GREYBUS PROTOCOLS DRIVERS
-M:     Rui Miguel Silva <rmfrfs@gmail.com>
-S:     Maintained
-F:     drivers/staging/greybus/sdio.c
-F:     drivers/staging/greybus/light.c
-F:     drivers/staging/greybus/gpio.c
-F:     drivers/staging/greybus/power_supply.c
-F:     drivers/staging/greybus/spi.c
-F:     drivers/staging/greybus/spilib.c
-
-GREYBUS PROTOCOLS DRIVERS
-M:     Bryan O'Donoghue <pure.logic@nexus-software.ie>
-S:     Maintained
-F:     drivers/staging/greybus/loopback.c
-F:     drivers/staging/greybus/timesync.c
-F:     drivers/staging/greybus/timesync_platform.c
-
-GREYBUS PROTOCOLS DRIVERS
+GREYBUS FW/HID/SPI PROTOCOLS DRIVERS
 M:     Viresh Kumar <vireshk@kernel.org>
 S:     Maintained
 F:     drivers/staging/greybus/authentication.c
@@ -5877,11 +5835,12 @@ F:      drivers/staging/greybus/spi.c
 F:     drivers/staging/greybus/spilib.c
 F:     drivers/staging/greybus/spilib.h
 
-GREYBUS PROTOCOLS DRIVERS
-M:     David Lin <dtwlin@gmail.com>
+GREYBUS LOOBACK/TIME PROTOCOLS DRIVERS
+M:     Bryan O'Donoghue <pure.logic@nexus-software.ie>
 S:     Maintained
-F:     drivers/staging/greybus/uart.c
-F:     drivers/staging/greybus/log.c
+F:     drivers/staging/greybus/loopback.c
+F:     drivers/staging/greybus/timesync.c
+F:     drivers/staging/greybus/timesync_platform.c
 
 GREYBUS PLATFORM DRIVERS
 M:     Vaibhav Hiremath <hvaibhav.linux@gmail.com>
@@ -5890,6 +5849,30 @@ F:       drivers/staging/greybus/arche-platform.c
 F:     drivers/staging/greybus/arche-apb-ctrl.c
 F:     drivers/staging/greybus/arche_platform.h
 
+GREYBUS SDIO/GPIO/SPI PROTOCOLS DRIVERS
+M:     Rui Miguel Silva <rmfrfs@gmail.com>
+S:     Maintained
+F:     drivers/staging/greybus/sdio.c
+F:     drivers/staging/greybus/light.c
+F:     drivers/staging/greybus/gpio.c
+F:     drivers/staging/greybus/power_supply.c
+F:     drivers/staging/greybus/spi.c
+F:     drivers/staging/greybus/spilib.c
+
+GREYBUS SUBSYSTEM
+M:     Johan Hovold <johan@kernel.org>
+M:     Alex Elder <elder@kernel.org>
+M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+S:     Maintained
+F:     drivers/staging/greybus/
+L:     greybus-dev@lists.linaro.org (moderated for non-subscribers)
+
+GREYBUS UART PROTOCOLS DRIVERS
+M:     David Lin <dtwlin@gmail.com>
+S:     Maintained
+F:     drivers/staging/greybus/uart.c
+F:     drivers/staging/greybus/log.c
+
 GS1662 VIDEO SERIALIZER
 M:     Charles-Antoine Couret <charles-antoine.couret@nexvision.fr>
 L:     linux-media@vger.kernel.org
@@ -5960,13 +5943,6 @@ L:       linux-efi@vger.kernel.org
 S:     Maintained
 F:     block/partitions/efi.*
 
-STK1160 USB VIDEO CAPTURE DRIVER
-M:     Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
-L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
-F:     drivers/media/usb/stk1160/
-
 H8/300 ARCHITECTURE
 M:     Yoshinori Sato <ysato@users.sourceforge.jp>
 L:     uclinux-h8-devel@lists.sourceforge.jp (moderated for non-subscribers)
@@ -5978,33 +5954,6 @@ F:       drivers/clocksource/h8300_*.c
 F:     drivers/clk/h8300/
 F:     drivers/irqchip/irq-renesas-h8*.c
 
-HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
-M:     Frank Seidel <frank@f-seidel.de>
-L:     platform-driver-x86@vger.kernel.org
-W:     http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
-S:     Maintained
-F:     drivers/platform/x86/hdaps.c
-
-HDPVR USB VIDEO ENCODER DRIVER
-M:     Hans Verkuil <hverkuil@xs4all.nl>
-L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
-S:     Odd Fixes
-F:     drivers/media/usb/hdpvr/
-
-HWPOISON MEMORY FAILURE HANDLING
-M:     Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
-L:     linux-mm@kvack.org
-S:     Maintained
-F:     mm/memory-failure.c
-F:     mm/hwpoison-inject.c
-
-HYPERVISOR VIRTUAL CONSOLE DRIVER
-L:     linuxppc-dev@lists.ozlabs.org
-S:     Odd Fixes
-F:     drivers/tty/hvc/
-
 HACKRF MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
@@ -6015,6 +5964,13 @@ T:       git git://linuxtv.org/anttip/media_tree.git
 S:     Maintained
 F:     drivers/media/usb/hackrf/
 
+HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
+M:     Frank Seidel <frank@f-seidel.de>
+L:     platform-driver-x86@vger.kernel.org
+W:     http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
+S:     Maintained
+F:     drivers/platform/x86/hdaps.c
+
 HARDWARE MONITORING
 M:     Jean Delvare <jdelvare@suse.com>
 M:     Guenter Roeck <linux@roeck-us.net>
@@ -6053,6 +6009,14 @@ L:       linux-parisc@vger.kernel.org
 S:     Maintained
 F:     sound/parisc/harmony.*
 
+HDPVR USB VIDEO ENCODER DRIVER
+M:     Hans Verkuil <hverkuil@xs4all.nl>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+W:     https://linuxtv.org
+S:     Odd Fixes
+F:     drivers/media/usb/hdpvr/
+
 HEWLETT PACKARD ENTERPRISE ILO NMI WATCHDOG DRIVER
 M:     Jimmy Vance <jimmy.vance@hpe.com>
 S:     Supported
@@ -6079,13 +6043,6 @@ F:       drivers/block/cciss*
 F:     include/linux/cciss_ioctl.h
 F:     include/uapi/linux/cciss_ioctl.h
 
-OPA-VNIC DRIVER
-M:     Dennis Dalessandro <dennis.dalessandro@intel.com>
-M:     Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
-L:     linux-rdma@vger.kernel.org
-S:     Supported
-F:     drivers/infiniband/ulp/opa_vnic
-
 HFI1 DRIVER
 M:     Mike Marciniszyn <mike.marciniszyn@intel.com>
 M:     Dennis Dalessandro <dennis.dalessandro@intel.com>
@@ -6263,6 +6220,12 @@ L:       netdev@vger.kernel.org
 S:     Maintained
 F:     net/hsr/
 
+HT16K33 LED CONTROLLER DRIVER
+M:     Robin van der Gracht <robin@protonic.nl>
+S:     Maintained
+F:     drivers/auxdisplay/ht16k33.c
+F:     Documentation/devicetree/bindings/display/ht16k33.txt
+
 HTCPEN TOUCHSCREEN DRIVER
 M:     Pau Oliva Fora <pof@eslack.org>
 L:     linux-input@vger.kernel.org
@@ -6282,6 +6245,13 @@ W:       https://linuxtv.org
 S:     Supported
 F:     drivers/media/platform/sti/hva
 
+HWPOISON MEMORY FAILURE HANDLING
+M:     Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
+L:     linux-mm@kvack.org
+S:     Maintained
+F:     mm/memory-failure.c
+F:     mm/hwpoison-inject.c
+
 Hyper-V CORE AND DRIVERS
 M:     "K. Y. Srinivasan" <kys@microsoft.com>
 M:     Haiyang Zhang <haiyangz@microsoft.com>
@@ -6304,6 +6274,18 @@ F:       include/linux/hyperv.h
 F:     tools/hv/
 F:     Documentation/ABI/stable/sysfs-bus-vmbus
 
+HYPERVISOR VIRTUAL CONSOLE DRIVER
+L:     linuxppc-dev@lists.ozlabs.org
+S:     Odd Fixes
+F:     drivers/tty/hvc/
+
+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-core-acpi.c
+
 I2C MUXES
 M:     Peter Rosin <peda@axentia.se>
 L:     linux-i2c@vger.kernel.org
@@ -6326,6 +6308,36 @@ F:       Documentation/i2c/busses/i2c-parport-light
 F:     drivers/i2c/busses/i2c-parport.c
 F:     drivers/i2c/busses/i2c-parport-light.c
 
+I2C SUBSYSTEM
+M:     Wolfram Sang <wsa@the-dreams.de>
+L:     linux-i2c@vger.kernel.org
+W:     https://i2c.wiki.kernel.org/
+Q:     https://patchwork.ozlabs.org/project/linux-i2c/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
+S:     Maintained
+F:     Documentation/devicetree/bindings/i2c/
+F:     Documentation/i2c/
+F:     drivers/i2c/
+F:     drivers/i2c/*/
+F:     include/linux/i2c.h
+F:     include/linux/i2c-*.h
+F:     include/uapi/linux/i2c.h
+F:     include/uapi/linux/i2c-*.h
+
+I2C-TAOS-EVM DRIVER
+M:     Jean Delvare <jdelvare@suse.com>
+L:     linux-i2c@vger.kernel.org
+S:     Maintained
+F:     Documentation/i2c/busses/i2c-taos-evm
+F:     drivers/i2c/busses/i2c-taos-evm.c
+
+I2C-TINY-USB DRIVER
+M:     Till Harbaum <till@harbaum.org>
+L:     linux-i2c@vger.kernel.org
+W:     http://www.harbaum.org/till/i2c_tiny_usb
+S:     Maintained
+F:     drivers/i2c/busses/i2c-tiny-usb.c
+
 I2C/SMBUS CONTROLLER DRIVERS FOR PC
 M:     Jean Delvare <jdelvare@suse.com>
 L:     linux-i2c@vger.kernel.org
@@ -6373,43 +6385,6 @@ L:       linux-i2c@vger.kernel.org
 S:     Maintained
 F:     drivers/i2c/i2c-stub.c
 
-I2C SUBSYSTEM
-M:     Wolfram Sang <wsa@the-dreams.de>
-L:     linux-i2c@vger.kernel.org
-W:     https://i2c.wiki.kernel.org/
-Q:     https://patchwork.ozlabs.org/project/linux-i2c/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
-S:     Maintained
-F:     Documentation/devicetree/bindings/i2c/
-F:     Documentation/i2c/
-F:     drivers/i2c/
-F:     drivers/i2c/*/
-F:     include/linux/i2c.h
-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-core-acpi.c
-
-I2C-TAOS-EVM DRIVER
-M:     Jean Delvare <jdelvare@suse.com>
-L:     linux-i2c@vger.kernel.org
-S:     Maintained
-F:     Documentation/i2c/busses/i2c-taos-evm
-F:     drivers/i2c/busses/i2c-taos-evm.c
-
-I2C-TINY-USB DRIVER
-M:     Till Harbaum <till@harbaum.org>
-L:     linux-i2c@vger.kernel.org
-W:     http://www.harbaum.org/till/i2c_tiny_usb
-S:     Maintained
-F:     drivers/i2c/busses/i2c-tiny-usb.c
-
 i386 BOOT CODE
 M:     "H. Peter Anvin" <hpa@zytor.com>
 S:     Maintained
@@ -6428,17 +6403,15 @@ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git
 S:     Maintained
 F:     arch/ia64/
 
-IBM Power VMX Cryptographic instructions
-M:     Leonidas S. Barbosa <leosilva@linux.vnet.ibm.com>
-M:     Paulo Flabiano Smorigo <pfsmorigo@linux.vnet.ibm.com>
-L:     linux-crypto@vger.kernel.org
+IBM Power 842 compression accelerator
+M:     Haren Myneni <haren@us.ibm.com>
 S:     Supported
-F:     drivers/crypto/vmx/Makefile
-F:     drivers/crypto/vmx/Kconfig
-F:     drivers/crypto/vmx/vmx.c
-F:     drivers/crypto/vmx/aes*
-F:     drivers/crypto/vmx/ghash*
-F:     drivers/crypto/vmx/ppc-xlate.pl
+F:     drivers/crypto/nx/Makefile
+F:     drivers/crypto/nx/Kconfig
+F:     drivers/crypto/nx/nx-842*
+F:     include/linux/sw842.h
+F:     crypto/842.c
+F:     lib/842/
 
 IBM Power in-Nest Crypto Acceleration
 M:     Leonidas S. Barbosa <leosilva@linux.vnet.ibm.com>
@@ -6453,33 +6426,29 @@ F:      drivers/crypto/nx/nx.*
 F:     drivers/crypto/nx/nx_csbcpb.h
 F:     drivers/crypto/nx/nx_debugfs.h
 
-IBM Power 842 compression accelerator
-M:     Haren Myneni <haren@us.ibm.com>
-S:     Supported
-F:     drivers/crypto/nx/Makefile
-F:     drivers/crypto/nx/Kconfig
-F:     drivers/crypto/nx/nx-842*
-F:     include/linux/sw842.h
-F:     crypto/842.c
-F:     lib/842/
-
 IBM Power Linux RAID adapter
 M:     Brian King <brking@us.ibm.com>
 S:     Supported
 F:     drivers/scsi/ipr.*
 
-IBM Power Virtual Ethernet Device Driver
+IBM Power SRIOV Virtual NIC Device Driver
 M:     Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
+M:     John Allen <jallen@linux.vnet.ibm.com>
 L:     netdev@vger.kernel.org
 S:     Supported
-F:     drivers/net/ethernet/ibm/ibmveth.*
+F:     drivers/net/ethernet/ibm/ibmvnic.*
 
-IBM Power SRIOV Virtual NIC Device Driver
+IBM Power Virtual Ethernet Device Driver
 M:     Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
-M:     John Allen <jallen@linux.vnet.ibm.com>
 L:     netdev@vger.kernel.org
 S:     Supported
-F:     drivers/net/ethernet/ibm/ibmvnic.*
+F:     drivers/net/ethernet/ibm/ibmveth.*
+
+IBM Power Virtual FC Device Drivers
+M:     Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+F:     drivers/scsi/ibmvscsi/ibmvfc*
 
 IBM Power Virtual SCSI Device Drivers
 M:     Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
@@ -6496,11 +6465,17 @@ L:      target-devel@vger.kernel.org
 S:     Supported
 F:     drivers/scsi/ibmvscsi_tgt/
 
-IBM Power Virtual FC Device Drivers
-M:     Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
-L:     linux-scsi@vger.kernel.org
+IBM Power VMX Cryptographic instructions
+M:     Leonidas S. Barbosa <leosilva@linux.vnet.ibm.com>
+M:     Paulo Flabiano Smorigo <pfsmorigo@linux.vnet.ibm.com>
+L:     linux-crypto@vger.kernel.org
 S:     Supported
-F:     drivers/scsi/ibmvscsi/ibmvfc*
+F:     drivers/crypto/vmx/Makefile
+F:     drivers/crypto/vmx/Kconfig
+F:     drivers/crypto/vmx/vmx.c
+F:     drivers/crypto/vmx/aes*
+F:     drivers/crypto/vmx/ghash*
+F:     drivers/crypto/vmx/ppc-xlate.pl
 
 IBM ServeRAID RAID DRIVER
 S:     Orphan
@@ -6512,11 +6487,6 @@ S:       Maintained
 F:     drivers/mfd/lpc_ich.c
 F:     drivers/gpio/gpio-ich.c
 
-IDT VersaClock 5 CLOCK DRIVER
-M:     Marek Vasut <marek.vasut@gmail.com>
-S:     Maintained
-F:     drivers/clk/clk-versaclock5.c
-
 IDE SUBSYSTEM
 M:     "David S. Miller" <davem@davemloft.net>
 L:     linux-ide@vger.kernel.org
@@ -6527,6 +6497,13 @@ F:       Documentation/ide/
 F:     drivers/ide/
 F:     include/linux/ide.h
 
+IDE/ATAPI DRIVERS
+M:     Borislav Petkov <bp@alien8.de>
+L:     linux-ide@vger.kernel.org
+S:     Maintained
+F:     Documentation/cdrom/ide-cd
+F:     drivers/ide/ide-cd*
+
 IDEAPAD LAPTOP EXTRAS DRIVER
 M:     Ike Panhc <ike.pan@canonical.com>
 L:     platform-driver-x86@vger.kernel.org
@@ -6541,12 +6518,10 @@ W:      https://github.com/o2genum/ideapad-slidebar
 S:     Maintained
 F:     drivers/input/misc/ideapad_slidebar.c
 
-IDE/ATAPI DRIVERS
-M:     Borislav Petkov <bp@alien8.de>
-L:     linux-ide@vger.kernel.org
+IDT VersaClock 5 CLOCK DRIVER
+M:     Marek Vasut <marek.vasut@gmail.com>
 S:     Maintained
-F:     Documentation/cdrom/ide-cd
-F:     drivers/ide/ide-cd*
+F:     drivers/clk/clk-versaclock5.c
 
 IEEE 802.15.4 SUBSYSTEM
 M:     Alexander Aring <alex.aring@gmail.com>
@@ -6636,6 +6611,16 @@ S:       Maintained
 F:     Documentation/devicetree/bindings/auxdisplay/img-ascii-lcd.txt
 F:     drivers/auxdisplay/img-ascii-lcd.c
 
+IMGTEC IR DECODER DRIVER
+M:     James Hogan <james.hogan@imgtec.com>
+S:     Maintained
+F:     drivers/media/rc/img-ir/
+
+IMS TWINTURBO FRAMEBUFFER DRIVER
+L:     linux-fbdev@vger.kernel.org
+S:     Orphan
+F:     drivers/video/fbdev/imsttfb.c
+
 INA209 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     linux-hwmon@vger.kernel.org
@@ -6661,37 +6646,6 @@ W:       http://industrypack.sourceforge.net
 S:     Maintained
 F:     drivers/ipack/
 
-INGENIC JZ4780 DMA Driver
-M:     Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
-S:     Maintained
-F:     drivers/dma/dma-jz4780.c
-
-INGENIC JZ4780 NAND DRIVER
-M:     Harvey Hunt <harveyhuntnexus@gmail.com>
-L:     linux-mtd@lists.infradead.org
-S:     Maintained
-F:     drivers/mtd/nand/jz4780_*
-
-INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
-M:     Mimi Zohar <zohar@linux.vnet.ibm.com>
-M:     Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
-L:     linux-ima-devel@lists.sourceforge.net
-L:     linux-ima-user@lists.sourceforge.net
-L:     linux-security-module@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
-S:     Supported
-F:     security/integrity/ima/
-
-IMGTEC IR DECODER DRIVER
-M:     James Hogan <james.hogan@imgtec.com>
-S:     Maintained
-F:     drivers/media/rc/img-ir/
-
-IMS TWINTURBO FRAMEBUFFER DRIVER
-L:     linux-fbdev@vger.kernel.org
-S:     Orphan
-F:     drivers/video/fbdev/imsttfb.c
-
 INFINIBAND SUBSYSTEM
 M:     Doug Ledford <dledford@redhat.com>
 M:     Sean Hefty <sean.hefty@intel.com>
@@ -6708,6 +6662,17 @@ F:       include/uapi/linux/if_infiniband.h
 F:     include/uapi/rdma/
 F:     include/rdma/
 
+INGENIC JZ4780 DMA Driver
+M:     Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
+S:     Maintained
+F:     drivers/dma/dma-jz4780.c
+
+INGENIC JZ4780 NAND DRIVER
+M:     Harvey Hunt <harveyhuntnexus@gmail.com>
+L:     linux-mtd@lists.infradead.org
+S:     Maintained
+F:     drivers/mtd/nand/jz4780_*
+
 INOTIFY
 M:     John McCutchan <john@johnmccutchan.com>
 M:     Robert Love <rlove@rlove.org>
@@ -6746,6 +6711,22 @@ F:       drivers/crypto/inside-secure/
 S:     Maintained
 L:     linux-crypto@vger.kernel.org
 
+INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
+M:     Mimi Zohar <zohar@linux.vnet.ibm.com>
+M:     Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
+L:     linux-ima-devel@lists.sourceforge.net
+L:     linux-ima-user@lists.sourceforge.net
+L:     linux-security-module@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
+S:     Supported
+F:     security/integrity/ima/
+
+INTEL 810/815 FRAMEBUFFER DRIVER
+M:     Antonino Daplas <adaplas@gmail.com>
+L:     linux-fbdev@vger.kernel.org
+S:     Maintained
+F:     drivers/video/fbdev/i810/
+
 INTEL ASoC BDW/HSW DRIVERS
 M:     Jie Yang <yang.jie@linux.intel.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -6763,96 +6744,20 @@ T:      git git://git.code.sf.net/p/intel-sas/isci
 S:     Supported
 F:     drivers/scsi/isci/
 
-INTEL HID EVENT DRIVER
-M:     Alex Hung <alex.hung@canonical.com>
-L:     platform-driver-x86@vger.kernel.org
-S:     Maintained
-F:     drivers/platform/x86/intel-hid.c
-
-INTEL VIRTUAL BUTTON DRIVER
-M:     AceLan Kao <acelan.kao@canonical.com>
-L:     platform-driver-x86@vger.kernel.org
-S:     Maintained
-F:     drivers/platform/x86/intel-vbtn.c
-
-INTEL IDLE DRIVER
-M:     Jacob Pan <jacob.jun.pan@linux.intel.com>
-M:     Len Brown <lenb@kernel.org>
-L:     linux-pm@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git
-B:     https://bugzilla.kernel.org
-S:     Supported
-F:     drivers/idle/intel_idle.c
-
-INTEL INTEGRATED SENSOR HUB DRIVER
-M:     Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
-M:     Jiri Kosina <jikos@kernel.org>
-L:     linux-input@vger.kernel.org
-S:     Maintained
-F:     drivers/hid/intel-ish-hid/
-
-INTEL PSTATE DRIVER
-M:     Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
-M:     Len Brown <lenb@kernel.org>
-L:     linux-pm@vger.kernel.org
-S:     Supported
-F:     drivers/cpufreq/intel_pstate.c
-
-INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
-M:     Maik Broemme <mbroemme@libmpq.org>
-L:     linux-fbdev@vger.kernel.org
-S:     Maintained
-F:     Documentation/fb/intelfb.txt
-F:     drivers/video/fbdev/intelfb/
-
-INTEL 810/815 FRAMEBUFFER DRIVER
-M:     Antonino Daplas <adaplas@gmail.com>
-L:     linux-fbdev@vger.kernel.org
-S:     Maintained
-F:     drivers/video/fbdev/i810/
-
-INTEL MENLOW THERMAL DRIVER
-M:     Sujith Thomas <sujith.thomas@intel.com>
-L:     platform-driver-x86@vger.kernel.org
-W:     https://01.org/linux-acpi
-S:     Supported
-F:     drivers/platform/x86/intel_menlow.c
-
-INTEL I/OAT DMA DRIVER
-M:     Dave Jiang <dave.jiang@intel.com>
-R:     Dan Williams <dan.j.williams@intel.com>
-L:     dmaengine@vger.kernel.org
-Q:     https://patchwork.kernel.org/project/linux-dmaengine/list/
-S:     Supported
-F:     drivers/dma/ioat*
-
-INTEL IOMMU (VT-d)
-M:     David Woodhouse <dwmw2@infradead.org>
-L:     iommu@lists.linux-foundation.org
-T:     git git://git.infradead.org/iommu-2.6.git
+INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
+M:     Daniel Vetter <daniel.vetter@intel.com>
+M:     Jani Nikula <jani.nikula@linux.intel.com>
+L:     intel-gfx@lists.freedesktop.org
+W:     https://01.org/linuxgraphics/
+B:     https://01.org/linuxgraphics/documentation/how-report-bugs
+C:     irc://chat.freenode.net/intel-gfx
+Q:     http://patchwork.freedesktop.org/project/intel-gfx/
+T:     git git://anongit.freedesktop.org/drm-intel
 S:     Supported
-F:     drivers/iommu/intel-iommu.c
-F:     include/linux/intel-iommu.h
-
-INTEL IOP-ADMA DMA DRIVER
-R:     Dan Williams <dan.j.williams@intel.com>
-S:     Odd fixes
-F:     drivers/dma/iop-adma.c
-
-INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
-M:     Krzysztof Halasa <khalasa@piap.pl>
-S:     Maintained
-F:     arch/arm/mach-ixp4xx/include/mach/qmgr.h
-F:     arch/arm/mach-ixp4xx/include/mach/npe.h
-F:     arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
-F:     arch/arm/mach-ixp4xx/ixp4xx_npe.c
-F:     drivers/net/ethernet/xscale/ixp4xx_eth.c
-F:     drivers/net/wan/ixp4xx_hss.c
-
-INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT
-M:     Deepak Saxena <dsaxena@plexity.net>
-S:     Maintained
-F:     drivers/char/hw_random/ixp4xx-rng.c
+F:     drivers/gpu/drm/i915/
+F:     include/drm/i915*
+F:     include/uapi/drm/i915_drm.h
+F:     Documentation/gpu/i915.rst
 
 INTEL ETHERNET DRIVERS
 M:     Jeff Kirsher <jeffrey.t.kirsher@intel.com>
@@ -6877,75 +6782,80 @@ F:      drivers/net/ethernet/intel/
 F:     drivers/net/ethernet/intel/*/
 F:     include/linux/avf/virtchnl.h
 
-INTEL RDMA RNIC DRIVER
-M:     Faisal Latif <faisal.latif@intel.com>
-M:     Shiraz Saleem <shiraz.saleem@intel.com>
-L:     linux-rdma@vger.kernel.org
-S:     Supported
-F:     drivers/infiniband/hw/i40iw/
-
-INTEL MERRIFIELD GPIO DRIVER
-M:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
-L:     linux-gpio@vger.kernel.org
+INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
+M:     Maik Broemme <mbroemme@libmpq.org>
+L:     linux-fbdev@vger.kernel.org
 S:     Maintained
-F:     drivers/gpio/gpio-merrifield.c
+F:     Documentation/fb/intelfb.txt
+F:     drivers/video/fbdev/intelfb/
 
-INTEL-MID GPIO DRIVER
-M:     David Cohen <david.a.cohen@linux.intel.com>
-L:     linux-gpio@vger.kernel.org
-S:     Maintained
-F:     drivers/gpio/gpio-intel-mid.c
+INTEL GVT-g DRIVERS (Intel GPU Virtualization)
+M:     Zhenyu Wang <zhenyuw@linux.intel.com>
+M:     Zhi Wang <zhi.a.wang@intel.com>
+L:     intel-gvt-dev@lists.freedesktop.org
+L:     intel-gfx@lists.freedesktop.org
+W:     https://01.org/igvt-g
+T:     git https://github.com/01org/gvt-linux.git
+S:     Supported
+F:     drivers/gpu/drm/i915/gvt/
 
-INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
-M:     Stanislav Yakovlev <stas.yakovlev@gmail.com>
-L:     linux-wireless@vger.kernel.org
+INTEL HID EVENT DRIVER
+M:     Alex Hung <alex.hung@canonical.com>
+L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
-F:     Documentation/networking/README.ipw2100
-F:     Documentation/networking/README.ipw2200
-F:     drivers/net/wireless/intel/ipw2x00/
+F:     drivers/platform/x86/intel-hid.c
 
-INTEL(R) TRACE HUB
-M:     Alexander Shishkin <alexander.shishkin@linux.intel.com>
+INTEL I/OAT DMA DRIVER
+M:     Dave Jiang <dave.jiang@intel.com>
+R:     Dan Williams <dan.j.williams@intel.com>
+L:     dmaengine@vger.kernel.org
+Q:     https://patchwork.kernel.org/project/linux-dmaengine/list/
 S:     Supported
-F:     Documentation/trace/intel_th.txt
-F:     drivers/hwtracing/intel_th/
+F:     drivers/dma/ioat*
 
-INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT)
-M:     Ning Sun <ning.sun@intel.com>
-L:     tboot-devel@lists.sourceforge.net
-W:     http://tboot.sourceforge.net
-T:     hg http://tboot.hg.sourceforge.net:8000/hgroot/tboot/tboot
+INTEL IDLE DRIVER
+M:     Jacob Pan <jacob.jun.pan@linux.intel.com>
+M:     Len Brown <lenb@kernel.org>
+L:     linux-pm@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git
+B:     https://bugzilla.kernel.org
+S:     Supported
+F:     drivers/idle/intel_idle.c
+
+INTEL INTEGRATED SENSOR HUB DRIVER
+M:     Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+M:     Jiri Kosina <jikos@kernel.org>
+L:     linux-input@vger.kernel.org
+S:     Maintained
+F:     drivers/hid/intel-ish-hid/
+
+INTEL IOMMU (VT-d)
+M:     David Woodhouse <dwmw2@infradead.org>
+L:     iommu@lists.linux-foundation.org
+T:     git git://git.infradead.org/iommu-2.6.git
 S:     Supported
-F:     Documentation/intel_txt.txt
-F:     include/linux/tboot.h
-F:     arch/x86/kernel/tboot.c
+F:     drivers/iommu/intel-iommu.c
+F:     include/linux/intel-iommu.h
 
-INTEL WIRELESS WIMAX CONNECTION 2400
-M:     Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
-M:     linux-wimax@intel.com
-L:     wimax@linuxwimax.org (subscribers-only)
-S:     Supported
-W:     http://linuxwimax.org
-F:     Documentation/wimax/README.i2400m
-F:     drivers/net/wimax/i2400m/
-F:     include/uapi/linux/wimax/i2400m.h
+INTEL IOP-ADMA DMA DRIVER
+R:     Dan Williams <dan.j.williams@intel.com>
+S:     Odd fixes
+F:     drivers/dma/iop-adma.c
 
-INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy)
-M:     Stanislaw Gruszka <sgruszka@redhat.com>
-L:     linux-wireless@vger.kernel.org
-S:     Supported
-F:     drivers/net/wireless/intel/iwlegacy/
+INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
+M:     Krzysztof Halasa <khalasa@piap.pl>
+S:     Maintained
+F:     arch/arm/mach-ixp4xx/include/mach/qmgr.h
+F:     arch/arm/mach-ixp4xx/include/mach/npe.h
+F:     arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
+F:     arch/arm/mach-ixp4xx/ixp4xx_npe.c
+F:     drivers/net/ethernet/xscale/ixp4xx_eth.c
+F:     drivers/net/wan/ixp4xx_hss.c
 
-INTEL WIRELESS WIFI LINK (iwlwifi)
-M:     Johannes Berg <johannes.berg@intel.com>
-M:     Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-M:     Luca Coelho <luciano.coelho@intel.com>
-M:     Intel Linux Wireless <linuxwifi@intel.com>
-L:     linux-wireless@vger.kernel.org
-W:     http://intellinuxwireless.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
-S:     Supported
-F:     drivers/net/wireless/intel/iwlwifi/
+INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT
+M:     Deepak Saxena <dsaxena@plexity.net>
+S:     Maintained
+F:     drivers/char/hw_random/ixp4xx-rng.c
 
 INTEL MANAGEMENT ENGINE (mei)
 M:     Tomas Winkler <tomas.winkler@intel.com>
@@ -6958,6 +6868,19 @@ F:       drivers/watchdog/mei_wdt.c
 F:     Documentation/misc-devices/mei/*
 F:     samples/mei/*
 
+INTEL MENLOW THERMAL DRIVER
+M:     Sujith Thomas <sujith.thomas@intel.com>
+L:     platform-driver-x86@vger.kernel.org
+W:     https://01.org/linux-acpi
+S:     Supported
+F:     drivers/platform/x86/intel_menlow.c
+
+INTEL MERRIFIELD GPIO DRIVER
+M:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+L:     linux-gpio@vger.kernel.org
+S:     Maintained
+F:     drivers/gpio/gpio-merrifield.c
+
 INTEL MIC DRIVERS (mic)
 M:     Sudeep Dutt <sudeep.dutt@intel.com>
 M:     Ashutosh Dixit <ashutosh.dixit@intel.com>
@@ -6967,13 +6890,21 @@ W:      http://software.intel.com/en-us/mic-developer
 F:     include/linux/mic_bus.h
 F:     include/linux/scif.h
 F:     include/uapi/linux/mic_common.h
-F:     include/uapi/linux/mic_ioctl.h
+F:     include/uapi/linux/mic_ioctl.h
 F:     include/uapi/linux/scif_ioctl.h
 F:     drivers/misc/mic/
 F:     drivers/dma/mic_x100_dma.c
 F:     drivers/dma/mic_x100_dma.h
 F:     Documentation/mic/
 
+INTEL PMC CORE DRIVER
+M:     Rajneesh Bhardwaj <rajneesh.bhardwaj@intel.com>
+M:     Vishwanath Somayaji <vishwanath.somayaji@intel.com>
+L:     platform-driver-x86@vger.kernel.org
+S:     Maintained
+F:     arch/x86/include/asm/pmc_core.h
+F:     drivers/platform/x86/intel_pmc_core*
+
 INTEL PMC/P-Unit IPC DRIVER
 M:     Zha Qipeng<qipeng.zha@intel.com>
 L:     platform-driver-x86@vger.kernel.org
@@ -6983,6 +6914,28 @@ F:       drivers/platform/x86/intel_punit_ipc.c
 F:     arch/x86/include/asm/intel_pmc_ipc.h
 F:     arch/x86/include/asm/intel_punit_ipc.h
 
+INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
+M:     Stanislav Yakovlev <stas.yakovlev@gmail.com>
+L:     linux-wireless@vger.kernel.org
+S:     Maintained
+F:     Documentation/networking/README.ipw2100
+F:     Documentation/networking/README.ipw2200
+F:     drivers/net/wireless/intel/ipw2x00/
+
+INTEL PSTATE DRIVER
+M:     Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+M:     Len Brown <lenb@kernel.org>
+L:     linux-pm@vger.kernel.org
+S:     Supported
+F:     drivers/cpufreq/intel_pstate.c
+
+INTEL RDMA RNIC DRIVER
+M:     Faisal Latif <faisal.latif@intel.com>
+M:     Shiraz Saleem <shiraz.saleem@intel.com>
+L:     linux-rdma@vger.kernel.org
+S:     Supported
+F:     drivers/infiniband/hw/i40iw/
+
 INTEL TELEMETRY DRIVER
 M:     Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>
 L:     platform-driver-x86@vger.kernel.org
@@ -6990,13 +6943,60 @@ S:      Maintained
 F:     arch/x86/include/asm/intel_telemetry.h
 F:     drivers/platform/x86/intel_telemetry*
 
-INTEL PMC CORE DRIVER
-M:     Rajneesh Bhardwaj <rajneesh.bhardwaj@intel.com>
-M:     Vishwanath Somayaji <vishwanath.somayaji@intel.com>
+INTEL VIRTUAL BUTTON DRIVER
+M:     AceLan Kao <acelan.kao@canonical.com>
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
-F:     arch/x86/include/asm/pmc_core.h
-F:     drivers/platform/x86/intel_pmc_core*
+F:     drivers/platform/x86/intel-vbtn.c
+
+INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy)
+M:     Stanislaw Gruszka <sgruszka@redhat.com>
+L:     linux-wireless@vger.kernel.org
+S:     Supported
+F:     drivers/net/wireless/intel/iwlegacy/
+
+INTEL WIRELESS WIFI LINK (iwlwifi)
+M:     Johannes Berg <johannes.berg@intel.com>
+M:     Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+M:     Luca Coelho <luciano.coelho@intel.com>
+M:     Intel Linux Wireless <linuxwifi@intel.com>
+L:     linux-wireless@vger.kernel.org
+W:     http://intellinuxwireless.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
+S:     Supported
+F:     drivers/net/wireless/intel/iwlwifi/
+
+INTEL WIRELESS WIMAX CONNECTION 2400
+M:     Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+M:     linux-wimax@intel.com
+L:     wimax@linuxwimax.org (subscribers-only)
+S:     Supported
+W:     http://linuxwimax.org
+F:     Documentation/wimax/README.i2400m
+F:     drivers/net/wimax/i2400m/
+F:     include/uapi/linux/wimax/i2400m.h
+
+INTEL(R) TRACE HUB
+M:     Alexander Shishkin <alexander.shishkin@linux.intel.com>
+S:     Supported
+F:     Documentation/trace/intel_th.txt
+F:     drivers/hwtracing/intel_th/
+
+INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT)
+M:     Ning Sun <ning.sun@intel.com>
+L:     tboot-devel@lists.sourceforge.net
+W:     http://tboot.sourceforge.net
+T:     hg http://tboot.hg.sourceforge.net:8000/hgroot/tboot/tboot
+S:     Supported
+F:     Documentation/intel_txt.txt
+F:     include/linux/tboot.h
+F:     arch/x86/kernel/tboot.c
+
+INTEL-MID GPIO DRIVER
+M:     David Cohen <david.a.cohen@linux.intel.com>
+L:     linux-gpio@vger.kernel.org
+S:     Maintained
+F:     drivers/gpio/gpio-intel-mid.c
 
 INVENSENSE MPU-3050 GYROSCOPE DRIVER
 M:     Linus Walleij <linus.walleij@linaro.org>
@@ -7042,13 +7042,6 @@ F:       drivers/char/ipmi/
 F:     include/linux/ipmi*
 F:     include/uapi/linux/ipmi*
 
-QCOM AUDIO (ASoC) DRIVERS
-M:     Patrick Lai <plai@codeaurora.org>
-M:     Banajit Goswami <bgoswami@codeaurora.org>
-L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-S:     Supported
-F:     sound/soc/qcom/
-
 IPS SCSI RAID DRIVER
 M:     Adaptec OEM Raid Solutions <aacraid@adaptec.com>
 L:     linux-scsi@vger.kernel.org
@@ -7095,6 +7088,15 @@ F:       drivers/net/irda/
 F:     include/net/irda/
 F:     net/irda/
 
+IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
+M:     Marc Zyngier <marc.zyngier@arm.com>
+S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
+F:     Documentation/IRQ-domain.txt
+F:     include/linux/irqdomain.h
+F:     kernel/irq/irqdomain.c
+F:     kernel/irq/msi.c
+
 IRQ SUBSYSTEM
 M:     Thomas Gleixner <tglx@linutronix.de>
 L:     linux-kernel@vger.kernel.org
@@ -7113,15 +7115,6 @@ T:       git git://git.infradead.org/users/jcooper/linux.git irqchip/core
 F:     Documentation/devicetree/bindings/interrupt-controller/
 F:     drivers/irqchip/
 
-IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
-M:     Marc Zyngier <marc.zyngier@arm.com>
-S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
-F:     Documentation/IRQ-domain.txt
-F:     include/linux/irqdomain.h
-F:     kernel/irq/irqdomain.c
-F:     kernel/irq/msi.c
-
 ISA
 M:     William Breathitt Gray <vilhelm.gray@gmail.com>
 S:     Maintained
@@ -7129,13 +7122,6 @@ F:       Documentation/isa.txt
 F:     drivers/base/isa.c
 F:     include/linux/isa.h
 
-ISAPNP
-M:     Jaroslav Kysela <perex@perex.cz>
-S:     Maintained
-F:     Documentation/isapnp.txt
-F:     drivers/pnp/isapnp/
-F:     include/linux/isapnp.h
-
 ISA RADIO MODULE
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
@@ -7144,11 +7130,12 @@ W:      https://linuxtv.org
 S:     Maintained
 F:     drivers/media/radio/radio-isa*
 
-iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER
-M:     Peter Jones <pjones@redhat.com>
-M:     Konrad Rzeszutek Wilk <konrad@kernel.org>
+ISAPNP
+M:     Jaroslav Kysela <perex@perex.cz>
 S:     Maintained
-F:     drivers/firmware/iscsi_ibft*
+F:     Documentation/isapnp.txt
+F:     drivers/pnp/isapnp/
+F:     include/linux/isapnp.h
 
 ISCSI
 M:     Lee Duncan <lduncan@suse.com>
@@ -7159,6 +7146,12 @@ S:       Maintained
 F:     drivers/scsi/*iscsi*
 F:     include/scsi/*iscsi*
 
+iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER
+M:     Peter Jones <pjones@redhat.com>
+M:     Konrad Rzeszutek Wilk <konrad@kernel.org>
+S:     Maintained
+F:     drivers/firmware/iscsi_ibft*
+
 ISCSI EXTENSIONS FOR RDMA (ISER) INITIATOR
 M:     Or Gerlitz <ogerlitz@mellanox.com>
 M:     Sagi Grimberg <sagi@grimberg.me>
@@ -7414,27 +7407,6 @@ S:       Maintained
 F:     arch/x86/include/asm/svm.h
 F:     arch/x86/kvm/svm.c
 
-KERNEL VIRTUAL MACHINE (KVM) FOR POWERPC
-M:     Alexander Graf <agraf@suse.com>
-L:     kvm-ppc@vger.kernel.org
-W:     http://www.linux-kvm.org/
-T:     git git://github.com/agraf/linux-2.6.git
-S:     Supported
-F:     arch/powerpc/include/asm/kvm*
-F:     arch/powerpc/kvm/
-
-KERNEL VIRTUAL MACHINE for s390 (KVM/s390)
-M:     Christian Borntraeger <borntraeger@de.ibm.com>
-M:     Cornelia Huck <cohuck@redhat.com>
-L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git
-S:     Supported
-F:     Documentation/s390/kvm.txt
-F:     arch/s390/include/asm/kvm*
-F:     arch/s390/kvm/
-F:     arch/s390/mm/gmap.c
-
 KERNEL VIRTUAL MACHINE (KVM) FOR ARM
 M:     Christoffer Dall <christoffer.dall@linaro.org>
 M:     Marc Zyngier <marc.zyngier@arm.com>
@@ -7449,6 +7421,15 @@ F:       arch/arm/kvm/
 F:     virt/kvm/arm/
 F:     include/kvm/arm_*
 
+KERNEL VIRTUAL MACHINE (KVM) FOR POWERPC
+M:     Alexander Graf <agraf@suse.com>
+L:     kvm-ppc@vger.kernel.org
+W:     http://www.linux-kvm.org/
+T:     git git://github.com/agraf/linux-2.6.git
+S:     Supported
+F:     arch/powerpc/include/asm/kvm*
+F:     arch/powerpc/kvm/
+
 KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
 M:     Christoffer Dall <christoffer.dall@linaro.org>
 M:     Marc Zyngier <marc.zyngier@arm.com>
@@ -7467,6 +7448,18 @@ F:       arch/mips/include/uapi/asm/kvm*
 F:     arch/mips/include/asm/kvm*
 F:     arch/mips/kvm/
 
+KERNEL VIRTUAL MACHINE for s390 (KVM/s390)
+M:     Christian Borntraeger <borntraeger@de.ibm.com>
+M:     Cornelia Huck <cohuck@redhat.com>
+L:     linux-s390@vger.kernel.org
+W:     http://www.ibm.com/developerworks/linux/linux390/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git
+S:     Supported
+F:     Documentation/s390/kvm.txt
+F:     arch/s390/include/asm/kvm*
+F:     arch/s390/kvm/
+F:     arch/s390/mm/gmap.c
+
 KERNFS
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 M:     Tejun Heo <tj@kernel.org>
@@ -7484,17 +7477,15 @@ F:      include/linux/kexec.h
 F:     include/uapi/linux/kexec.h
 F:     kernel/kexec*
 
-KEYS/KEYRINGS:
-M:     David Howells <dhowells@redhat.com>
+KEYS-ENCRYPTED
+M:     Mimi Zohar <zohar@linux.vnet.ibm.com>
+M:     David Safford <safford@us.ibm.com>
+L:     linux-security-module@vger.kernel.org
 L:     keyrings@vger.kernel.org
-S:     Maintained
-F:     Documentation/security/keys/core.rst
-F:     include/linux/key.h
-F:     include/linux/key-type.h
-F:     include/linux/keyctl.h
-F:     include/uapi/linux/keyctl.h
-F:     include/keys/
-F:     security/keys/
+S:     Supported
+F:     Documentation/security/keys/trusted-encrypted.rst
+F:     include/keys/encrypted-type.h
+F:     security/keys/encrypted-keys/
 
 KEYS-TRUSTED
 M:     David Safford <safford@us.ibm.com>
@@ -7506,16 +7497,18 @@ F:      Documentation/security/keys/trusted-encrypted.rst
 F:     include/keys/trusted-type.h
 F:     security/keys/trusted.c
 F:     security/keys/trusted.h
-
-KEYS-ENCRYPTED
-M:     Mimi Zohar <zohar@linux.vnet.ibm.com>
-M:     David Safford <safford@us.ibm.com>
-L:     linux-security-module@vger.kernel.org
+
+KEYS/KEYRINGS:
+M:     David Howells <dhowells@redhat.com>
 L:     keyrings@vger.kernel.org
-S:     Supported
-F:     Documentation/security/keys/trusted-encrypted.rst
-F:     include/keys/encrypted-type.h
-F:     security/keys/encrypted-keys/
+S:     Maintained
+F:     Documentation/security/keys/core.rst
+F:     include/linux/key.h
+F:     include/linux/key-type.h
+F:     include/linux/keyctl.h
+F:     include/uapi/linux/keyctl.h
+F:     include/keys/
+F:     security/keys/
 
 KGDB / KDB /debug_core
 M:     Jason Wessel <jason.wessel@windriver.com>
@@ -7548,6 +7541,15 @@ F:       include/linux/kmemleak.h
 F:     mm/kmemleak.c
 F:     mm/kmemleak-test.c
 
+KMOD MODULE USERMODE HELPER
+M:     "Luis R. Rodriguez" <mcgrof@kernel.org>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+F:     kernel/kmod.c
+F:     include/linux/kmod.h
+F:     lib/test_kmod.c
+F:     tools/testing/selftests/kmod/
+
 KPROBES
 M:     Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
 M:     Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
@@ -7650,16 +7652,6 @@ F:       drivers/lguest/
 F:     include/linux/lguest*.h
 F:     tools/lguest/
 
-LIBATA SUBSYSTEM (Serial and Parallel ATA drivers)
-M:     Tejun Heo <tj@kernel.org>
-L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
-S:     Maintained
-F:     drivers/ata/
-F:     include/linux/ata.h
-F:     include/linux/libata.h
-F:     Documentation/devicetree/bindings/ata/
-
 LIBATA PATA ARASAN COMPACT FLASH CONTROLLER
 M:     Viresh Kumar <vireshk@kernel.org>
 L:     linux-ide@vger.kernel.org
@@ -7703,22 +7695,21 @@ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
 S:     Maintained
 F:     drivers/ata/sata_promise.*
 
+LIBATA SUBSYSTEM (Serial and Parallel ATA drivers)
+M:     Tejun Heo <tj@kernel.org>
+L:     linux-ide@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+S:     Maintained
+F:     drivers/ata/
+F:     include/linux/ata.h
+F:     include/linux/libata.h
+F:     Documentation/devicetree/bindings/ata/
+
 LIBLOCKDEP
 M:     Sasha Levin <alexander.levin@verizon.com>
 S:     Maintained
 F:     tools/lib/lockdep/
 
-LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM
-M:     Dan Williams <dan.j.williams@intel.com>
-L:     linux-nvdimm@lists.01.org
-Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git
-S:     Supported
-F:     drivers/nvdimm/*
-F:     include/linux/nd.h
-F:     include/linux/libnvdimm.h
-F:     include/uapi/linux/ndctl.h
-
 LIBNVDIMM BLK: MMIO-APERTURE DRIVER
 M:     Ross Zwisler <ross.zwisler@linux.intel.com>
 L:     linux-nvdimm@lists.01.org
@@ -7726,7 +7717,6 @@ Q:        https://patchwork.kernel.org/project/linux-nvdimm/list/
 S:     Supported
 F:     drivers/nvdimm/blk.c
 F:     drivers/nvdimm/region_devs.c
-F:     drivers/acpi/nfit*
 
 LIBNVDIMM BTT: BLOCK TRANSLATION TABLE
 M:     Vishal Verma <vishal.l.verma@intel.com>
@@ -7742,6 +7732,18 @@ Q:       https://patchwork.kernel.org/project/linux-nvdimm/list/
 S:     Supported
 F:     drivers/nvdimm/pmem*
 
+LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM
+M:     Dan Williams <dan.j.williams@intel.com>
+L:     linux-nvdimm@lists.01.org
+Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git
+S:     Supported
+F:     drivers/nvdimm/*
+F:     drivers/acpi/nfit/*
+F:     include/linux/nd.h
+F:     include/linux/libnvdimm.h
+F:     include/uapi/linux/ndctl.h
+
 LIGHTNVM PLATFORM SUPPORT
 M:     Matias Bjorling <mb@lightnvm.io>
 W:     http://github/OpenChannelSSD
@@ -7751,6 +7753,14 @@ F:       drivers/lightnvm/
 F:     include/linux/lightnvm.h
 F:     include/uapi/linux/lightnvm.h
 
+LINUX FOR POWER MACINTOSH
+M:     Benjamin Herrenschmidt <benh@kernel.crashing.org>
+W:     http://www.penguinppc.org/
+L:     linuxppc-dev@lists.ozlabs.org
+S:     Maintained
+F:     arch/powerpc/platforms/powermac/
+F:     drivers/macintosh/
+
 LINUX FOR POWERPC (32-BIT AND 64-BIT)
 M:     Benjamin Herrenschmidt <benh@kernel.crashing.org>
 M:     Paul Mackerras <paulus@samba.org>
@@ -7784,14 +7794,6 @@ N:       powernv
 N:     [^a-z0-9]ps3
 N:     pseries
 
-LINUX FOR POWER MACINTOSH
-M:     Benjamin Herrenschmidt <benh@kernel.crashing.org>
-W:     http://www.penguinppc.org/
-L:     linuxppc-dev@lists.ozlabs.org
-S:     Maintained
-F:     arch/powerpc/platforms/powermac/
-F:     drivers/macintosh/
-
 LINUX FOR POWERPC EMBEDDED MPC5XXX
 M:     Anatolij Gustschin <agust@denx.de>
 L:     linuxppc-dev@lists.ozlabs.org
@@ -7809,19 +7811,6 @@ S:       Maintained
 F:     arch/powerpc/platforms/40x/
 F:     arch/powerpc/platforms/44x/
 
-LINUX FOR POWERPC EMBEDDED XILINX VIRTEX
-L:     linuxppc-dev@lists.ozlabs.org
-S:     Orphan
-F:     arch/powerpc/*/*virtex*
-F:     arch/powerpc/*/*/*virtex*
-
-LINUX FOR POWERPC EMBEDDED PPC8XX
-M:     Vitaly Bordug <vitb@kernel.crashing.org>
-W:     http://www.penguinppc.org/
-L:     linuxppc-dev@lists.ozlabs.org
-S:     Maintained
-F:     arch/powerpc/platforms/8xx/
-
 LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX
 M:     Scott Wood <oss@buserror.net>
 M:     Kumar Gala <galak@kernel.crashing.org>
@@ -7833,6 +7822,19 @@ F:       arch/powerpc/platforms/83xx/
 F:     arch/powerpc/platforms/85xx/
 F:     Documentation/devicetree/bindings/powerpc/fsl/
 
+LINUX FOR POWERPC EMBEDDED PPC8XX
+M:     Vitaly Bordug <vitb@kernel.crashing.org>
+W:     http://www.penguinppc.org/
+L:     linuxppc-dev@lists.ozlabs.org
+S:     Maintained
+F:     arch/powerpc/platforms/8xx/
+
+LINUX FOR POWERPC EMBEDDED XILINX VIRTEX
+L:     linuxppc-dev@lists.ozlabs.org
+S:     Orphan
+F:     arch/powerpc/*/*virtex*
+F:     arch/powerpc/*/*/*virtex*
+
 LINUX FOR POWERPC PA SEMI PWRFICIENT
 L:     linuxppc-dev@lists.ozlabs.org
 S:     Orphan
@@ -7840,6 +7842,11 @@ F:       arch/powerpc/platforms/pasemi/
 F:     drivers/*/*pasemi*
 F:     drivers/*/*/*pasemi*
 
+LINUX KERNEL DUMP TEST MODULE (LKDTM)
+M:     Kees Cook <keescook@chromium.org>
+S:     Maintained
+F:     drivers/misc/lkdtm*
+
 LINUX SECURITY MODULE (LSM) FRAMEWORK
 M:     Chris Wright <chrisw@sous-sol.org>
 L:     linux-security-module@vger.kernel.org
@@ -7869,11 +7876,6 @@ F:       samples/livepatch/
 L:     live-patching@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching.git
 
-LINUX KERNEL DUMP TEST MODULE (LKDTM)
-M:     Kees Cook <keescook@chromium.org>
-S:     Maintained
-F:     drivers/misc/lkdtm*
-
 LLC (802.2)
 L:     netdev@vger.kernel.org
 S:     Odd fixes
@@ -7926,6 +7928,13 @@ Q:       http://patchwork.linuxtv.org/project/linux-media/list/
 S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/lmedm04*
 
+LOADPIN SECURITY MODULE
+M:     Kees Cook <keescook@chromium.org>
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git lsm/loadpin
+S:     Supported
+F:     security/loadpin/
+F:     Documentation/admin-guide/LSM/LoadPin.rst
+
 LOCKING PRIMITIVES
 M:     Peter Zijlstra <peterz@infradead.org>
 M:     Ingo Molnar <mingo@redhat.com>
@@ -8216,14 +8225,6 @@ S:       Maintained
 F:     Documentation/devicetree/bindings/sound/max9860.txt
 F:     sound/soc/codecs/max9860.*
 
-MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS
-M:     Krzysztof Kozlowski <krzk@kernel.org>
-M:     Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
-L:     linux-pm@vger.kernel.org
-S:     Supported
-F:     drivers/power/supply/max14577_charger.c
-F:     drivers/power/supply/max77693_charger.c
-
 MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER
 M:     Javier Martinez Canillas <javier@dowhile0.org>
 L:     linux-kernel@vger.kernel.org
@@ -8232,6 +8233,14 @@ F:       drivers/regulator/max77802-regulator.c
 F:     Documentation/devicetree/bindings/*/*max77802.txt
 F:     include/dt-bindings/*/*max77802.h
 
+MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS
+M:     Krzysztof Kozlowski <krzk@kernel.org>
+M:     Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
+L:     linux-pm@vger.kernel.org
+S:     Supported
+F:     drivers/power/supply/max14577_charger.c
+F:     drivers/power/supply/max77693_charger.c
+
 MAXIM PMIC AND MUIC DRIVERS FOR EXYNOS BASED BOARDS
 M:     Chanwoo Choi <cw00.choi@samsung.com>
 M:     Krzysztof Kozlowski <krzk@kernel.org>
@@ -8274,14 +8283,25 @@ L:      linux-iio@vger.kernel.org
 S:     Maintained
 F:     drivers/iio/dac/cio-dac.c
 
-MEDIA DRIVERS FOR RENESAS - DRIF
-M:     Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
+MEDIA DRIVERS FOR ASCOT2E
+M:     Sergey Kozlov <serjk@netup.ru>
+M:     Abylay Ospan <aospan@netup.ru>
 L:     linux-media@vger.kernel.org
-L:     linux-renesas-soc@vger.kernel.org
+W:     https://linuxtv.org
+W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
-F:     Documentation/devicetree/bindings/media/renesas,drif.txt
-F:     drivers/media/platform/rcar_drif.c
+F:     drivers/media/dvb-frontends/ascot2e*
+
+MEDIA DRIVERS FOR CXD2841ER
+M:     Sergey Kozlov <serjk@netup.ru>
+M:     Abylay Ospan <aospan@netup.ru>
+L:     linux-media@vger.kernel.org
+W:     https://linuxtv.org
+W:     http://netup.tv/
+T:     git git://linuxtv.org/media_tree.git
+S:     Supported
+F:     drivers/media/dvb-frontends/cxd2841er*
 
 MEDIA DRIVERS FOR FREESCALE IMX
 M:     Steve Longerbeam <slongerbeam@gmail.com>
@@ -8295,43 +8315,6 @@ F:       drivers/staging/media/imx/
 F:     include/linux/imx-media.h
 F:     include/media/imx.h
 
-MEDIA DRIVERS FOR RENESAS - FCP
-M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-L:     linux-media@vger.kernel.org
-L:     linux-renesas-soc@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-S:     Supported
-F:     Documentation/devicetree/bindings/media/renesas,fcp.txt
-F:     drivers/media/platform/rcar-fcp.c
-F:     include/media/rcar-fcp.h
-
-MEDIA DRIVERS FOR RENESAS - FDP1
-M:     Kieran Bingham <kieran@bingham.xyz>
-L:     linux-media@vger.kernel.org
-L:     linux-renesas-soc@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-S:     Supported
-F:     Documentation/devicetree/bindings/media/renesas,fdp1.txt
-F:     drivers/media/platform/rcar_fdp1.c
-
-MEDIA DRIVERS FOR RENESAS - VIN
-M:     Niklas Söderlund <niklas.soderlund@ragnatech.se>
-L:     linux-media@vger.kernel.org
-L:     linux-renesas-soc@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-S:     Supported
-F:     Documentation/devicetree/bindings/media/rcar_vin.txt
-F:     drivers/media/platform/rcar-vin/
-
-MEDIA DRIVERS FOR RENESAS - VSP1
-M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-L:     linux-media@vger.kernel.org
-L:     linux-renesas-soc@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-S:     Supported
-F:     Documentation/devicetree/bindings/media/renesas,vsp1.txt
-F:     drivers/media/platform/vsp1/
-
 MEDIA DRIVERS FOR HELENE
 M:     Abylay Ospan <aospan@netup.ru>
 L:     linux-media@vger.kernel.org
@@ -8341,7 +8324,7 @@ T:        git git://linuxtv.org/media_tree.git
 S:     Supported
 F:     drivers/media/dvb-frontends/helene*
 
-MEDIA DRIVERS FOR ASCOT2E
+MEDIA DRIVERS FOR HORUS3A
 M:     Sergey Kozlov <serjk@netup.ru>
 M:     Abylay Ospan <aospan@netup.ru>
 L:     linux-media@vger.kernel.org
@@ -8349,9 +8332,9 @@ W:        https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
-F:     drivers/media/dvb-frontends/ascot2e*
+F:     drivers/media/dvb-frontends/horus3a*
 
-MEDIA DRIVERS FOR CXD2841ER
+MEDIA DRIVERS FOR LNBH25
 M:     Sergey Kozlov <serjk@netup.ru>
 M:     Abylay Ospan <aospan@netup.ru>
 L:     linux-media@vger.kernel.org
@@ -8359,9 +8342,9 @@ W:        https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
-F:     drivers/media/dvb-frontends/cxd2841er*
+F:     drivers/media/dvb-frontends/lnbh25*
 
-MEDIA DRIVERS FOR HORUS3A
+MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices
 M:     Sergey Kozlov <serjk@netup.ru>
 M:     Abylay Ospan <aospan@netup.ru>
 L:     linux-media@vger.kernel.org
@@ -8369,27 +8352,53 @@ W:      https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
-F:     drivers/media/dvb-frontends/horus3a*
+F:     drivers/media/pci/netup_unidvb/*
 
-MEDIA DRIVERS FOR LNBH25
-M:     Sergey Kozlov <serjk@netup.ru>
-M:     Abylay Ospan <aospan@netup.ru>
+MEDIA DRIVERS FOR RENESAS - DRIF
+M:     Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
 L:     linux-media@vger.kernel.org
-W:     https://linuxtv.org
-W:     http://netup.tv/
+L:     linux-renesas-soc@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
-F:     drivers/media/dvb-frontends/lnbh25*
+F:     Documentation/devicetree/bindings/media/renesas,drif.txt
+F:     drivers/media/platform/rcar_drif.c
 
-MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices
-M:     Sergey Kozlov <serjk@netup.ru>
-M:     Abylay Ospan <aospan@netup.ru>
+MEDIA DRIVERS FOR RENESAS - FCP
+M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
-W:     https://linuxtv.org
-W:     http://netup.tv/
+L:     linux-renesas-soc@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
-F:     drivers/media/pci/netup_unidvb/*
+F:     Documentation/devicetree/bindings/media/renesas,fcp.txt
+F:     drivers/media/platform/rcar-fcp.c
+F:     include/media/rcar-fcp.h
+
+MEDIA DRIVERS FOR RENESAS - FDP1
+M:     Kieran Bingham <kieran@bingham.xyz>
+L:     linux-media@vger.kernel.org
+L:     linux-renesas-soc@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Supported
+F:     Documentation/devicetree/bindings/media/renesas,fdp1.txt
+F:     drivers/media/platform/rcar_fdp1.c
+
+MEDIA DRIVERS FOR RENESAS - VIN
+M:     Niklas Söderlund <niklas.soderlund@ragnatech.se>
+L:     linux-media@vger.kernel.org
+L:     linux-renesas-soc@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Supported
+F:     Documentation/devicetree/bindings/media/rcar_vin.txt
+F:     drivers/media/platform/rcar-vin/
+
+MEDIA DRIVERS FOR RENESAS - VSP1
+M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+L:     linux-media@vger.kernel.org
+L:     linux-renesas-soc@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Supported
+F:     Documentation/devicetree/bindings/media/renesas,vsp1.txt
+F:     drivers/media/platform/vsp1/
 
 MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
 M:     Mauro Carvalho Chehab <mchehab@s-opensource.com>
@@ -8416,7 +8425,9 @@ F:        include/uapi/linux/uvcvideo.h
 
 MEDIATEK ETHERNET DRIVER
 M:     Felix Fietkau <nbd@openwrt.org>
-M:     John Crispin <blogic@openwrt.org>
+M:     John Crispin <john@phrozen.org>
+M:     Sean Wang <sean.wang@mediatek.com>
+M:     Nelson Chang <nelson.chang@mediatek.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/mediatek/
@@ -8428,15 +8439,6 @@ S:       Supported
 F:     drivers/media/platform/mtk-jpeg/
 F:     Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt
 
-MEDIATEK MEDIA DRIVER
-M:     Tiffany Lin <tiffany.lin@mediatek.com>
-M:     Andrew-CT Chen <andrew-ct.chen@mediatek.com>
-S:     Supported
-F:     drivers/media/platform/mtk-vcodec/
-F:     drivers/media/platform/mtk-vpu/
-F:     Documentation/devicetree/bindings/media/mediatek-vcodec.txt
-F:     Documentation/devicetree/bindings/media/mediatek-vpu.txt
-
 MEDIATEK MDP DRIVER
 M:     Minghsiu Tsai <minghsiu.tsai@mediatek.com>
 M:     Houlong Wei <houlong.wei@mediatek.com>
@@ -8446,6 +8448,15 @@ F:       drivers/media/platform/mtk-mdp/
 F:     drivers/media/platform/mtk-vpu/
 F:     Documentation/devicetree/bindings/media/mediatek-mdp.txt
 
+MEDIATEK MEDIA DRIVER
+M:     Tiffany Lin <tiffany.lin@mediatek.com>
+M:     Andrew-CT Chen <andrew-ct.chen@mediatek.com>
+S:     Supported
+F:     drivers/media/platform/mtk-vcodec/
+F:     drivers/media/platform/mtk-vpu/
+F:     Documentation/devicetree/bindings/media/mediatek-vcodec.txt
+F:     Documentation/devicetree/bindings/media/mediatek-vpu.txt
+
 MEDIATEK MT7601U WIRELESS LAN DRIVER
 M:     Jakub Kicinski <kubakici@wp.pl>
 L:     linux-wireless@vger.kernel.org
@@ -8453,9 +8464,9 @@ S:        Maintained
 F:     drivers/net/wireless/mediatek/mt7601u/
 
 MEDIATEK RANDOM NUMBER GENERATOR SUPPORT
-M:      Sean Wang <sean.wang@mediatek.com>
-S:      Maintained
-F:      drivers/char/hw_random/mtk-rng.c
+M:     Sean Wang <sean.wang@mediatek.com>
+S:     Maintained
+F:     drivers/char/hw_random/mtk-rng.c
 
 MEGACHIPS STDPXXXX-GE-B850V3-FW LVDS/DP++ BRIDGES
 M:     Peter Senna Tschudin <peter.senna@collabora.com>
@@ -8477,6 +8488,13 @@ F:       Documentation/scsi/megaraid.txt
 F:     drivers/scsi/megaraid.*
 F:     drivers/scsi/megaraid/
 
+MELEXIS MLX90614 DRIVER
+M:     Crt Mori <cmo@melexis.com>
+L:     linux-iio@vger.kernel.org
+W:     http://www.melexis.com
+S:     Supported
+F:     drivers/iio/temperature/mlx90614.c
+
 MELFAS MIP4 TOUCHSCREEN DRIVER
 M:     Sangwon Jee <jeesw@melfas.com>
 W:     http://www.melfas.com
@@ -8537,6 +8555,56 @@ W:       http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
 F:     drivers/net/ethernet/mellanox/mlxfw/
 
+MELLANOX MLX CPLD HOTPLUG DRIVER
+M:     Vadim Pasternak <vadimp@mellanox.com>
+L:     platform-driver-x86@vger.kernel.org
+S:     Supported
+F:     drivers/platform/x86/mlxcpld-hotplug.c
+F:     include/linux/platform_data/mlxcpld-hotplug.h
+
+MELLANOX MLX4 core VPI driver
+M:     Tariq Toukan <tariqt@mellanox.com>
+L:     netdev@vger.kernel.org
+L:     linux-rdma@vger.kernel.org
+W:     http://www.mellanox.com
+Q:     http://patchwork.ozlabs.org/project/netdev/list/
+S:     Supported
+F:     drivers/net/ethernet/mellanox/mlx4/
+F:     include/linux/mlx4/
+
+MELLANOX MLX4 IB driver
+M:     Yishai Hadas <yishaih@mellanox.com>
+L:     linux-rdma@vger.kernel.org
+W:     http://www.mellanox.com
+Q:     http://patchwork.kernel.org/project/linux-rdma/list/
+S:     Supported
+F:     drivers/infiniband/hw/mlx4/
+F:     include/linux/mlx4/
+F:     include/uapi/rdma/mlx4-abi.h
+
+MELLANOX MLX5 core VPI driver
+M:     Saeed Mahameed <saeedm@mellanox.com>
+M:     Matan Barak <matanb@mellanox.com>
+M:     Leon Romanovsky <leonro@mellanox.com>
+L:     netdev@vger.kernel.org
+L:     linux-rdma@vger.kernel.org
+W:     http://www.mellanox.com
+Q:     http://patchwork.ozlabs.org/project/netdev/list/
+S:     Supported
+F:     drivers/net/ethernet/mellanox/mlx5/core/
+F:     include/linux/mlx5/
+
+MELLANOX MLX5 IB driver
+M:     Matan Barak <matanb@mellanox.com>
+M:     Leon Romanovsky <leonro@mellanox.com>
+L:     linux-rdma@vger.kernel.org
+W:     http://www.mellanox.com
+Q:     http://patchwork.kernel.org/project/linux-rdma/list/
+S:     Supported
+F:     drivers/infiniband/hw/mlx5/
+F:     include/linux/mlx5/
+F:     include/uapi/rdma/mlx5-abi.h
+
 MELLANOX MLXCPLD I2C AND MUX DRIVER
 M:     Vadim Pasternak <vadimp@mellanox.com>
 M:     Michael Shych <michaelsh@mellanox.com>
@@ -8554,26 +8622,10 @@ F:      drivers/leds/leds-mlxcpld.c
 F:     Documentation/leds/leds-mlxcpld.txt
 
 MELLANOX PLATFORM DRIVER
-M:      Vadim Pasternak <vadimp@mellanox.com>
-L:      platform-driver-x86@vger.kernel.org
-S:      Supported
-F:      drivers/platform/x86/mlx-platform.c
-
-MELLANOX MLX CPLD HOTPLUG DRIVER
 M:     Vadim Pasternak <vadimp@mellanox.com>
 L:     platform-driver-x86@vger.kernel.org
 S:     Supported
-F:     drivers/platform/x86/mlxcpld-hotplug.c
-F:     include/linux/platform_data/mlxcpld-hotplug.h
-
-SOFT-ROCE DRIVER (rxe)
-M:     Moni Shoua <monis@mellanox.com>
-L:     linux-rdma@vger.kernel.org
-S:     Supported
-W:     https://github.com/SoftRoCE/rxe-dev/wiki/rxe-dev:-Home
-Q:     http://patchwork.kernel.org/project/linux-rdma/list/
-F:     drivers/infiniband/sw/rxe/
-F:     include/uapi/rdma/rdma_user_rxe.h
+F:     drivers/platform/x86/mlx-platform.c
 
 MEMBARRIER SUPPORT
 M:     Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
@@ -8695,6 +8747,18 @@ S:       Maintained
 F:     drivers/usb/misc/usb251xb.c
 F:     Documentation/devicetree/bindings/usb/usb251xb.txt
 
+MICROSEMI SMART ARRAY SMARTPQI DRIVER (smartpqi)
+M:     Don Brace <don.brace@microsemi.com>
+L:     esc.storagedev@microsemi.com
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+F:     drivers/scsi/smartpqi/smartpqi*.[ch]
+F:     drivers/scsi/smartpqi/Kconfig
+F:     drivers/scsi/smartpqi/Makefile
+F:     include/linux/cciss*.h
+F:     include/uapi/linux/cciss*.h
+F:     Documentation/scsi/smartpqi.txt
+
 MICROSOFT SURFACE PRO 3 BUTTON DRIVER
 M:     Chen Yu <yu.c.chen@intel.com>
 L:     platform-driver-x86@vger.kernel.org
@@ -8717,6 +8781,22 @@ F:       Documentation/devicetree/bindings/mips/
 F:     Documentation/mips/
 F:     arch/mips/
 
+MIPS BOSTON DEVELOPMENT BOARD
+M:     Paul Burton <paul.burton@imgtec.com>
+L:     linux-mips@linux-mips.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/clock/img,boston-clock.txt
+F:     arch/mips/boot/dts/img/boston.dts
+F:     arch/mips/configs/generic/board-boston.config
+F:     drivers/clk/imgtec/clk-boston.c
+F:     include/dt-bindings/clock/boston-clock.h
+
+MIPS GENERIC PLATFORM
+M:     Paul Burton <paul.burton@imgtec.com>
+L:     linux-mips@linux-mips.org
+S:     Supported
+F:     arch/mips/generic/
+
 MIPS/LOONGSON1 ARCHITECTURE
 M:     Keguang Zhang <keguang.zhang@gmail.com>
 L:     linux-mips@linux-mips.org
@@ -8734,67 +8814,15 @@ W:      https://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/radio/radio-miropcm20*
 
-MELLANOX MLX4 core VPI driver
-M:     Tariq Toukan <tariqt@mellanox.com>
-L:     netdev@vger.kernel.org
-L:     linux-rdma@vger.kernel.org
-W:     http://www.mellanox.com
-Q:     http://patchwork.ozlabs.org/project/netdev/list/
-S:     Supported
-F:     drivers/net/ethernet/mellanox/mlx4/
-F:     include/linux/mlx4/
-
-MELLANOX MLX4 IB driver
-M:     Yishai Hadas <yishaih@mellanox.com>
-L:     linux-rdma@vger.kernel.org
-W:     http://www.mellanox.com
-Q:     http://patchwork.kernel.org/project/linux-rdma/list/
-S:     Supported
-F:     drivers/infiniband/hw/mlx4/
-F:     include/linux/mlx4/
-F:     include/uapi/rdma/mlx4-abi.h
-
-MELLANOX MLX5 core VPI driver
-M:     Saeed Mahameed <saeedm@mellanox.com>
-M:     Matan Barak <matanb@mellanox.com>
-M:     Leon Romanovsky <leonro@mellanox.com>
-L:     netdev@vger.kernel.org
-L:     linux-rdma@vger.kernel.org
-W:     http://www.mellanox.com
-Q:     http://patchwork.ozlabs.org/project/netdev/list/
-S:     Supported
-F:     drivers/net/ethernet/mellanox/mlx5/core/
-F:     include/linux/mlx5/
-
-MELLANOX MLX5 IB driver
-M:     Matan Barak <matanb@mellanox.com>
-M:     Leon Romanovsky <leonro@mellanox.com>
-L:     linux-rdma@vger.kernel.org
-W:     http://www.mellanox.com
-Q:     http://patchwork.kernel.org/project/linux-rdma/list/
-S:     Supported
-F:     drivers/infiniband/hw/mlx5/
-F:     include/linux/mlx5/
-F:     include/uapi/rdma/mlx5-abi.h
-
-MELEXIS MLX90614 DRIVER
-M:     Crt Mori <cmo@melexis.com>
-L:     linux-iio@vger.kernel.org
-W:     http://www.melexis.com
-S:     Supported
-F:     drivers/iio/temperature/mlx90614.c
-
-MICROSEMI SMART ARRAY SMARTPQI DRIVER (smartpqi)
-M:     Don Brace <don.brace@microsemi.com>
-L:     esc.storagedev@microsemi.com
-L:     linux-scsi@vger.kernel.org
-S:     Supported
-F:     drivers/scsi/smartpqi/smartpqi*.[ch]
-F:     drivers/scsi/smartpqi/Kconfig
-F:     drivers/scsi/smartpqi/Makefile
-F:     include/linux/cciss*.h
-F:     include/uapi/linux/cciss*.h
-F:     Documentation/scsi/smartpqi.txt
+MMP SUPPORT
+M:     Eric Miao <eric.y.miao@gmail.com>
+M:     Haojian Zhuang <haojian.zhuang@gmail.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+T:     git git://github.com/hzhuang1/linux.git
+T:     git git://git.linaro.org/people/ycmiao/pxa-linux.git
+S:     Maintained
+F:     arch/arm/boot/dts/mmp*
+F:     arch/arm/mach-mmp/
 
 MN88472 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
@@ -8928,6 +8956,11 @@ F:       drivers/mfd/
 F:     include/linux/mfd/
 F:     include/dt-bindings/mfd/
 
+MULTIMEDIA CARD (MMC) ETC. OVER SPI
+S:     Orphan
+F:     drivers/mmc/host/mmc_spi.c
+F:     include/linux/spi/mmc_spi.h
+
 MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
 M:     Ulf Hansson <ulf.hansson@linaro.org>
 L:     linux-mmc@vger.kernel.org
@@ -8938,11 +8971,6 @@ F:       drivers/mmc/
 F:     include/linux/mmc/
 F:     include/uapi/linux/mmc/
 
-MULTIMEDIA CARD (MMC) ETC. OVER SPI
-S:     Orphan
-F:     drivers/mmc/host/mmc_spi.c
-F:     include/linux/spi/mmc_spi.h
-
 MULTIPLEXER SUBSYSTEM
 M:     Peter Rosin <peda@axentia.se>
 S:     Maintained
@@ -9005,10 +9033,6 @@ S:       Maintained
 F:     drivers/mtd/nand/
 F:     include/linux/mtd/nand*.h
 
-NATSEMI ETHERNET DRIVER (DP8381x)
-S:     Orphan
-F:     drivers/net/ethernet/natsemi/natsemi.c
-
 NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER
 M:     Daniel Mack <zonque@gmail.com>
 S:     Maintained
@@ -9016,6 +9040,10 @@ L:       alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://www.native-instruments.com
 F:     sound/usb/caiaq/
 
+NATSEMI ETHERNET DRIVER (DP8381x)
+S:     Orphan
+F:     drivers/net/ethernet/natsemi/natsemi.c
+
 NCP FILESYSTEM
 M:     Petr Vandrovec <petr@vandrovec.name>
 S:     Odd Fixes
@@ -9135,6 +9163,35 @@ S:       Maintained
 W:     https://fedorahosted.org/dropwatch/
 F:     net/core/drop_monitor.c
 
+NETWORKING DRIVERS
+L:     netdev@vger.kernel.org
+W:     http://www.linuxfoundation.org/en/Net
+Q:     http://patchwork.ozlabs.org/project/netdev/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
+S:     Odd Fixes
+F:     Documentation/devicetree/bindings/net/
+F:     drivers/net/
+F:     include/linux/if_*
+F:     include/linux/netdevice.h
+F:     include/linux/etherdevice.h
+F:     include/linux/fcdevice.h
+F:     include/linux/fddidevice.h
+F:     include/linux/hippidevice.h
+F:     include/linux/inetdevice.h
+F:     include/uapi/linux/if_*
+F:     include/uapi/linux/netdevice.h
+
+NETWORKING DRIVERS (WIRELESS)
+M:     Kalle Valo <kvalo@codeaurora.org>
+L:     linux-wireless@vger.kernel.org
+Q:     http://patchwork.kernel.org/project/linux-wireless/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git
+S:     Maintained
+F:     Documentation/devicetree/bindings/net/wireless/
+F:     drivers/net/wireless/
+
 NETWORKING [DSA]
 M:     Andrew Lunn <andrew@lunn.ch>
 M:     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
@@ -9166,28 +9223,6 @@ F:       tools/net/
 F:     tools/testing/selftests/net/
 F:     lib/random32.c
 
-NETWORKING [IPv4/IPv6]
-M:     "David S. Miller" <davem@davemloft.net>
-M:     Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
-M:     Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
-L:     netdev@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
-S:     Maintained
-F:     net/ipv4/
-F:     net/ipv6/
-F:     include/net/ip*
-F:     arch/x86/net/*
-
-NETWORKING [TLS]
-M:     Ilya Lesokhin <ilyal@mellanox.com>
-M:     Aviad Yehezkel <aviadye@mellanox.com>
-M:     Dave Watson <davejwatson@fb.com>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     net/tls/*
-F:     include/uapi/linux/tls.h
-F:     include/net/tls.h
-
 NETWORKING [IPSEC]
 M:     Steffen Klassert <steffen.klassert@secunet.com>
 M:     Herbert Xu <herbert@gondor.apana.org.au>
@@ -9212,43 +9247,36 @@ F:      net/ipv6/ip6_vti.c
 F:     include/uapi/linux/xfrm.h
 F:     include/net/xfrm.h
 
+NETWORKING [IPv4/IPv6]
+M:     "David S. Miller" <davem@davemloft.net>
+M:     Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+M:     Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
+L:     netdev@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
+S:     Maintained
+F:     net/ipv4/
+F:     net/ipv6/
+F:     include/net/ip*
+F:     arch/x86/net/*
+
 NETWORKING [LABELED] (NetLabel, CIPSO, Labeled IPsec, SECMARK)
 M:     Paul Moore <paul@paul-moore.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 
-NETWORKING [WIRELESS]
-L:     linux-wireless@vger.kernel.org
-Q:     http://patchwork.kernel.org/project/linux-wireless/list/
-
-NETWORKING DRIVERS
+NETWORKING [TLS]
+M:     Ilya Lesokhin <ilyal@mellanox.com>
+M:     Aviad Yehezkel <aviadye@mellanox.com>
+M:     Dave Watson <davejwatson@fb.com>
 L:     netdev@vger.kernel.org
-W:     http://www.linuxfoundation.org/en/Net
-Q:     http://patchwork.ozlabs.org/project/netdev/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
-S:     Odd Fixes
-F:     Documentation/devicetree/bindings/net/
-F:     drivers/net/
-F:     include/linux/if_*
-F:     include/linux/netdevice.h
-F:     include/linux/etherdevice.h
-F:     include/linux/fcdevice.h
-F:     include/linux/fddidevice.h
-F:     include/linux/hippidevice.h
-F:     include/linux/inetdevice.h
-F:     include/uapi/linux/if_*
-F:     include/uapi/linux/netdevice.h
+S:     Maintained
+F:     net/tls/*
+F:     include/uapi/linux/tls.h
+F:     include/net/tls.h
 
-NETWORKING DRIVERS (WIRELESS)
-M:     Kalle Valo <kvalo@codeaurora.org>
+NETWORKING [WIRELESS]
 L:     linux-wireless@vger.kernel.org
 Q:     http://patchwork.kernel.org/project/linux-wireless/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git
-S:     Maintained
-F:     Documentation/devicetree/bindings/net/wireless/
-F:     drivers/net/wireless/
 
 NETXEN (1/10) GbE SUPPORT
 M:     Manish Chopra <manish.chopra@cavium.com>
@@ -9342,14 +9370,6 @@ S:       Maintained
 F:     drivers/media/i2c/et8ek8
 F:     drivers/media/i2c/ad5820.c
 
-NOKIA N900 CAMERA SUPPORT (ET8EK8 SENSOR, AD5820 FOCUS)
-M:     Pavel Machek <pavel@ucw.cz>
-M:     Sakari Ailus <sakari.ailus@iki.fi>
-L:     linux-media@vger.kernel.org
-S:     Maintained
-F:     drivers/media/i2c/et8ek8
-F:     drivers/media/i2c/ad5820.c
-
 NOKIA N900 POWER SUPPLY DRIVERS
 R:     Pali Rohár <pali.rohar@gmail.com>
 F:     include/linux/power/bq2415x_charger.h
@@ -9361,6 +9381,12 @@ F:       drivers/power/supply/bq27xxx_battery_i2c.c
 F:     drivers/power/supply/isp1704_charger.c
 F:     drivers/power/supply/rx51_battery.c
 
+NTB AMD DRIVER
+M:     Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+L:     linux-ntb@googlegroups.com
+S:     Supported
+F:     drivers/ntb/hw/amd/
+
 NTB DRIVER CORE
 M:     Jon Mason <jdmason@kudzu.us>
 M:     Dave Jiang <dave.jiang@intel.com>
@@ -9375,6 +9401,12 @@ F:       include/linux/ntb.h
 F:     include/linux/ntb_transport.h
 F:     tools/testing/selftests/ntb/
 
+NTB IDT DRIVER
+M:     Serge Semin <fancer.lancer@gmail.com>
+L:     linux-ntb@googlegroups.com
+S:     Supported
+F:     drivers/ntb/hw/idt/
+
 NTB INTEL DRIVER
 M:     Jon Mason <jdmason@kudzu.us>
 M:     Dave Jiang <dave.jiang@intel.com>
@@ -9384,12 +9416,6 @@ W:       https://github.com/jonmason/ntb/wiki
 T:     git git://github.com/jonmason/ntb.git
 F:     drivers/ntb/hw/intel/
 
-NTB AMD DRIVER
-M:     Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
-L:     linux-ntb@googlegroups.com
-S:     Supported
-F:     drivers/ntb/hw/amd/
-
 NTFS FILESYSTEM
 M:     Anton Altaparmakov <anton@tuxera.com>
 L:     linux-ntfs-dev@lists.sourceforge.net
@@ -9419,15 +9445,6 @@ F:       drivers/nvme/host/
 F:     include/linux/nvme.h
 F:     include/uapi/linux/nvme_ioctl.h
 
-NVM EXPRESS TARGET DRIVER
-M:     Christoph Hellwig <hch@lst.de>
-M:     Sagi Grimberg <sagi@grimberg.me>
-L:     linux-nvme@lists.infradead.org
-T:     git://git.infradead.org/nvme.git
-W:     http://git.infradead.org/nvme.git
-S:     Supported
-F:     drivers/nvme/target/
-
 NVM EXPRESS FC TRANSPORT DRIVERS
 M:     James Smart <james.smart@broadcom.com>
 L:     linux-nvme@lists.infradead.org
@@ -9438,6 +9455,15 @@ F:       drivers/nvme/host/fc.c
 F:     drivers/nvme/target/fc.c
 F:     drivers/nvme/target/fcloop.c
 
+NVM EXPRESS TARGET DRIVER
+M:     Christoph Hellwig <hch@lst.de>
+M:     Sagi Grimberg <sagi@grimberg.me>
+L:     linux-nvme@lists.infradead.org
+T:     git://git.infradead.org/nvme.git
+W:     http://git.infradead.org/nvme.git
+S:     Supported
+F:     drivers/nvme/target/
+
 NVMEM FRAMEWORK
 M:     Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
 S:     Maintained
@@ -9446,13 +9472,6 @@ F:       Documentation/devicetree/bindings/nvmem/
 F:     include/linux/nvmem-consumer.h
 F:     include/linux/nvmem-provider.h
 
-NXP-NCI NFC DRIVER
-M:     Clément Perrochaud <clement.perrochaud@effinnov.com>
-R:     Charles Gorand <charles.gorand@effinnov.com>
-L:     linux-nfc@lists.01.org (moderated for non-subscribers)
-S:     Supported
-F:     drivers/nfc/nxp-nci
-
 NXP TDA998X DRM DRIVER
 M:     Russell King <linux@armlinux.org.uk>
 S:     Supported
@@ -9467,55 +9486,31 @@ L:      alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Maintained
 F:     sound/soc/codecs/tfa9879*
 
+NXP-NCI NFC DRIVER
+M:     Clément Perrochaud <clement.perrochaud@effinnov.com>
+R:     Charles Gorand <charles.gorand@effinnov.com>
+L:     linux-nfc@lists.01.org (moderated for non-subscribers)
+S:     Supported
+F:     drivers/nfc/nxp-nci
+
 OBJTOOL
 M:     Josh Poimboeuf <jpoimboe@redhat.com>
 S:     Supported
 F:     tools/objtool/
 
-OMAP1 SUPPORT
-M:     Aaro Koskinen <aaro.koskinen@iki.fi>
-M:     Tony Lindgren <tony@atomide.com>
+OMAP AUDIO SUPPORT
+M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
+M:     Jarkko Nikula <jarkko.nikula@bitmer.com>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 L:     linux-omap@vger.kernel.org
-Q:     http://patchwork.kernel.org/project/linux-omap/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git
 S:     Maintained
-F:     arch/arm/mach-omap1/
-F:     arch/arm/plat-omap/
-F:     arch/arm/configs/omap1_defconfig
-F:     drivers/i2c/busses/i2c-omap.c
-F:     include/linux/i2c-omap.h
+F:     sound/soc/omap/
 
-OMAP2+ SUPPORT
-M:     Tony Lindgren <tony@atomide.com>
+OMAP CLOCK FRAMEWORK SUPPORT
+M:     Paul Walmsley <paul@pwsan.com>
 L:     linux-omap@vger.kernel.org
-W:     http://www.muru.com/linux/omap/
-W:     http://linux.omap.com/
-Q:     http://patchwork.kernel.org/project/linux-omap/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git
 S:     Maintained
-F:     arch/arm/mach-omap2/
-F:     arch/arm/plat-omap/
-F:     arch/arm/configs/omap2plus_defconfig
-F:     drivers/i2c/busses/i2c-omap.c
-F:     drivers/irqchip/irq-omap-intc.c
-F:     drivers/mfd/*omap*.c
-F:     drivers/mfd/menelaus.c
-F:     drivers/mfd/palmas.c
-F:     drivers/mfd/tps65217.c
-F:     drivers/mfd/tps65218.c
-F:     drivers/mfd/tps65910.c
-F:     drivers/mfd/twl-core.[ch]
-F:     drivers/mfd/twl4030*.c
-F:     drivers/mfd/twl6030*.c
-F:     drivers/mfd/twl6040*.c
-F:     drivers/regulator/palmas-regulator*.c
-F:     drivers/regulator/pbias-regulator.c
-F:     drivers/regulator/tps65217-regulator.c
-F:     drivers/regulator/tps65218-regulator.c
-F:     drivers/regulator/tps65910-regulator.c
-F:     drivers/regulator/twl-regulator.c
-F:     drivers/regulator/twl6030-regulator.c
-F:     include/linux/i2c-omap.h
+F:     arch/arm/*omap*/*clock*
 
 OMAP DEVICE TREE SUPPORT
 M:     Benoît Cousson <bcousson@baylibre.com>
@@ -9529,33 +9524,20 @@ F:      arch/arm/boot/dts/*am4*
 F:     arch/arm/boot/dts/*am5*
 F:     arch/arm/boot/dts/*dra7*
 
-OMAP CLOCK FRAMEWORK SUPPORT
-M:     Paul Walmsley <paul@pwsan.com>
-L:     linux-omap@vger.kernel.org
-S:     Maintained
-F:     arch/arm/*omap*/*clock*
-
-OMAP POWER MANAGEMENT SUPPORT
-M:     Kevin Hilman <khilman@kernel.org>
-L:     linux-omap@vger.kernel.org
-S:     Maintained
-F:     arch/arm/*omap*/*pm*
-F:     drivers/cpufreq/omap-cpufreq.c
-
-OMAP POWERDOMAIN SOC ADAPTATION LAYER SUPPORT
-M:     Rajendra Nayak <rnayak@codeaurora.org>
-M:     Paul Walmsley <paul@pwsan.com>
+OMAP DISPLAY SUBSYSTEM and FRAMEBUFFER SUPPORT (DSS2)
+M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
 L:     linux-omap@vger.kernel.org
+L:     linux-fbdev@vger.kernel.org
 S:     Maintained
-F:     arch/arm/mach-omap2/prm*
+F:     drivers/video/fbdev/omap2/
+F:     Documentation/arm/OMAP/DSS
 
-OMAP AUDIO SUPPORT
-M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
-M:     Jarkko Nikula <jarkko.nikula@bitmer.com>
-L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+OMAP FRAMEBUFFER SUPPORT
+M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
+L:     linux-fbdev@vger.kernel.org
 L:     linux-omap@vger.kernel.org
 S:     Maintained
-F:     sound/soc/omap/
+F:     drivers/video/fbdev/omap/
 
 OMAP GENERAL PURPOSE MEMORY CONTROLLER SUPPORT
 M:     Roger Quadros <rogerq@ti.com>
@@ -9565,20 +9547,14 @@ S:      Maintained
 F:     drivers/memory/omap-gpmc.c
 F:     arch/arm/mach-omap2/*gpmc*
 
-OMAP FRAMEBUFFER SUPPORT
-M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
-L:     linux-fbdev@vger.kernel.org
-L:     linux-omap@vger.kernel.org
-S:     Maintained
-F:     drivers/video/fbdev/omap/
-
-OMAP DISPLAY SUBSYSTEM and FRAMEBUFFER SUPPORT (DSS2)
-M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
+OMAP GPIO DRIVER
+M:     Grygorii Strashko <grygorii.strashko@ti.com>
+M:     Santosh Shilimkar <ssantosh@kernel.org>
+M:     Kevin Hilman <khilman@kernel.org>
 L:     linux-omap@vger.kernel.org
-L:     linux-fbdev@vger.kernel.org
 S:     Maintained
-F:     drivers/video/fbdev/omap2/
-F:     Documentation/arm/OMAP/DSS
+F:     Documentation/devicetree/bindings/gpio/gpio-omap.txt
+F:     drivers/gpio/gpio-omap.c
 
 OMAP HARDWARE SPINLOCK SUPPORT
 M:     Ohad Ben-Cohen <ohad@wizery.com>
@@ -9586,30 +9562,12 @@ L:      linux-omap@vger.kernel.org
 S:     Maintained
 F:     drivers/hwspinlock/omap_hwspinlock.c
 
-OMAP MMC SUPPORT
-M:     Jarkko Lavinen <jarkko.lavinen@nokia.com>
-L:     linux-omap@vger.kernel.org
-S:     Maintained
-F:     drivers/mmc/host/omap.c
-
 OMAP HS MMC SUPPORT
 L:     linux-mmc@vger.kernel.org
 L:     linux-omap@vger.kernel.org
 S:     Orphan
 F:     drivers/mmc/host/omap_hsmmc.c
 
-OMAP RANDOM NUMBER GENERATOR SUPPORT
-M:     Deepak Saxena <dsaxena@plexity.net>
-S:     Maintained
-F:     drivers/char/hw_random/omap-rng.c
-
-OMAP HWMOD SUPPORT
-M:     Benoît Cousson <bcousson@baylibre.com>
-M:     Paul Walmsley <paul@pwsan.com>
-L:     linux-omap@vger.kernel.org
-S:     Maintained
-F:     arch/arm/mach-omap2/omap_hwmod.*
-
 OMAP HWMOD DATA
 M:     Paul Walmsley <paul@pwsan.com>
 L:     linux-omap@vger.kernel.org
@@ -9622,6 +9580,13 @@ L:       linux-omap@vger.kernel.org
 S:     Maintained
 F:     arch/arm/mach-omap2/omap_hwmod_44xx_data.c
 
+OMAP HWMOD SUPPORT
+M:     Benoît Cousson <bcousson@baylibre.com>
+M:     Paul Walmsley <paul@pwsan.com>
+L:     linux-omap@vger.kernel.org
+S:     Maintained
+F:     arch/arm/mach-omap2/omap_hwmod.*
+
 OMAP IMAGING SUBSYSTEM (OMAP3 ISP and OMAP4 ISS)
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
@@ -9630,6 +9595,31 @@ F:       Documentation/devicetree/bindings/media/ti,omap3isp.txt
 F:     drivers/media/platform/omap3isp/
 F:     drivers/staging/media/omap4iss/
 
+OMAP MMC SUPPORT
+M:     Jarkko Lavinen <jarkko.lavinen@nokia.com>
+L:     linux-omap@vger.kernel.org
+S:     Maintained
+F:     drivers/mmc/host/omap.c
+
+OMAP POWER MANAGEMENT SUPPORT
+M:     Kevin Hilman <khilman@kernel.org>
+L:     linux-omap@vger.kernel.org
+S:     Maintained
+F:     arch/arm/*omap*/*pm*
+F:     drivers/cpufreq/omap-cpufreq.c
+
+OMAP POWERDOMAIN SOC ADAPTATION LAYER SUPPORT
+M:     Rajendra Nayak <rnayak@codeaurora.org>
+M:     Paul Walmsley <paul@pwsan.com>
+L:     linux-omap@vger.kernel.org
+S:     Maintained
+F:     arch/arm/mach-omap2/prm*
+
+OMAP RANDOM NUMBER GENERATOR SUPPORT
+M:     Deepak Saxena <dsaxena@plexity.net>
+S:     Maintained
+F:     drivers/char/hw_random/omap-rng.c
+
 OMAP USB SUPPORT
 L:     linux-usb@vger.kernel.org
 L:     linux-omap@vger.kernel.org
@@ -9637,20 +9627,56 @@ S:      Orphan
 F:     drivers/usb/*/*omap*
 F:     arch/arm/*omap*/usb*
 
-OMAP GPIO DRIVER
-M:     Grygorii Strashko <grygorii.strashko@ti.com>
-M:     Santosh Shilimkar <ssantosh@kernel.org>
-M:     Kevin Hilman <khilman@kernel.org>
+OMAP/NEWFLOW NANOBONE MACHINE SUPPORT
+M:     Mark Jackson <mpfj@newflow.co.uk>
+L:     linux-omap@vger.kernel.org
+S:     Maintained
+F:     arch/arm/boot/dts/am335x-nano.dts
+
+OMAP1 SUPPORT
+M:     Aaro Koskinen <aaro.koskinen@iki.fi>
+M:     Tony Lindgren <tony@atomide.com>
 L:     linux-omap@vger.kernel.org
+Q:     http://patchwork.kernel.org/project/linux-omap/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git
 S:     Maintained
-F:     Documentation/devicetree/bindings/gpio/gpio-omap.txt
-F:     drivers/gpio/gpio-omap.c
+F:     arch/arm/mach-omap1/
+F:     arch/arm/plat-omap/
+F:     arch/arm/configs/omap1_defconfig
+F:     drivers/i2c/busses/i2c-omap.c
+F:     include/linux/i2c-omap.h
 
-OMAP/NEWFLOW NANOBONE MACHINE SUPPORT
-M:     Mark Jackson <mpfj@newflow.co.uk>
+OMAP2+ SUPPORT
+M:     Tony Lindgren <tony@atomide.com>
 L:     linux-omap@vger.kernel.org
+W:     http://www.muru.com/linux/omap/
+W:     http://linux.omap.com/
+Q:     http://patchwork.kernel.org/project/linux-omap/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git
 S:     Maintained
-F:     arch/arm/boot/dts/am335x-nano.dts
+F:     arch/arm/mach-omap2/
+F:     arch/arm/plat-omap/
+F:     arch/arm/configs/omap2plus_defconfig
+F:     drivers/i2c/busses/i2c-omap.c
+F:     drivers/irqchip/irq-omap-intc.c
+F:     drivers/mfd/*omap*.c
+F:     drivers/mfd/menelaus.c
+F:     drivers/mfd/palmas.c
+F:     drivers/mfd/tps65217.c
+F:     drivers/mfd/tps65218.c
+F:     drivers/mfd/tps65910.c
+F:     drivers/mfd/twl-core.[ch]
+F:     drivers/mfd/twl4030*.c
+F:     drivers/mfd/twl6030*.c
+F:     drivers/mfd/twl6040*.c
+F:     drivers/regulator/palmas-regulator*.c
+F:     drivers/regulator/pbias-regulator.c
+F:     drivers/regulator/tps65217-regulator.c
+F:     drivers/regulator/tps65218-regulator.c
+F:     drivers/regulator/tps65910-regulator.c
+F:     drivers/regulator/twl-regulator.c
+F:     drivers/regulator/twl6030-regulator.c
+F:     include/linux/i2c-omap.h
 
 OMFS FILESYSTEM
 M:     Bob Copeland <me@bobcopeland.com>
@@ -9671,6 +9697,13 @@ M:       Harald Welte <laforge@gnumonks.org>
 S:     Maintained
 F:     drivers/char/pcmcia/cm4040_cs.*
 
+OMNIVISION OV13858 SENSOR DRIVER
+M:     Sakari Ailus <sakari.ailus@linux.intel.com>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Maintained
+F:     drivers/media/i2c/ov13858.c
+
 OMNIVISION OV5640 SENSOR DRIVER
 M:     Steve Longerbeam <slongerbeam@gmail.com>
 L:     linux-media@vger.kernel.org
@@ -9693,13 +9726,6 @@ S:       Maintained
 F:     drivers/media/i2c/ov7670.c
 F:     Documentation/devicetree/bindings/media/i2c/ov7670.txt
 
-OMNIVISION OV13858 SENSOR DRIVER
-M:     Sakari Ailus <sakari.ailus@linux.intel.com>
-L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
-F:     drivers/media/i2c/ov13858.c
-
 ONENAND FLASH DRIVER
 M:     Kyungmin Park <kyungmin.park@samsung.com>
 L:     linux-mtd@lists.infradead.org
@@ -9717,12 +9743,26 @@ F:      drivers/scsi/osst.*
 F:     drivers/scsi/osst_*.h
 F:     drivers/scsi/st.h
 
-OPENCORES I2C BUS DRIVER
-M:     Peter Korsgaard <jacmet@sunsite.dk>
-L:     linux-i2c@vger.kernel.org
+OP-TEE DRIVER
+M:     Jens Wiklander <jens.wiklander@linaro.org>
 S:     Maintained
-F:     Documentation/i2c/busses/i2c-ocores
-F:     drivers/i2c/busses/i2c-ocores.c
+F:     drivers/tee/optee/
+
+OPA-VNIC DRIVER
+M:     Dennis Dalessandro <dennis.dalessandro@intel.com>
+M:     Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
+L:     linux-rdma@vger.kernel.org
+S:     Supported
+F:     drivers/infiniband/ulp/opa_vnic
+
+OPEN FIRMWARE AND DEVICE TREE OVERLAYS
+M:     Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+L:     devicetree@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/dynamic-resolution-notes.txt
+F:     Documentation/devicetree/overlay-notes.txt
+F:     drivers/of/overlay.c
+F:     drivers/of/resolver.c
 
 OPEN FIRMWARE AND FLATTENED DEVICE TREE
 M:     Rob Herring <robh+dt@kernel.org>
@@ -9747,14 +9787,12 @@ F:      Documentation/devicetree/
 F:     arch/*/boot/dts/
 F:     include/dt-bindings/
 
-OPEN FIRMWARE AND DEVICE TREE OVERLAYS
-M:     Pantelis Antoniou <pantelis.antoniou@konsulko.com>
-L:     devicetree@vger.kernel.org
+OPENCORES I2C BUS DRIVER
+M:     Peter Korsgaard <jacmet@sunsite.dk>
+L:     linux-i2c@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/dynamic-resolution-notes.txt
-F:     Documentation/devicetree/overlay-notes.txt
-F:     drivers/of/overlay.c
-F:     drivers/of/resolver.c
+F:     Documentation/i2c/busses/i2c-ocores
+F:     drivers/i2c/busses/i2c-ocores.c
 
 OPENRISC ARCHITECTURE
 M:     Jonas Bonn <jonas@southpole.se>
@@ -9803,11 +9841,6 @@ F:       arch/*/oprofile/
 F:     drivers/oprofile/
 F:     include/linux/oprofile.h
 
-OP-TEE DRIVER
-M:     Jens Wiklander <jens.wiklander@linaro.org>
-S:     Maintained
-F:     drivers/tee/optee/
-
 ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
 M:     Mark Fasheh <mfasheh@versity.com>
 M:     Joel Becker <jlbec@evilplan.org>
@@ -9818,6 +9851,14 @@ F:       Documentation/filesystems/ocfs2.txt
 F:     Documentation/filesystems/dlmfs.txt
 F:     fs/ocfs2/
 
+ORANGEFS FILESYSTEM
+M:     Mike Marshall <hubcap@omnibond.com>
+L:     pvfs2-developers@beowulf-underground.org (subscribers-only)
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git
+S:     Supported
+F:     fs/orangefs/
+F:     Documentation/filesystems/orangefs.txt
+
 ORINOCO DRIVER
 L:     linux-wireless@vger.kernel.org
 W:     http://wireless.kernel.org/en/users/Drivers/orinoco
@@ -9832,6 +9873,16 @@ F:       drivers/scsi/osd/
 F:     include/scsi/osd_*
 F:     fs/exofs/
 
+OV2659 OMNIVISION SENSOR DRIVER
+M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
+L:     linux-media@vger.kernel.org
+W:     https://linuxtv.org
+Q:     http://patchwork.linuxtv.org/project/linux-media/list/
+T:     git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
+S:     Maintained
+F:     drivers/media/i2c/ov2659.c
+F:     include/media/i2c/ov2659.h
+
 OVERLAY FILESYSTEM
 M:     Miklos Szeredi <miklos@szeredi.hu>
 L:     linux-unionfs@vger.kernel.org
@@ -9840,14 +9891,6 @@ S:       Supported
 F:     fs/overlayfs/
 F:     Documentation/filesystems/overlayfs.txt
 
-ORANGEFS FILESYSTEM
-M:     Mike Marshall <hubcap@omnibond.com>
-L:     pvfs2-developers@beowulf-underground.org (subscribers-only)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git
-S:     Supported
-F:     fs/orangefs/
-F:     Documentation/filesystems/orangefs.txt
-
 P54 WIRELESS DRIVER
 M:     Christian Lamparter <chunkeey@googlemail.com>
 L:     linux-wireless@vger.kernel.org
@@ -9888,11 +9931,11 @@ F:      Documentation/mn10300/
 F:     arch/mn10300/
 
 PARALLEL LCD/KEYPAD PANEL DRIVER
-M:      Willy Tarreau <willy@haproxy.com>
-M:      Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
-S:      Odd Fixes
-F:      Documentation/misc-devices/lcd-panel-cgram.txt
-F:      drivers/misc/panel.c
+M:     Willy Tarreau <willy@haproxy.com>
+M:     Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
+S:     Odd Fixes
+F:     Documentation/misc-devices/lcd-panel-cgram.txt
+F:     drivers/misc/panel.c
 
 PARALLEL PORT SUBSYSTEM
 M:     Sudip Mukherjee <sudipm.mukherjee@gmail.com>
@@ -9988,42 +10031,13 @@ M:     Khalid Aziz <khalid@gonehiking.org>
 S:     Maintained
 F:     drivers/firmware/pcdp.*
 
-PCI ERROR RECOVERY
-M:     Linas Vepstas <linasvepstas@gmail.com>
-L:     linux-pci@vger.kernel.org
-S:     Supported
-F:     Documentation/PCI/pci-error-recovery.txt
-
-PCI ENHANCED ERROR HANDLING (EEH) FOR POWERPC
-M:     Russell Currey <ruscur@russell.cc>
-L:     linuxppc-dev@lists.ozlabs.org
-S:     Supported
-F:     Documentation/powerpc/eeh-pci-error-recovery.txt
-F:     arch/powerpc/kernel/eeh*.c
-F:     arch/powerpc/platforms/*/eeh*.c
-F:     arch/powerpc/include/*/eeh*.h
-
-PCI SUBSYSTEM
-M:     Bjorn Helgaas <bhelgaas@google.com>
-L:     linux-pci@vger.kernel.org
-Q:     http://patchwork.ozlabs.org/project/linux-pci/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
-S:     Supported
-F:     Documentation/devicetree/bindings/pci/
-F:     Documentation/PCI/
-F:     drivers/pci/
-F:     include/linux/pci*
-F:     arch/x86/pci/
-F:     arch/x86/kernel/quirks.c
-
-PCI ENDPOINT SUBSYSTEM
-M:     Kishon Vijay Abraham I <kishon@ti.com>
+PCI DRIVER FOR AARDVARK (Marvell Armada 3700)
+M:     Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
 L:     linux-pci@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/pci-endpoint.git
-S:     Supported
-F:     drivers/pci/endpoint/
-F:     drivers/misc/pci_endpoint_test.c
-F:     tools/pci/
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/devicetree/bindings/pci/aardvark-pci.txt
+F:     drivers/pci/host/pci-aardvark.c
 
 PCI DRIVER FOR ALTERA PCIE IP
 M:     Ley Foon Tan <lftan@altera.com>
@@ -10033,6 +10047,14 @@ S:     Supported
 F:     Documentation/devicetree/bindings/pci/altera-pcie.txt
 F:     drivers/pci/host/pcie-altera.c
 
+PCI DRIVER FOR APPLIEDMICRO XGENE
+M:     Tanmay Inamdar <tinamdar@apm.com>
+L:     linux-pci@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/pci/xgene-pci.txt
+F:     drivers/pci/host/pci-xgene.c
+
 PCI DRIVER FOR ARM VERSATILE PLATFORM
 M:     Rob Herring <robh@kernel.org>
 L:     linux-pci@vger.kernel.org
@@ -10049,14 +10071,6 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/pci/pci-armada8k.txt
 F:     drivers/pci/dwc/pcie-armada8k.c
 
-PCI DRIVER FOR APPLIEDMICRO XGENE
-M:     Tanmay Inamdar <tinamdar@apm.com>
-L:     linux-pci@vger.kernel.org
-L:     linux-arm-kernel@lists.infradead.org
-S:     Maintained
-F:     Documentation/devicetree/bindings/pci/xgene-pci.txt
-F:     drivers/pci/host/pci-xgene.c
-
 PCI DRIVER FOR FREESCALE LAYERSCAPE
 M:     Minghuan Lian <minghuan.Lian@freescale.com>
 M:     Mingkai Hu <mingkai.hu@freescale.com>
@@ -10067,6 +10081,15 @@ L:     linux-arm-kernel@lists.infradead.org
 S:     Maintained
 F:     drivers/pci/dwc/*layerscape*
 
+PCI DRIVER FOR GENERIC OF HOSTS
+M:     Will Deacon <will.deacon@arm.com>
+L:     linux-pci@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/devicetree/bindings/pci/host-generic-pci.txt
+F:     drivers/pci/host/pci-host-common.c
+F:     drivers/pci/host/pci-host-generic.c
+
 PCI DRIVER FOR IMX6
 M:     Richard Zhu <hongxing.zhu@nxp.com>
 M:     Lucas Stach <l.stach@pengutronix.de>
@@ -10076,28 +10099,11 @@ S:    Maintained
 F:     Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt
 F:     drivers/pci/dwc/*imx6*
 
-PCI DRIVER FOR TI KEYSTONE
-M:     Murali Karicheri <m-karicheri2@ti.com>
-L:     linux-pci@vger.kernel.org
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     drivers/pci/dwc/*keystone*
-
-PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
-M:     Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
-M:     Jason Cooper <jason@lakedaemon.net>
-L:     linux-pci@vger.kernel.org
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     drivers/pci/host/*mvebu*
-
-PCI DRIVER FOR AARDVARK (Marvell Armada 3700)
-M:     Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+PCI DRIVER FOR INTEL VOLUME MANAGEMENT DEVICE (VMD)
+M:     Keith Busch <keith.busch@intel.com>
 L:     linux-pci@vger.kernel.org
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     Documentation/devicetree/bindings/pci/aardvark-pci.txt
-F:     drivers/pci/host/pci-aardvark.c
+S:     Supported
+F:     drivers/pci/host/vmd.c
 
 PCI DRIVER FOR MICROSEMI SWITCHTEC
 M:     Kurt Schwemmer <kurt.schwemmer@microsemi.com>
@@ -10110,6 +10116,14 @@ F:     Documentation/ABI/testing/sysfs-class-switchtec
 F:     drivers/pci/switch/switchtec*
 F:     include/uapi/linux/switchtec_ioctl.h
 
+PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
+M:     Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+M:     Jason Cooper <jason@lakedaemon.net>
+L:     linux-pci@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     drivers/pci/host/*mvebu*
+
 PCI DRIVER FOR NVIDIA TEGRA
 M:     Thierry Reding <thierry.reding@gmail.com>
 L:     linux-tegra@vger.kernel.org
@@ -10118,14 +10132,6 @@ 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/dwc/pci-dra7xx.c
-
 PCI DRIVER FOR RENESAS R-CAR
 M:     Simon Horman <horms@verge.net.au>
 L:     linux-pci@vger.kernel.org
@@ -10149,26 +10155,44 @@ S:    Maintained
 F:     Documentation/devicetree/bindings/pci/designware-pcie.txt
 F:     drivers/pci/dwc/*designware*
 
-PCI DRIVER FOR GENERIC OF HOSTS
-M:     Will Deacon <will.deacon@arm.com>
+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/dwc/pci-dra7xx.c
+
+PCI DRIVER FOR TI KEYSTONE
+M:     Murali Karicheri <m-karicheri2@ti.com>
 L:     linux-pci@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     Documentation/devicetree/bindings/pci/host-generic-pci.txt
-F:     drivers/pci/host/pci-host-common.c
-F:     drivers/pci/host/pci-host-generic.c
+F:     drivers/pci/dwc/*keystone*
 
-PCI DRIVER FOR INTEL VOLUME MANAGEMENT DEVICE (VMD)
-M:     Keith Busch <keith.busch@intel.com>
+PCI ENDPOINT SUBSYSTEM
+M:     Kishon Vijay Abraham I <kishon@ti.com>
 L:     linux-pci@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/pci-endpoint.git
+S:     Supported
+F:     drivers/pci/endpoint/
+F:     drivers/misc/pci_endpoint_test.c
+F:     tools/pci/
+
+PCI ENHANCED ERROR HANDLING (EEH) FOR POWERPC
+M:     Russell Currey <ruscur@russell.cc>
+L:     linuxppc-dev@lists.ozlabs.org
 S:     Supported
-F:     drivers/pci/host/vmd.c
+F:     Documentation/powerpc/eeh-pci-error-recovery.txt
+F:     arch/powerpc/kernel/eeh*.c
+F:     arch/powerpc/platforms/*/eeh*.c
+F:     arch/powerpc/include/*/eeh*.h
 
-PCIE DRIVER FOR ST SPEAR13XX
-M:     Pratyush Anand <pratyush.anand@gmail.com>
+PCI ERROR RECOVERY
+M:     Linas Vepstas <linasvepstas@gmail.com>
 L:     linux-pci@vger.kernel.org
-S:     Maintained
-F:     drivers/pci/dwc/*spear*
+S:     Supported
+F:     Documentation/PCI/pci-error-recovery.txt
 
 PCI MSI DRIVER FOR ALTERA MSI IP
 M:     Ley Foon Tan <lftan@altera.com>
@@ -10186,6 +10210,19 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
 F:     drivers/pci/host/pci-xgene-msi.c
 
+PCI SUBSYSTEM
+M:     Bjorn Helgaas <bhelgaas@google.com>
+L:     linux-pci@vger.kernel.org
+Q:     http://patchwork.ozlabs.org/project/linux-pci/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
+S:     Supported
+F:     Documentation/devicetree/bindings/pci/
+F:     Documentation/PCI/
+F:     drivers/pci/
+F:     include/linux/pci*
+F:     arch/x86/pci/
+F:     arch/x86/kernel/quirks.c
+
 PCIE DRIVER FOR AXIS ARTPEC
 M:     Niklas Cassel <niklas.cassel@axis.com>
 M:     Jesper Nilsson <jesper.nilsson@axis.com>
@@ -10195,6 +10232,14 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/pci/axis,artpec*
 F:     drivers/pci/dwc/*artpec*
 
+PCIE DRIVER FOR CAVIUM THUNDERX
+M:     David Daney <david.daney@cavium.com>
+L:     linux-pci@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Supported
+F:     Documentation/devicetree/bindings/pci/pci-thunder-*
+F:     drivers/pci/host/pci-thunder-*
+
 PCIE DRIVER FOR HISILICON
 M:     Zhou Wang <wangzhou1@hisilicon.com>
 M:     Gabriele Paoloni <gabriele.paoloni@huawei.com>
@@ -10211,6 +10256,21 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/pci/pcie-kirin.txt
 F:     drivers/pci/dwc/pcie-kirin.c
 
+PCIE DRIVER FOR MEDIATEK
+M:     Ryder Lee <ryder.lee@mediatek.com>
+L:     linux-pci@vger.kernel.org
+L:     linux-mediatek@lists.infradead.org
+S:     Supported
+F:     Documentation/devicetree/bindings/pci/mediatek*
+F:     drivers/pci/host/*mediatek*
+
+PCIE DRIVER FOR QUALCOMM MSM
+M:     Stanimir Varbanov <svarbanov@mm-sol.com>
+L:     linux-pci@vger.kernel.org
+L:     linux-arm-msm@vger.kernel.org
+S:     Maintained
+F:     drivers/pci/dwc/*qcom*
+
 PCIE DRIVER FOR ROCKCHIP
 M:     Shawn Lin <shawn.lin@rock-chips.com>
 L:     linux-pci@vger.kernel.org
@@ -10219,28 +10279,11 @@ S:    Maintained
 F:     Documentation/devicetree/bindings/pci/rockchip-pcie.txt
 F:     drivers/pci/host/pcie-rockchip.c
 
-PCIE DRIVER FOR QUALCOMM MSM
-M:     Stanimir Varbanov <svarbanov@mm-sol.com>
-L:     linux-pci@vger.kernel.org
-L:     linux-arm-msm@vger.kernel.org
-S:     Maintained
-F:     drivers/pci/dwc/*qcom*
-
-PCIE DRIVER FOR CAVIUM THUNDERX
-M:     David Daney <david.daney@cavium.com>
+PCIE DRIVER FOR ST SPEAR13XX
+M:     Pratyush Anand <pratyush.anand@gmail.com>
 L:     linux-pci@vger.kernel.org
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Supported
-F:     Documentation/devicetree/bindings/pci/pci-thunder-*
-F:     drivers/pci/host/pci-thunder-*
-
-PCIE DRIVER FOR MEDIATEK
-M:      Ryder Lee <ryder.lee@mediatek.com>
-L:      linux-pci@vger.kernel.org
-L:      linux-mediatek@lists.infradead.org
-S:      Supported
-F:      Documentation/devicetree/bindings/pci/mediatek*
-F:      drivers/pci/host/*mediatek*
+S:     Maintained
+F:     drivers/pci/dwc/*spear*
 
 PCMCIA SUBSYSTEM
 P:     Linux PCMCIA Team
@@ -10409,14 +10452,14 @@ S:    Maintained
 F:     drivers/pinctrl/spear/
 
 PISTACHIO SOC SUPPORT
-M:      James Hartley <james.hartley@imgtec.com>
-M:      Ionela Voinescu <ionela.voinescu@imgtec.com>
-L:      linux-mips@linux-mips.org
-S:      Maintained
-F:      arch/mips/pistachio/
-F:      arch/mips/include/asm/mach-pistachio/
-F:      arch/mips/boot/dts/img/pistachio*
-F:      arch/mips/configs/pistachio*_defconfig
+M:     James Hartley <james.hartley@imgtec.com>
+M:     Ionela Voinescu <ionela.voinescu@imgtec.com>
+L:     linux-mips@linux-mips.org
+S:     Maintained
+F:     arch/mips/pistachio/
+F:     arch/mips/include/asm/mach-pistachio/
+F:     arch/mips/boot/dts/img/pistachio*
+F:     arch/mips/configs/pistachio*_defconfig
 
 PKTCDVD DRIVER
 S:     Orphan
@@ -10459,6 +10502,11 @@ L:     linux-scsi@vger.kernel.org
 S:     Supported
 F:     drivers/scsi/pm8001/
 
+PNP SUPPORT
+M:     "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+S:     Maintained
+F:     drivers/pnp/
+
 POSIX CLOCKS and TIMERS
 M:     Thomas Gleixner <tglx@linutronix.de>
 L:     linux-kernel@vger.kernel.org
@@ -10480,15 +10528,6 @@ F:     include/linux/pm_*
 F:     include/linux/powercap.h
 F:     drivers/powercap/
 
-POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
-M:     Sebastian Reichel <sre@kernel.org>
-L:     linux-pm@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
-S:     Maintained
-F:     Documentation/devicetree/bindings/power/supply/
-F:     include/linux/power_supply.h
-F:     drivers/power/supply/
-
 POWER STATE COORDINATION INTERFACE (PSCI)
 M:     Mark Rutland <mark.rutland@arm.com>
 M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
@@ -10498,23 +10537,21 @@ F:    drivers/firmware/psci*.c
 F:     include/linux/psci.h
 F:     include/uapi/linux/psci.h
 
+POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
+M:     Sebastian Reichel <sre@kernel.org>
+L:     linux-pm@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
+S:     Maintained
+F:     Documentation/devicetree/bindings/power/supply/
+F:     include/linux/power_supply.h
+F:     drivers/power/supply/
+
 POWERNV OPERATOR PANEL LCD DISPLAY DRIVER
 M:     Suraj Jitindar Singh <sjitindarsingh@gmail.com>
 L:     linuxppc-dev@lists.ozlabs.org
 S:     Maintained
 F:     drivers/char/powernv-op-panel.c
 
-PNP SUPPORT
-M:     "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
-S:     Maintained
-F:     drivers/pnp/
-
-PPP PROTOCOL DRIVERS AND COMPRESSORS
-M:     Paul Mackerras <paulus@samba.org>
-L:     linux-ppp@vger.kernel.org
-S:     Maintained
-F:     drivers/net/ppp/ppp_*
-
 PPP OVER ATM (RFC 2364)
 M:     Mitchell Blank Jr <mitch@sfgoth.com>
 S:     Maintained
@@ -10534,6 +10571,12 @@ F:     net/l2tp/l2tp_ppp.c
 F:     include/linux/if_pppol2tp.h
 F:     include/uapi/linux/if_pppol2tp.h
 
+PPP PROTOCOL DRIVERS AND COMPRESSORS
+M:     Paul Mackerras <paulus@samba.org>
+L:     linux-ppp@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ppp/ppp_*
+
 PPS SUPPORT
 M:     Rodolfo Giometti <giometti@enneenne.com>
 W:     http://wiki.enneenne.com/index.php/LinuxPPS_support
@@ -10647,7 +10690,6 @@ F:      drivers/ptp/*
 F:     include/linux/ptp_cl*
 
 PTRACE SUPPORT
-M:     Roland McGrath <roland@hack.frob.com>
 M:     Oleg Nesterov <oleg@redhat.com>
 S:     Maintained
 F:     include/asm-generic/syscall.h
@@ -10655,7 +10697,12 @@ F:     include/linux/ptrace.h
 F:     include/linux/regset.h
 F:     include/linux/tracehook.h
 F:     include/uapi/linux/ptrace.h
+F:     include/uapi/linux/ptrace.h
+F:     include/asm-generic/ptrace.h
 F:     kernel/ptrace.c
+F:     arch/*/ptrace*.c
+F:     arch/*/*/ptrace*.c
+F:     arch/*/include/asm/ptrace*.h
 
 PULSE8-CEC DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
@@ -10704,6 +10751,20 @@ F:     include/linux/pwm_backlight.h
 F:     drivers/gpio/gpio-mvebu.c
 F:     Documentation/devicetree/bindings/gpio/gpio-mvebu.txt
 
+PXA GPIO DRIVER
+M:     Robert Jarzmik <robert.jarzmik@free.fr>
+L:     linux-gpio@vger.kernel.org
+S:     Maintained
+F:     drivers/gpio/gpio-pxa.c
+
+PXA MMCI DRIVER
+S:     Orphan
+
+PXA RTC DRIVER
+M:     Robert Jarzmik <robert.jarzmik@free.fr>
+L:     linux-rtc@vger.kernel.org
+S:     Maintained
+
 PXA2xx/PXA3xx SUPPORT
 M:     Daniel Mack <daniel@zonque.org>
 M:     Haojian Zhuang <haojian.zhuang@gmail.com>
@@ -10723,36 +10784,12 @@ F:    include/sound/pxa2xx-lib.h
 F:     sound/arm/pxa*
 F:     sound/soc/pxa/
 
-PXA GPIO DRIVER
-M:     Robert Jarzmik <robert.jarzmik@free.fr>
-L:     linux-gpio@vger.kernel.org
-S:     Maintained
-F:     drivers/gpio/gpio-pxa.c
-
 PXA3xx NAND FLASH DRIVER
 M:     Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
 L:     linux-mtd@lists.infradead.org
 S:     Maintained
 F:     drivers/mtd/nand/pxa3xx_nand.c
 
-MMP SUPPORT
-M:     Eric Miao <eric.y.miao@gmail.com>
-M:     Haojian Zhuang <haojian.zhuang@gmail.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://github.com/hzhuang1/linux.git
-T:     git git://git.linaro.org/people/ycmiao/pxa-linux.git
-S:     Maintained
-F:     arch/arm/boot/dts/mmp*
-F:     arch/arm/mach-mmp/
-
-PXA MMCI DRIVER
-S:     Orphan
-
-PXA RTC DRIVER
-M:     Robert Jarzmik <robert.jarzmik@free.fr>
-L:     linux-rtc@vger.kernel.org
-S:     Maintained
-
 QAT DRIVER
 M:     Giovanni Cabiddu <giovanni.cabiddu@intel.com>
 M:     Salvatore Benedetto <salvatore.benedetto@intel.com>
@@ -10760,12 +10797,56 @@ L:    qat-linux@intel.com
 S:     Supported
 F:     drivers/crypto/qat/
 
+QCOM AUDIO (ASoC) DRIVERS
+M:     Patrick Lai <plai@codeaurora.org>
+M:     Banajit Goswami <bgoswami@codeaurora.org>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Supported
+F:     sound/soc/qcom/
+
+QEMU MACHINE EMULATOR AND VIRTUALIZER SUPPORT
+M:     Gabriel Somlo <somlo@cmu.edu>
+M:     "Michael S. Tsirkin" <mst@redhat.com>
+L:     qemu-devel@nongnu.org
+S:     Maintained
+F:     drivers/firmware/qemu_fw_cfg.c
+
 QIB DRIVER
 M:     Mike Marciniszyn <infinipath@intel.com>
 L:     linux-rdma@vger.kernel.org
 S:     Supported
 F:     drivers/infiniband/hw/qib/
 
+QLOGIC QL41xxx FCOE DRIVER
+M:     QLogic-Storage-Upstream@cavium.com
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+F:     drivers/scsi/qedf/
+
+QLOGIC QL41xxx ISCSI DRIVER
+M:     QLogic-Storage-Upstream@cavium.com
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+F:     drivers/scsi/qedi/
+
+QLOGIC QL4xxx ETHERNET DRIVER
+M:     Yuval Mintz <Yuval.Mintz@cavium.com>
+M:     Ariel Elior <Ariel.Elior@cavium.com>
+M:     everest-linux-l2@cavium.com
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/ethernet/qlogic/qed/
+F:     include/linux/qed/
+F:     drivers/net/ethernet/qlogic/qede/
+
+QLOGIC QL4xxx RDMA DRIVER
+M:     Ram Amrani <Ram.Amrani@cavium.com>
+M:     Ariel Elior <Ariel.Elior@cavium.com>
+L:     linux-rdma@vger.kernel.org
+S:     Supported
+F:     drivers/infiniband/hw/qedr/
+F:     include/uapi/rdma/qedr-abi.h
+
 QLOGIC QLA1280 SCSI DRIVER
 M:     Michael Reed <mdr@sgi.com>
 L:     linux-scsi@vger.kernel.org
@@ -10779,13 +10860,6 @@ S:     Supported
 F:     Documentation/scsi/LICENSE.qla2xxx
 F:     drivers/scsi/qla2xxx/
 
-QLOGIC QLA4XXX iSCSI DRIVER
-M:     QLogic-Storage-Upstream@qlogic.com
-L:     linux-scsi@vger.kernel.org
-S:     Supported
-F:     Documentation/scsi/LICENSE.qla4xxx
-F:     drivers/scsi/qla4xxx/
-
 QLOGIC QLA3XXX NETWORK DRIVER
 M:     Dept-GELinuxNICDev@cavium.com
 L:     netdev@vger.kernel.org
@@ -10793,6 +10867,13 @@ S:     Supported
 F:     Documentation/networking/LICENSE.qla3xxx
 F:     drivers/net/ethernet/qlogic/qla3xxx.*
 
+QLOGIC QLA4XXX iSCSI DRIVER
+M:     QLogic-Storage-Upstream@qlogic.com
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+F:     Documentation/scsi/LICENSE.qla4xxx
+F:     drivers/scsi/qla4xxx/
+
 QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
 M:     Harish Patil <harish.patil@cavium.com>
 M:     Manish Chopra <manish.chopra@cavium.com>
@@ -10809,28 +10890,6 @@ L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/qlogic/qlge/
 
-QLOGIC QL4xxx ETHERNET DRIVER
-M:     Yuval Mintz <Yuval.Mintz@cavium.com>
-M:     Ariel Elior <Ariel.Elior@cavium.com>
-M:     everest-linux-l2@cavium.com
-L:     netdev@vger.kernel.org
-S:     Supported
-F:     drivers/net/ethernet/qlogic/qed/
-F:     include/linux/qed/
-F:     drivers/net/ethernet/qlogic/qede/
-
-QLOGIC QL41xxx ISCSI DRIVER
-M:     QLogic-Storage-Upstream@cavium.com
-L:     linux-scsi@vger.kernel.org
-S:     Supported
-F:     drivers/scsi/qedi/
-
-QLOGIC QL41xxx FCOE DRIVER
-M:     QLogic-Storage-Upstream@cavium.com
-L:     linux-scsi@vger.kernel.org
-S:     Supported
-F:     drivers/scsi/qedf/
-
 QNX4 FILESYSTEM
 M:     Anders Larsen <al@alarsen.net>
 W:     http://www.alarsen.net/linux/qnx4fs/
@@ -10857,13 +10916,6 @@ T:     git git://linuxtv.org/anttip/media_tree.git
 S:     Maintained
 F:     drivers/media/tuners/qt1010*
 
-QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
-M:     QCA ath9k Development <ath9k-devel@qca.qualcomm.com>
-L:     linux-wireless@vger.kernel.org
-W:     http://wireless.kernel.org/en/users/Drivers/ath9k
-S:     Supported
-F:     drivers/net/wireless/ath/ath9k/
-
 QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
 M:     Kalle Valo <kvalo@qca.qualcomm.com>
 L:     ath10k@lists.infradead.org
@@ -10872,6 +10924,13 @@ T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
 S:     Supported
 F:     drivers/net/wireless/ath/ath10k/
 
+QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
+M:     QCA ath9k Development <ath9k-devel@qca.qualcomm.com>
+L:     linux-wireless@vger.kernel.org
+W:     http://wireless.kernel.org/en/users/Drivers/ath9k
+S:     Supported
+F:     drivers/net/wireless/ath/ath9k/
+
 QUALCOMM EMAC GIGABIT ETHERNET DRIVER
 M:     Timur Tabi <timur@codeaurora.org>
 L:     netdev@vger.kernel.org
@@ -10901,33 +10960,24 @@ T:    git git://github.com/KrasnikovEugene/wcn36xx.git
 S:     Supported
 F:     drivers/net/wireless/ath/wcn36xx/
 
-QEMU MACHINE EMULATOR AND VIRTUALIZER SUPPORT
-M:     Gabriel Somlo <somlo@cmu.edu>
-M:     "Michael S. Tsirkin" <mst@redhat.com>
-L:     qemu-devel@nongnu.org
-S:     Maintained
-F:     drivers/firmware/qemu_fw_cfg.c
-
 QUANTENNA QTNFMAC WIRELESS DRIVER
-M:   Igor Mitsyanko <imitsyanko@quantenna.com>
-M:   Avinash Patil <avinashp@quantenna.com>
-M:   Sergey Matyukevich <smatyukevich@quantenna.com>
-L:   linux-wireless@vger.kernel.org
-S:   Maintained
-F:   drivers/net/wireless/quantenna
+M:     Igor Mitsyanko <imitsyanko@quantenna.com>
+M:     Avinash Patil <avinashp@quantenna.com>
+M:     Sergey Matyukevich <smatyukevich@quantenna.com>
+L:     linux-wireless@vger.kernel.org
+S:     Maintained
+F:     drivers/net/wireless/quantenna
 
-RADOS BLOCK DEVICE (RBD)
-M:     Ilya Dryomov <idryomov@gmail.com>
-M:     Sage Weil <sage@redhat.com>
-M:     Alex Elder <elder@kernel.org>
-L:     ceph-devel@vger.kernel.org
-W:     http://ceph.com/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
-T:     git git://github.com/ceph/ceph-client.git
-S:     Supported
-F:     Documentation/ABI/testing/sysfs-bus-rbd
-F:     drivers/block/rbd.c
-F:     drivers/block/rbd_types.h
+RADEON and AMDGPU DRM DRIVERS
+M:     Alex Deucher <alexander.deucher@amd.com>
+M:     Christian König <christian.koenig@amd.com>
+L:     amd-gfx@lists.freedesktop.org
+T:     git git://people.freedesktop.org/~agd5f/linux
+S:     Supported
+F:     drivers/gpu/drm/radeon/
+F:     include/uapi/drm/radeon_drm.h
+F:     drivers/gpu/drm/amd/
+F:     include/uapi/drm/amdgpu_drm.h
 
 RADEON FRAMEBUFFER DISPLAY DRIVER
 M:     Benjamin Herrenschmidt <benh@kernel.crashing.org>
@@ -10951,6 +11001,19 @@ S:     Maintained
 F:     drivers/media/radio/radio-shark2.c
 F:     drivers/media/radio/radio-tea5777.c
 
+RADOS BLOCK DEVICE (RBD)
+M:     Ilya Dryomov <idryomov@gmail.com>
+M:     Sage Weil <sage@redhat.com>
+M:     Alex Elder <elder@kernel.org>
+L:     ceph-devel@vger.kernel.org
+W:     http://ceph.com/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
+T:     git git://github.com/ceph/ceph-client.git
+S:     Supported
+F:     Documentation/ABI/testing/sysfs-bus-rbd
+F:     drivers/block/rbd.c
+F:     drivers/block/rbd_types.h
+
 RAGE128 FRAMEBUFFER DISPLAY DRIVER
 M:     Paul Mackerras <paulus@samba.org>
 L:     linux-fbdev@vger.kernel.org
@@ -11030,6 +11093,12 @@ L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/rdc/r6040.c
 
+RDMAVT - RDMA verbs software
+M:     Dennis Dalessandro <dennis.dalessandro@intel.com>
+L:     linux-rdma@vger.kernel.org
+S:     Supported
+F:     drivers/infiniband/sw/rdmavt
+
 RDS - RELIABLE DATAGRAM SOCKETS
 M:     Santosh Shilimkar <santosh.shilimkar@oracle.com>
 L:     netdev@vger.kernel.org
@@ -11040,12 +11109,6 @@ S:     Supported
 F:     net/rds/
 F:     Documentation/networking/rds.txt
 
-RDMAVT - RDMA verbs software
-M:     Dennis Dalessandro <dennis.dalessandro@intel.com>
-L:     linux-rdma@vger.kernel.org
-S:     Supported
-F:     drivers/infiniband/sw/rdmavt
-
 RDT - RESOURCE ALLOCATION
 M:     Fenghua Yu <fenghua.yu@intel.com>
 L:     linux-kernel@vger.kernel.org
@@ -11094,11 +11157,6 @@ S:     Maintained
 F:     sound/soc/codecs/rt*
 F:     include/sound/rt*.h
 
-REISERFS FILE SYSTEM
-L:     reiserfs-devel@vger.kernel.org
-S:     Supported
-F:     fs/reiserfs/
-
 REGISTER MAP ABSTRACTION
 M:     Mark Brown <broonie@kernel.org>
 L:     linux-kernel@vger.kernel.org
@@ -11108,6 +11166,11 @@ F:     Documentation/devicetree/bindings/regmap/
 F:     drivers/base/regmap/
 F:     include/linux/regmap.h
 
+REISERFS FILE SYSTEM
+L:     reiserfs-devel@vger.kernel.org
+S:     Supported
+F:     fs/reiserfs/
+
 REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM
 M:     Ohad Ben-Cohen <ohad@wizery.com>
 M:     Bjorn Andersson <bjorn.andersson@linaro.org>
@@ -11183,16 +11246,16 @@ S:    Maintained
 F:     lib/rhashtable.c
 F:     include/linux/rhashtable.h
 
-RICOH SMARTMEDIA/XD DRIVER
+RICOH R5C592 MEMORYSTICK DRIVER
 M:     Maxim Levitsky <maximlevitsky@gmail.com>
 S:     Maintained
-F:     drivers/mtd/nand/r852.c
-F:     drivers/mtd/nand/r852.h
+F:     drivers/memstick/host/r592.*
 
-RICOH R5C592 MEMORYSTICK DRIVER
+RICOH SMARTMEDIA/XD DRIVER
 M:     Maxim Levitsky <maximlevitsky@gmail.com>
 S:     Maintained
-F:     drivers/memstick/host/r592.*
+F:     drivers/mtd/nand/r852.c
+F:     drivers/mtd/nand/r852.h
 
 ROCCAT DRIVERS
 M:     Stefan Achatz <erazor_de@users.sourceforge.net>
@@ -11329,6 +11392,23 @@ S:     Supported
 F:     drivers/s390/block/dasd*
 F:     block/partitions/ibm.c
 
+S390 IOMMU (PCI)
+M:     Gerald Schaefer <gerald.schaefer@de.ibm.com>
+L:     linux-s390@vger.kernel.org
+W:     http://www.ibm.com/developerworks/linux/linux390/
+S:     Supported
+F:     drivers/iommu/s390-iommu.c
+
+S390 IUCV NETWORK LAYER
+M:     Julian Wiedmann <jwi@linux.vnet.ibm.com>
+M:     Ursula Braun <ubraun@linux.vnet.ibm.com>
+L:     linux-s390@vger.kernel.org
+W:     http://www.ibm.com/developerworks/linux/linux390/
+S:     Supported
+F:     drivers/s390/net/*iucv*
+F:     include/net/iucv/
+F:     net/iucv/
+
 S390 NETWORK DRIVERS
 M:     Julian Wiedmann <jwi@linux.vnet.ibm.com>
 M:     Ursula Braun <ubraun@linux.vnet.ibm.com>
@@ -11346,6 +11426,16 @@ S:     Supported
 F:     arch/s390/pci/
 F:     drivers/pci/hotplug/s390_pci_hpc.c
 
+S390 VFIO-CCW DRIVER
+M:     Cornelia Huck <cohuck@redhat.com>
+M:     Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
+L:     linux-s390@vger.kernel.org
+L:     kvm@vger.kernel.org
+S:     Supported
+F:     drivers/s390/cio/vfio_ccw*
+F:     Documentation/s390/vfio-ccw.txt
+F:     include/uapi/linux/vfio_ccw.h
+
 S390 ZCRYPT DRIVER
 M:     Harald Freudenberger <freude@de.ibm.com>
 L:     linux-s390@vger.kernel.org
@@ -11360,33 +11450,6 @@ W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
 F:     drivers/s390/scsi/zfcp_*
 
-S390 IUCV NETWORK LAYER
-M:     Julian Wiedmann <jwi@linux.vnet.ibm.com>
-M:     Ursula Braun <ubraun@linux.vnet.ibm.com>
-L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
-S:     Supported
-F:     drivers/s390/net/*iucv*
-F:     include/net/iucv/
-F:     net/iucv/
-
-S390 IOMMU (PCI)
-M:     Gerald Schaefer <gerald.schaefer@de.ibm.com>
-L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
-S:     Supported
-F:     drivers/iommu/s390-iommu.c
-
-S390 VFIO-CCW DRIVER
-M:     Cornelia Huck <cohuck@redhat.com>
-M:     Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
-L:     linux-s390@vger.kernel.org
-L:     kvm@vger.kernel.org
-S:     Supported
-F:     drivers/s390/cio/vfio_ccw*
-F:     Documentation/s390/vfio-ccw.txt
-F:     include/uapi/linux/vfio_ccw.h
-
 S3C24XX SD/MMC Driver
 M:     Ben Dooks <ben-linux@fluff.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -11420,12 +11483,6 @@ F:     drivers/media/common/saa7146/
 F:     drivers/media/pci/saa7146/
 F:     include/media/saa7146*
 
-SAMSUNG LAPTOP DRIVER
-M:     Corentin Chary <corentin.chary@gmail.com>
-L:     platform-driver-x86@vger.kernel.org
-S:     Maintained
-F:     drivers/platform/x86/samsung-laptop.c
-
 SAMSUNG AUDIO (ASoC) DRIVERS
 M:     Krzysztof Kozlowski <krzk@kernel.org>
 M:     Sangbeom Kim <sbkim73@samsung.com>
@@ -11448,6 +11505,12 @@ L:     linux-fbdev@vger.kernel.org
 S:     Maintained
 F:     drivers/video/fbdev/s3c-fb.c
 
+SAMSUNG LAPTOP DRIVER
+M:     Corentin Chary <corentin.chary@gmail.com>
+L:     platform-driver-x86@vger.kernel.org
+S:     Maintained
+F:     drivers/platform/x86/samsung-laptop.c
+
 SAMSUNG MULTIFUNCTION PMIC DEVICE DRIVERS
 M:     Sangbeom Kim <sbkim73@samsung.com>
 M:     Krzysztof Kozlowski <krzk@kernel.org>
@@ -11466,22 +11529,6 @@ F:     Documentation/devicetree/bindings/regulator/samsung,s2m*.txt
 F:     Documentation/devicetree/bindings/regulator/samsung,s5m*.txt
 F:     Documentation/devicetree/bindings/clock/samsung,s2mps11.txt
 
-SAMSUNG S5P Security SubSystem (SSS) DRIVER
-M:     Krzysztof Kozlowski <krzk@kernel.org>
-M:     Vladimir Zapolskiy <vz@mleia.com>
-L:     linux-crypto@vger.kernel.org
-L:     linux-samsung-soc@vger.kernel.org
-S:     Maintained
-F:     drivers/crypto/s5p-sss.c
-
-SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
-M:     Kyungmin Park <kyungmin.park@samsung.com>
-M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
-L:     linux-media@vger.kernel.org
-Q:     https://patchwork.linuxtv.org/project/linux-media/list/
-S:     Supported
-F:     drivers/media/platform/exynos4-is/
-
 SAMSUNG S3C24XX/S3C64XX SOC SERIES CAMIF DRIVER
 M:     Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
 L:     linux-media@vger.kernel.org
@@ -11490,20 +11537,6 @@ S:     Maintained
 F:     drivers/media/platform/s3c-camif/
 F:     include/media/drv-intf/s3c_camif.h
 
-SAMSUNG S5C73M3 CAMERA DRIVER
-M:     Kyungmin Park <kyungmin.park@samsung.com>
-M:     Andrzej Hajda <a.hajda@samsung.com>
-L:     linux-media@vger.kernel.org
-S:     Supported
-F:     drivers/media/i2c/s5c73m3/*
-
-SAMSUNG S5K5BAF CAMERA DRIVER
-M:     Kyungmin Park <kyungmin.park@samsung.com>
-M:     Andrzej Hajda <a.hajda@samsung.com>
-L:     linux-media@vger.kernel.org
-S:     Supported
-F:     drivers/media/i2c/s5k5baf.c
-
 SAMSUNG S3FWRN5 NFC DRIVER
 M:     Robert Baldyga <r.baldyga@samsung.com>
 M:     Krzysztof Opasiak <k.opasiak@samsung.com>
@@ -11511,176 +11544,86 @@ L:   linux-nfc@lists.01.org (moderated for non-subscribers)
 S:     Supported
 F:     drivers/nfc/s3fwrn5
 
-SAMSUNG SOC CLOCK DRIVERS
-M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
-M:     Tomasz Figa <tomasz.figa@gmail.com>
-M:     Chanwoo Choi <cw00.choi@samsung.com>
-S:     Supported
-L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
-F:     drivers/clk/samsung/
-F:     include/dt-bindings/clock/exynos*.h
-F:     Documentation/devicetree/bindings/clock/exynos*.txt
-
-SAMSUNG SPI DRIVERS
-M:     Kukjin Kim <kgene@kernel.org>
-M:     Krzysztof Kozlowski <krzk@kernel.org>
-M:     Andi Shyti <andi.shyti@samsung.com>
-L:     linux-spi@vger.kernel.org
-L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
-S:     Maintained
-F:     Documentation/devicetree/bindings/spi/spi-samsung.txt
-F:     drivers/spi/spi-s3c*
-F:     include/linux/platform_data/spi-s3c64xx.h
-
-SAMSUNG SXGBE DRIVERS
-M:     Byungho An <bh74.an@samsung.com>
-M:     Girish K S <ks.giri@samsung.com>
-M:     Vipul Pandya <vipul.pandya@samsung.com>
-S:     Supported
-L:     netdev@vger.kernel.org
-F:     drivers/net/ethernet/samsung/sxgbe/
-
-SAMSUNG THERMAL DRIVER
-M:     Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
-L:     linux-pm@vger.kernel.org
-L:     linux-samsung-soc@vger.kernel.org
-S:     Supported
-T:     git https://github.com/lmajewski/linux-samsung-thermal.git
-F:     drivers/thermal/samsung/
-
-SAMSUNG USB2 PHY DRIVER
-M:     Kamil Debski <kamil@wypas.org>
-M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
-L:     linux-kernel@vger.kernel.org
-S:     Supported
-F:     Documentation/devicetree/bindings/phy/samsung-phy.txt
-F:     Documentation/phy/samsung-usb2.txt
-F:     drivers/phy/samsung/phy-exynos4210-usb2.c
-F:     drivers/phy/samsung/phy-exynos4x12-usb2.c
-F:     drivers/phy/samsung/phy-exynos5250-usb2.c
-F:     drivers/phy/samsung/phy-s5pv210-usb2.c
-F:     drivers/phy/samsung/phy-samsung-usb2.c
-F:     drivers/phy/samsung/phy-samsung-usb2.h
-
-SERIAL DRIVERS
-M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-L:     linux-serial@vger.kernel.org
-S:     Maintained
-F:     Documentation/devicetree/bindings/serial/
-F:     drivers/tty/serial/
-
-SERIAL DEVICE BUS
-M:     Rob Herring <robh@kernel.org>
-L:     linux-serial@vger.kernel.org
-S:     Maintained
-F:     Documentation/devicetree/bindings/serial/slave-device.txt
-F:     drivers/tty/serdev/
-F:     include/linux/serdev.h
-
-SERIAL IR RECEIVER
-M:     Sean Young <sean@mess.org>
+SAMSUNG S5C73M3 CAMERA DRIVER
+M:     Kyungmin Park <kyungmin.park@samsung.com>
+M:     Andrzej Hajda <a.hajda@samsung.com>
 L:     linux-media@vger.kernel.org
-S:     Maintained
-F:     drivers/media/rc/serial_ir.c
-
-STI CEC DRIVER
-M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
-S:     Maintained
-F:     drivers/staging/media/st-cec/
-F:     Documentation/devicetree/bindings/media/stih-cec.txt
-
-SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
-M:     Ursula Braun <ubraun@linux.vnet.ibm.com>
-L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
-S:     Supported
-F:     net/smc/
-
-SYNOPSYS DESIGNWARE DMAC DRIVER
-M:     Viresh Kumar <vireshk@kernel.org>
-M:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
-S:     Maintained
-F:     include/linux/dma/dw.h
-F:     include/linux/platform_data/dma-dw.h
-F:     drivers/dma/dw/
-
-SYNOPSYS DESIGNWARE ENTERPRISE ETHERNET DRIVER
-M:     Jie Deng <jiedeng@synopsys.com>
-L:     netdev@vger.kernel.org
 S:     Supported
-F:     drivers/net/ethernet/synopsys/
-
-SYNOPSYS DESIGNWARE I2C DRIVER
-M:     Jarkko Nikula <jarkko.nikula@linux.intel.com>
-R:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
-R:     Mika Westerberg <mika.westerberg@linux.intel.com>
-L:     linux-i2c@vger.kernel.org
-S:     Maintained
-F:     drivers/i2c/busses/i2c-designware-*
-F:     include/linux/platform_data/i2c-designware.h
+F:     drivers/media/i2c/s5c73m3/*
 
-SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
-M:     Jaehoon Chung <jh80.chung@samsung.com>
-L:     linux-mmc@vger.kernel.org
-S:     Maintained
-F:     drivers/mmc/host/dw_mmc*
+SAMSUNG S5K5BAF CAMERA DRIVER
+M:     Kyungmin Park <kyungmin.park@samsung.com>
+M:     Andrzej Hajda <a.hajda@samsung.com>
+L:     linux-media@vger.kernel.org
+S:     Supported
+F:     drivers/media/i2c/s5k5baf.c
 
-SYSTEM TRACE MODULE CLASS
-M:     Alexander Shishkin <alexander.shishkin@linux.intel.com>
+SAMSUNG S5P Security SubSystem (SSS) DRIVER
+M:     Krzysztof Kozlowski <krzk@kernel.org>
+M:     Vladimir Zapolskiy <vz@mleia.com>
+L:     linux-crypto@vger.kernel.org
+L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ash/stm.git
-F:     Documentation/trace/stm.txt
-F:     drivers/hwtracing/stm/
-F:     include/linux/stm.h
-F:     include/uapi/linux/stm.h
+F:     drivers/crypto/s5p-sss.c
 
-TEE SUBSYSTEM
-M:     Jens Wiklander <jens.wiklander@linaro.org>
-S:     Maintained
-F:     include/linux/tee_drv.h
-F:     include/uapi/linux/tee.h
-F:     drivers/tee/
-F:     Documentation/tee.txt
+SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
+M:     Kyungmin Park <kyungmin.park@samsung.com>
+M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
+L:     linux-media@vger.kernel.org
+Q:     https://patchwork.linuxtv.org/project/linux-media/list/
+S:     Supported
+F:     drivers/media/platform/exynos4-is/
 
-THUNDERBOLT DRIVER
-M:     Andreas Noever <andreas.noever@gmail.com>
-M:     Michael Jamet <michael.jamet@intel.com>
-M:     Mika Westerberg <mika.westerberg@linux.intel.com>
-M:     Yehezkel Bernat <yehezkel.bernat@intel.com>
+SAMSUNG SOC CLOCK DRIVERS
+M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
+M:     Tomasz Figa <tomasz.figa@gmail.com>
+M:     Chanwoo Choi <cw00.choi@samsung.com>
+S:     Supported
+L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
+F:     drivers/clk/samsung/
+F:     include/dt-bindings/clock/exynos*.h
+F:     Documentation/devicetree/bindings/clock/exynos*.txt
+
+SAMSUNG SPI DRIVERS
+M:     Kukjin Kim <kgene@kernel.org>
+M:     Krzysztof Kozlowski <krzk@kernel.org>
+M:     Andi Shyti <andi.shyti@samsung.com>
+L:     linux-spi@vger.kernel.org
+L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 S:     Maintained
-F:     drivers/thunderbolt/
+F:     Documentation/devicetree/bindings/spi/spi-samsung.txt
+F:     drivers/spi/spi-s3c*
+F:     include/linux/platform_data/spi-s3c64xx.h
 
-TI BQ27XXX POWER SUPPLY DRIVER
-R:     Andrew F. Davis <afd@ti.com>
-F:     include/linux/power/bq27xxx_battery.h
-F:     drivers/power/supply/bq27xxx_battery.c
-F:     drivers/power/supply/bq27xxx_battery_i2c.c
+SAMSUNG SXGBE DRIVERS
+M:     Byungho An <bh74.an@samsung.com>
+M:     Girish K S <ks.giri@samsung.com>
+M:     Vipul Pandya <vipul.pandya@samsung.com>
+S:     Supported
+L:     netdev@vger.kernel.org
+F:     drivers/net/ethernet/samsung/sxgbe/
 
-TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
-M:     John Stultz <john.stultz@linaro.org>
-M:     Thomas Gleixner <tglx@linutronix.de>
-R:     Stephen Boyd <sboyd@codeaurora.org>
-L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
+SAMSUNG THERMAL DRIVER
+M:     Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
+L:     linux-pm@vger.kernel.org
+L:     linux-samsung-soc@vger.kernel.org
 S:     Supported
-F:     include/linux/clocksource.h
-F:     include/linux/time.h
-F:     include/linux/timex.h
-F:     include/uapi/linux/time.h
-F:     include/uapi/linux/timex.h
-F:     kernel/time/clocksource.c
-F:     kernel/time/time*.c
-F:     kernel/time/alarmtimer.c
-F:     kernel/time/ntp.c
-F:     tools/testing/selftests/timers/
+T:     git https://github.com/lmajewski/linux-samsung-thermal.git
+F:     drivers/thermal/samsung/
 
-TI TRF7970A NFC DRIVER
-M:     Mark Greer <mgreer@animalcreek.com>
-L:     linux-wireless@vger.kernel.org
-L:     linux-nfc@lists.01.org (moderated for non-subscribers)
+SAMSUNG USB2 PHY DRIVER
+M:     Kamil Debski <kamil@wypas.org>
+M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
+L:     linux-kernel@vger.kernel.org
 S:     Supported
-F:     drivers/nfc/trf7970a.c
-F:     Documentation/devicetree/bindings/net/nfc/trf7970a.txt
+F:     Documentation/devicetree/bindings/phy/samsung-phy.txt
+F:     Documentation/phy/samsung-usb2.txt
+F:     drivers/phy/samsung/phy-exynos4210-usb2.c
+F:     drivers/phy/samsung/phy-exynos4x12-usb2.c
+F:     drivers/phy/samsung/phy-exynos5250-usb2.c
+F:     drivers/phy/samsung/phy-s5pv210-usb2.c
+F:     drivers/phy/samsung/phy-samsung-usb2.c
+F:     drivers/phy/samsung/phy-samsung-usb2.h
 
 SC1200 WDT DRIVER
 M:     Zwane Mwaikambo <zwanem@gmail.com>
@@ -11710,16 +11653,6 @@ M:     Lubomir Rintel <lkundrak@v3.sk>
 S:     Supported
 F:     drivers/char/pcmcia/scr24x_cs.c
 
-SYSTEM CONTROL & POWER INTERFACE (SCPI) Message Protocol drivers
-M:     Sudeep Holla <sudeep.holla@arm.com>
-L:     linux-arm-kernel@lists.infradead.org
-S:     Maintained
-F:     Documentation/devicetree/bindings/arm/arm,scpi.txt
-F:     drivers/clk/clk-scpi.c
-F:     drivers/cpufreq/scpi-cpufreq.c
-F:     drivers/firmware/arm_scpi.c
-F:     include/linux/scpi_protocol.h
-
 SCSI CDROM DRIVER
 M:     Jens Axboe <axboe@kernel.dk>
 L:     linux-scsi@vger.kernel.org
@@ -11804,14 +11737,6 @@ L:     sdricohcs-devel@lists.sourceforge.net (subscribers-only)
 S:     Maintained
 F:     drivers/mmc/host/sdricoh_cs.c
 
-SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
-M:     Adrian Hunter <adrian.hunter@intel.com>
-L:     linux-mmc@vger.kernel.org
-T:     git git://git.infradead.org/users/ahunter/linux-sdhci.git
-S:     Maintained
-F:     drivers/mmc/host/sdhci*
-F:     include/linux/mmc/sdhci*
-
 SECURE COMPUTING
 M:     Kees Cook <keescook@chromium.org>
 R:     Andy Lutomirski <luto@amacapital.net>
@@ -11834,6 +11759,14 @@ L:     bcm-kernel-feedback-list@broadcom.com
 S:     Maintained
 F:     drivers/mmc/host/sdhci-brcmstb*
 
+SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
+M:     Adrian Hunter <adrian.hunter@intel.com>
+L:     linux-mmc@vger.kernel.org
+T:     git git://git.infradead.org/users/ahunter/linux-sdhci.git
+S:     Maintained
+F:     drivers/mmc/host/sdhci*
+F:     include/linux/mmc/sdhci*
+
 SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER
 M:     Ben Dooks <ben-linux@fluff.org>
 M:     Jaehoon Chung <jh80.chung@samsung.com>
@@ -11858,6 +11791,10 @@ F:     block/opal_proto.h
 F:     include/linux/sed*
 F:     include/uapi/linux/sed*
 
+SECURITY CONTACT
+M:     Security Officers <security@kernel.org>
+S:     Supported
+
 SECURITY SUBSYSTEM
 M:     James Morris <james.l.morris@oracle.com>
 M:     "Serge E. Hallyn" <serge@hallyn.com>
@@ -11867,10 +11804,6 @@ W:     http://kernsec.org/
 S:     Supported
 F:     security/
 
-SECURITY CONTACT
-M:     Security Officers <security@kernel.org>
-S:     Supported
-
 SELINUX SECURITY MODULE
 M:     Paul Moore <paul@paul-moore.com>
 M:     Stephen Smalley <sds@tycho.nsa.gov>
@@ -11884,62 +11817,32 @@ F:    security/selinux/
 F:     scripts/selinux/
 F:     Documentation/admin-guide/LSM/SELinux.rst
 
-APPARMOR SECURITY MODULE
-M:     John Johansen <john.johansen@canonical.com>
-L:     apparmor@lists.ubuntu.com (subscribers-only, general discussion)
-W:     apparmor.wiki.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
-S:     Supported
-F:     security/apparmor/
-F:     Documentation/admin-guide/LSM/apparmor.rst
-
-LOADPIN SECURITY MODULE
-M:     Kees Cook <keescook@chromium.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git lsm/loadpin
-S:     Supported
-F:     security/loadpin/
-F:     Documentation/admin-guide/LSM/LoadPin.rst
-
-YAMA SECURITY MODULE
-M:     Kees Cook <keescook@chromium.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip
-S:     Supported
-F:     security/yama/
-F:     Documentation/admin-guide/LSM/Yama.rst
-
 SENSABLE PHANTOM
 M:     Jiri Slaby <jirislaby@gmail.com>
 S:     Maintained
 F:     drivers/misc/phantom.c
 F:     include/uapi/linux/phantom.h
 
-Emulex 10Gbps iSCSI - OneConnect DRIVER
-M:     Subbu Seetharaman <subbu.seetharaman@broadcom.com>
-M:     Ketan Mukadam <ketan.mukadam@broadcom.com>
-M:     Jitendra Bhivare <jitendra.bhivare@broadcom.com>
-L:     linux-scsi@vger.kernel.org
-W:     http://www.broadcom.com
-S:     Supported
-F:     drivers/scsi/be2iscsi/
+SERIAL DEVICE BUS
+M:     Rob Herring <robh@kernel.org>
+L:     linux-serial@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/serial/slave-device.txt
+F:     drivers/tty/serdev/
+F:     include/linux/serdev.h
 
-Emulex 10Gbps NIC BE2, BE3-R, Lancer, Skyhawk-R DRIVER (be2net)
-M:     Sathya Perla <sathya.perla@broadcom.com>
-M:     Ajit Khaparde <ajit.khaparde@broadcom.com>
-M:     Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
-M:     Somnath Kotur <somnath.kotur@broadcom.com>
-L:     netdev@vger.kernel.org
-W:     http://www.emulex.com
-S:     Supported
-F:     drivers/net/ethernet/emulex/benet/
+SERIAL DRIVERS
+M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+L:     linux-serial@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/serial/
+F:     drivers/tty/serial/
 
-EMULEX ONECONNECT ROCE DRIVER
-M:     Selvin Xavier <selvin.xavier@broadcom.com>
-M:     Devesh Sharma <devesh.sharma@broadcom.com>
-L:     linux-rdma@vger.kernel.org
-W:     http://www.broadcom.com
-S:     Odd Fixes
-F:     drivers/infiniband/hw/ocrdma/
-F:     include/uapi/rdma/ocrdma-abi.h
+SERIAL IR RECEIVER
+M:     Sean Young <sean@mess.org>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     drivers/media/rc/serial_ir.c
 
 SFC NETWORK DRIVER
 M:     Solarflare linux maintainers <linux-net-drivers@solarflare.com>
@@ -11968,6 +11871,24 @@ M:     Robin Holt <robinmholt@gmail.com>
 S:     Maintained
 F:     drivers/misc/sgi-xp/
 
+SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
+M:     Ursula Braun <ubraun@linux.vnet.ibm.com>
+L:     linux-s390@vger.kernel.org
+W:     http://www.ibm.com/developerworks/linux/linux390/
+S:     Supported
+F:     net/smc/
+
+SH_VEU V4L2 MEM2MEM DRIVER
+L:     linux-media@vger.kernel.org
+S:     Orphan
+F:     drivers/media/platform/sh_veu.c
+
+SH_VOU V4L2 OUTPUT DRIVER
+L:     linux-media@vger.kernel.org
+S:     Orphan
+F:     drivers/media/platform/sh_vou.c
+F:     include/media/drv-intf/sh_vou.h
+
 SI2157 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
@@ -12050,24 +11971,14 @@ S:    Maintained
 F:     drivers/input/touchscreen/silead.c
 F:     drivers/platform/x86/silead_dmi.c
 
-SIMPLEFB FB DRIVER
-M:     Hans de Goede <hdegoede@redhat.com>
+SILICON MOTION SM712 FRAME BUFFER DRIVER
+M:     Sudip Mukherjee <sudipm.mukherjee@gmail.com>
+M:     Teddy Wang <teddy.wang@siliconmotion.com>
+M:     Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
 L:     linux-fbdev@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/display/simple-framebuffer.txt
-F:     drivers/video/fbdev/simplefb.c
-F:     include/linux/platform_data/simplefb.h
-
-SH_VEU V4L2 MEM2MEM DRIVER
-L:     linux-media@vger.kernel.org
-S:     Orphan
-F:     drivers/media/platform/sh_veu.c
-
-SH_VOU V4L2 OUTPUT DRIVER
-L:     linux-media@vger.kernel.org
-S:     Orphan
-F:     drivers/media/platform/sh_vou.c
-F:     include/media/drv-intf/sh_vou.h
+F:     drivers/video/fbdev/sm712*
+F:     Documentation/fb/sm712fb.txt
 
 SIMPLE FIRMWARE INTERFACE (SFI)
 M:     Len Brown <lenb@kernel.org>
@@ -12079,6 +11990,14 @@ F:     arch/x86/platform/sfi/
 F:     drivers/sfi/
 F:     include/linux/sfi*.h
 
+SIMPLEFB FB DRIVER
+M:     Hans de Goede <hdegoede@redhat.com>
+L:     linux-fbdev@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/display/simple-framebuffer.txt
+F:     drivers/video/fbdev/simplefb.c
+F:     include/linux/platform_data/simplefb.h
+
 SIMTEC EB110ATX (Chalice CATS)
 P:     Ben Dooks
 P:     Vincent Sanders <vince@simtec.co.uk>
@@ -12103,61 +12022,6 @@ F:     lib/siphash.c
 F:     lib/test_siphash.c
 F:     include/linux/siphash.h
 
-TI DAVINCI MACHINE SUPPORT
-M:     Sekhar Nori <nsekhar@ti.com>
-M:     Kevin Hilman <khilman@kernel.org>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci.git
-S:     Supported
-F:     arch/arm/mach-davinci/
-F:     drivers/i2c/busses/i2c-davinci.c
-F:     arch/arm/boot/dts/da850*
-
-TI DAVINCI SERIES MEDIA DRIVER
-M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
-L:     linux-media@vger.kernel.org
-W:     https://linuxtv.org
-Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-T:     git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
-S:     Maintained
-F:     drivers/media/platform/davinci/
-F:     include/media/davinci/
-
-TI DAVINCI SERIES GPIO DRIVER
-M:     Keerthy <j-keerthy@ti.com>
-L:     linux-gpio@vger.kernel.org
-S:     Maintained
-F:     Documentation/devicetree/bindings/gpio/gpio-davinci.txt
-F:     drivers/gpio/gpio-davinci.c
-
-TI AM437X VPFE DRIVER
-M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
-L:     linux-media@vger.kernel.org
-W:     https://linuxtv.org
-Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-T:     git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
-S:     Maintained
-F:     drivers/media/platform/am437x/
-
-OV2659 OMNIVISION SENSOR DRIVER
-M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
-L:     linux-media@vger.kernel.org
-W:     https://linuxtv.org
-Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-T:     git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
-S:     Maintained
-F:     drivers/media/i2c/ov2659.c
-F:     include/media/i2c/ov2659.h
-
-SILICON MOTION SM712 FRAME BUFFER DRIVER
-M:     Sudip Mukherjee <sudipm.mukherjee@gmail.com>
-M:     Teddy Wang <teddy.wang@siliconmotion.com>
-M:     Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
-L:     linux-fbdev@vger.kernel.org
-S:     Maintained
-F:     drivers/video/fbdev/sm712*
-F:     Documentation/fb/sm712fb.txt
-
 SIS 190 ETHERNET DRIVER
 M:     Francois Romieu <romieu@fr.zoreil.com>
 L:     netdev@vger.kernel.org
@@ -12218,14 +12082,6 @@ S:     Maintained
 F:     Documentation/admin-guide/LSM/Smack.rst
 F:     security/smack/
 
-DRIVERS FOR ADAPTIVE VOLTAGE SCALING (AVS)
-M:     Kevin Hilman <khilman@kernel.org>
-M:     Nishanth Menon <nm@ti.com>
-S:     Maintained
-F:     drivers/power/avs/
-F:     include/linux/power/smartreflex.h
-L:     linux-pm@vger.kernel.org
-
 SMC91x ETHERNET DRIVER
 M:     Nicolas Pitre <nico@fluxnic.net>
 S:     Odd Fixes
@@ -12263,6 +12119,12 @@ S:     Supported
 F:     Documentation/hwmon/sch5627
 F:     drivers/hwmon/sch5627.c
 
+SMSC UFX6000 and UFX7000 USB to VGA DRIVER
+M:     Steve Glendinning <steve.glendinning@shawell.net>
+L:     linux-fbdev@vger.kernel.org
+S:     Maintained
+F:     drivers/video/fbdev/smscufx.c
+
 SMSC47B397 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
 L:     linux-hwmon@vger.kernel.org
@@ -12283,12 +12145,6 @@ L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/smsc/smsc9420.*
 
-SMSC UFX6000 and UFX7000 USB to VGA DRIVER
-M:     Steve Glendinning <steve.glendinning@shawell.net>
-L:     linux-fbdev@vger.kernel.org
-S:     Maintained
-F:     drivers/video/fbdev/smscufx.c
-
 SOC-CAMERA V4L2 SUBSYSTEM
 M:     Guennadi Liakhovetski <g.liakhovetski@gmx.de>
 L:     linux-media@vger.kernel.org
@@ -12303,6 +12159,15 @@ M:     Chris Boot <bootc@bootc.net>
 S:     Maintained
 F:     drivers/leds/leds-net48xx.c
 
+SOFT-ROCE DRIVER (rxe)
+M:     Moni Shoua <monis@mellanox.com>
+L:     linux-rdma@vger.kernel.org
+S:     Supported
+W:     https://github.com/SoftRoCE/rxe-dev/wiki/rxe-dev:-Home
+Q:     http://patchwork.kernel.org/project/linux-rdma/list/
+F:     drivers/infiniband/sw/rxe/
+F:     include/uapi/rdma/rdma_user_rxe.h
+
 SOFTLOGIC 6x10 MPEG CODEC
 M:     Bluecherry Maintainers <maintainers@bluecherrydvr.com>
 M:     Anton Sviridenko <anton@corp.bluecherry.net>
@@ -12335,16 +12200,6 @@ S:     Maintained
 F:     drivers/ssb/
 F:     include/linux/ssb/
 
-SONY VAIO CONTROL DEVICE DRIVER
-M:     Mattia Dongili <malattia@linux.it>
-L:     platform-driver-x86@vger.kernel.org
-W:     http://www.linux.it/~malattia/wiki/index.php/Sony_drivers
-S:     Maintained
-F:     Documentation/laptops/sony-laptop.txt
-F:     drivers/char/sonypi.c
-F:     drivers/platform/x86/sony-laptop.c
-F:     include/linux/sony-laptop.h
-
 SONY MEMORYSTICK CARD SUPPORT
 M:     Alex Dubov <oakad@yahoo.com>
 W:     http://tifmxx.berlios.de/
@@ -12356,6 +12211,16 @@ M:     Maxim Levitsky <maximlevitsky@gmail.com>
 S:     Maintained
 F:     drivers/memstick/core/ms_block.*
 
+SONY VAIO CONTROL DEVICE DRIVER
+M:     Mattia Dongili <malattia@linux.it>
+L:     platform-driver-x86@vger.kernel.org
+W:     http://www.linux.it/~malattia/wiki/index.php/Sony_drivers
+S:     Maintained
+F:     Documentation/laptops/sony-laptop.txt
+F:     drivers/char/sonypi.c
+F:     drivers/platform/x86/sony-laptop.c
+F:     include/linux/sony-laptop.h
+
 SOUND
 M:     Jaroslav Kysela <perex@perex.cz>
 M:     Takashi Iwai <tiwai@suse.com>
@@ -12381,6 +12246,13 @@ F:     include/uapi/sound/compress_*
 F:     sound/core/compress_offload.c
 F:     sound/soc/soc-compress.c
 
+SOUND - DMAENGINE HELPERS
+M:     Lars-Peter Clausen <lars@metafoo.de>
+S:     Supported
+F:     include/sound/dmaengine_pcm.h
+F:     sound/core/pcm_dmaengine.c
+F:     sound/soc/soc-generic-dmaengine-pcm.c
+
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
 M:     Liam Girdwood <lgirdwood@gmail.com>
 M:     Mark Brown <broonie@kernel.org>
@@ -12393,13 +12265,6 @@ F:     Documentation/sound/alsa/soc/
 F:     sound/soc/
 F:     include/sound/soc*
 
-SOUND - DMAENGINE HELPERS
-M:     Lars-Peter Clausen <lars@metafoo.de>
-S:     Supported
-F:     include/sound/dmaengine_pcm.h
-F:     sound/core/pcm_dmaengine.c
-F:     sound/soc/soc-generic-dmaengine-pcm.c
-
 SP2 MEDIA DRIVER
 M:     Olli Salonen <olli.salonen@iki.fi>
 L:     linux-media@vger.kernel.org
@@ -12442,21 +12307,21 @@ T:    git git://git.kernel.org/pub/scm/devel/sparse/chrisl/sparse.git
 S:     Maintained
 F:     include/linux/compiler.h
 
-SPEAR PLATFORM SUPPORT
+SPEAR CLOCK FRAMEWORK SUPPORT
 M:     Viresh Kumar <vireshk@kernel.org>
-M:     Shiraz Hashim <shiraz.linux.kernel@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.st.com/spear
 S:     Maintained
-F:     arch/arm/boot/dts/spear*
-F:     arch/arm/mach-spear/
+F:     drivers/clk/spear/
 
-SPEAR CLOCK FRAMEWORK SUPPORT
+SPEAR PLATFORM SUPPORT
 M:     Viresh Kumar <vireshk@kernel.org>
+M:     Shiraz Hashim <shiraz.linux.kernel@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.st.com/spear
 S:     Maintained
-F:     drivers/clk/spear/
+F:     arch/arm/boot/dts/spear*
+F:     arch/arm/mach-spear/
 
 SPI NOR SUBSYSTEM
 M:     Cyrille Pitchen <cyrille.pitchen@wedev4u.fr>
@@ -12464,7 +12329,8 @@ M:      Marek Vasut <marek.vasut@gmail.com>
 L:     linux-mtd@lists.infradead.org
 W:     http://www.linux-mtd.infradead.org/
 Q:     http://patchwork.ozlabs.org/project/linux-mtd/list/
-T:     git git://github.com/spi-nor/linux.git
+T:     git git://git.infradead.org/linux-mtd.git spi-nor/fixes
+T:     git git://git.infradead.org/l2-mtd.git spi-nor/next
 S:     Maintained
 F:     drivers/mtd/spi-nor/
 F:     include/linux/mtd/spi-nor.h
@@ -12489,6 +12355,15 @@ S:     Supported
 F:     Documentation/networking/spider_net.txt
 F:     drivers/net/ethernet/toshiba/spider_net*
 
+SPMI SUBSYSTEM
+R:     Stephen Boyd <sboyd@codeaurora.org>
+L:     linux-arm-msm@vger.kernel.org
+F:     Documentation/devicetree/bindings/spmi/
+F:     drivers/spmi/
+F:     include/dt-bindings/spmi/spmi.h
+F:     include/linux/spmi.h
+F:     include/trace/events/spmi.h
+
 SPU FILE SYSTEM
 M:     Jeremy Kerr <jk@ozlabs.org>
 L:     linuxppc-dev@lists.ozlabs.org
@@ -12517,13 +12392,6 @@ L:     stable@vger.kernel.org
 S:     Supported
 F:     Documentation/process/stable-kernel-rules.rst
 
-STAGING SUBSYSTEM
-M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
-L:     devel@driverdev.osuosl.org
-S:     Supported
-F:     drivers/staging/
-
 STAGING - COMEDI
 M:     Ian Abbott <abbotti@mev.co.uk>
 M:     H Hartley Sweeten <hsweeten@visionengravers.com>
@@ -12613,11 +12481,39 @@ M:    Arnaud Patard <arnaud.patard@rtp-net.org>
 S:     Odd Fixes
 F:     drivers/staging/xgifb/
 
+STAGING SUBSYSTEM
+M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
+L:     devel@driverdev.osuosl.org
+S:     Supported
+F:     drivers/staging/
+
 STARFIRE/DURALAN NETWORK DRIVER
 M:     Ion Badulescu <ionut@badula.org>
 S:     Odd Fixes
 F:     drivers/net/ethernet/adaptec/starfire*
 
+STI CEC DRIVER
+M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
+S:     Maintained
+F:     drivers/staging/media/st-cec/
+F:     Documentation/devicetree/bindings/media/stih-cec.txt
+
+STK1160 USB VIDEO CAPTURE DRIVER
+M:     Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Maintained
+F:     drivers/media/usb/stk1160/
+
+STMMAC ETHERNET DRIVER
+M:     Giuseppe Cavallaro <peppe.cavallaro@st.com>
+M:     Alexandre Torgue <alexandre.torgue@st.com>
+L:     netdev@vger.kernel.org
+W:     http://www.stlinux.com
+S:     Supported
+F:     drivers/net/ethernet/stmicro/stmmac/
+
 SUN3/3X
 M:     Sam Creasey <sammy@sammy.net>
 W:     http://sammy.net/sun3/
@@ -12689,6 +12585,20 @@ S:     Supported
 F:     net/switchdev/
 F:     include/net/switchdev.h
 
+SYNC FILE FRAMEWORK
+M:     Sumit Semwal <sumit.semwal@linaro.org>
+R:     Gustavo Padovan <gustavo@padovan.org>
+S:     Maintained
+L:     linux-media@vger.kernel.org
+L:     dri-devel@lists.freedesktop.org
+F:     drivers/dma-buf/sync_*
+F:     drivers/dma-buf/dma-fence*
+F:     drivers/dma-buf/sw_sync.c
+F:     include/linux/sync_file.h
+F:     include/uapi/linux/sync_file.h
+F:     Documentation/sync_file.txt
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+
 SYNOPSYS ARC ARCHITECTURE
 M:     Vineet Gupta <vgupta@synopsys.com>
 L:     linux-snps-arc@lists.infradead.org
@@ -12707,6 +12617,35 @@ F:     arch/arc/plat-axs10x
 F:     arch/arc/boot/dts/ax*
 F:     Documentation/devicetree/bindings/arc/axs10*
 
+SYNOPSYS DESIGNWARE DMAC DRIVER
+M:     Viresh Kumar <vireshk@kernel.org>
+M:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+S:     Maintained
+F:     include/linux/dma/dw.h
+F:     include/linux/platform_data/dma-dw.h
+F:     drivers/dma/dw/
+
+SYNOPSYS DESIGNWARE ENTERPRISE ETHERNET DRIVER
+M:     Jie Deng <jiedeng@synopsys.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/ethernet/synopsys/
+
+SYNOPSYS DESIGNWARE I2C DRIVER
+M:     Jarkko Nikula <jarkko.nikula@linux.intel.com>
+R:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+R:     Mika Westerberg <mika.westerberg@linux.intel.com>
+L:     linux-i2c@vger.kernel.org
+S:     Maintained
+F:     drivers/i2c/busses/i2c-designware-*
+F:     include/linux/platform_data/i2c-designware.h
+
+SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
+M:     Jaehoon Chung <jh80.chung@samsung.com>
+L:     linux-mmc@vger.kernel.org
+S:     Maintained
+F:     drivers/mmc/host/dw_mmc*
+
 SYSTEM CONFIGURATION (SYSCON)
 M:     Lee Jones <lee.jones@linaro.org>
 M:     Arnd Bergmann <arnd@arndb.de>
@@ -12714,6 +12653,16 @@ T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
 S:     Supported
 F:     drivers/mfd/syscon.c
 
+SYSTEM CONTROL & POWER INTERFACE (SCPI) Message Protocol drivers
+M:     Sudeep Holla <sudeep.holla@arm.com>
+L:     linux-arm-kernel@lists.infradead.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/arm/arm,scpi.txt
+F:     drivers/clk/clk-scpi.c
+F:     drivers/cpufreq/scpi-cpufreq.c
+F:     drivers/firmware/arm_scpi.c
+F:     include/linux/scpi_protocol.h
+
 SYSTEM RESET/SHUTDOWN DRIVERS
 M:     Sebastian Reichel <sre@kernel.org>
 L:     linux-pm@vger.kernel.org
@@ -12722,6 +12671,15 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/power/reset/
 F:     drivers/power/reset/
 
+SYSTEM TRACE MODULE CLASS
+M:     Alexander Shishkin <alexander.shishkin@linux.intel.com>
+S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ash/stm.git
+F:     Documentation/trace/stm.txt
+F:     drivers/hwtracing/stm/
+F:     include/linux/stm.h
+F:     include/uapi/linux/stm.h
+
 SYSV FILESYSTEM
 M:     Christoph Hellwig <hch@infradead.org>
 S:     Maintained
@@ -12891,6 +12849,14 @@ L:     linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/rc/ttusbir.c
 
+TEE SUBSYSTEM
+M:     Jens Wiklander <jens.wiklander@linaro.org>
+S:     Maintained
+F:     include/linux/tee_drv.h
+F:     include/uapi/linux/tee.h
+F:     drivers/tee/
+F:     Documentation/tee.txt
+
 TEGRA ARCHITECTURE SUPPORT
 M:     Thierry Reding <thierry.reding@gmail.com>
 M:     Jonathan Hunter <jonathanh@nvidia.com>
@@ -13020,7 +12986,24 @@ W:     http://ibm-acpi.sourceforge.net
 W:     http://thinkwiki.org/wiki/Ibm-acpi
 T:     git git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
 S:     Maintained
-F:     drivers/platform/x86/thinkpad_acpi.c
+F:     drivers/platform/x86/thinkpad_acpi.c
+
+THUNDERBOLT DRIVER
+M:     Andreas Noever <andreas.noever@gmail.com>
+M:     Michael Jamet <michael.jamet@intel.com>
+M:     Mika Westerberg <mika.westerberg@linux.intel.com>
+M:     Yehezkel Bernat <yehezkel.bernat@intel.com>
+S:     Maintained
+F:     drivers/thunderbolt/
+
+TI AM437X VPFE DRIVER
+M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
+L:     linux-media@vger.kernel.org
+W:     https://linuxtv.org
+Q:     http://patchwork.linuxtv.org/project/linux-media/list/
+T:     git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
+S:     Maintained
+F:     drivers/media/platform/am437x/
 
 TI BANDGAP AND THERMAL DRIVER
 M:     Eduardo Valentin <edubezval@gmail.com>
@@ -13030,13 +13013,11 @@ L:    linux-omap@vger.kernel.org
 S:     Maintained
 F:     drivers/thermal/ti-soc-thermal/
 
-TI VPE/CAL DRIVERS
-M:     Benoit Parrot <bparrot@ti.com>
-L:     linux-media@vger.kernel.org
-W:     http://linuxtv.org/
-Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
-F:     drivers/media/platform/ti-vpe/
+TI BQ27XXX POWER SUPPLY DRIVER
+R:     Andrew F. Davis <afd@ti.com>
+F:     include/linux/power/bq27xxx_battery.h
+F:     drivers/power/supply/bq27xxx_battery.c
+F:     drivers/power/supply/bq27xxx_battery_i2c.c
 
 TI CDCE706 CLOCK DRIVER
 M:     Max Filippov <jcmvbkbc@gmail.com>
@@ -13050,6 +13031,33 @@ S:     Maintained
 F:     drivers/clk/ti/
 F:     include/linux/clk/ti.h
 
+TI DAVINCI MACHINE SUPPORT
+M:     Sekhar Nori <nsekhar@ti.com>
+M:     Kevin Hilman <khilman@kernel.org>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci.git
+S:     Supported
+F:     arch/arm/mach-davinci/
+F:     drivers/i2c/busses/i2c-davinci.c
+F:     arch/arm/boot/dts/da850*
+
+TI DAVINCI SERIES GPIO DRIVER
+M:     Keerthy <j-keerthy@ti.com>
+L:     linux-gpio@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/gpio/gpio-davinci.txt
+F:     drivers/gpio/gpio-davinci.c
+
+TI DAVINCI SERIES MEDIA DRIVER
+M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
+L:     linux-media@vger.kernel.org
+W:     https://linuxtv.org
+Q:     http://patchwork.linuxtv.org/project/linux-media/list/
+T:     git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
+S:     Maintained
+F:     drivers/media/platform/davinci/
+F:     include/media/davinci/
+
 TI ETHERNET SWITCH DRIVER (CPSW)
 R:     Grygorii Strashko <grygorii.strashko@ti.com>
 L:     linux-omap@vger.kernel.org
@@ -13073,7 +13081,6 @@ S:      Maintained
 F:     drivers/soc/ti/*
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
 
-
 TI LM49xxx FAMILY ASoC CODEC DRIVERS
 M:     M R Swami Reddy <mr.swami.reddy@ti.com>
 M:     Vishwas A Deshpande <vishwas.a.deshpande@ti.com>
@@ -13118,12 +13125,28 @@ L:    alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Odd Fixes
 F:     sound/soc/codecs/tas571x*
 
+TI TRF7970A NFC DRIVER
+M:     Mark Greer <mgreer@animalcreek.com>
+L:     linux-wireless@vger.kernel.org
+L:     linux-nfc@lists.01.org (moderated for non-subscribers)
+S:     Supported
+F:     drivers/nfc/trf7970a.c
+F:     Documentation/devicetree/bindings/net/nfc/trf7970a.txt
+
 TI TWL4030 SERIES SOC CODEC DRIVER
 M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Maintained
 F:     sound/soc/codecs/twl4030*
 
+TI VPE/CAL DRIVERS
+M:     Benoit Parrot <bparrot@ti.com>
+L:     linux-media@vger.kernel.org
+W:     http://linuxtv.org/
+Q:     http://patchwork.linuxtv.org/project/linux-media/list/
+S:     Maintained
+F:     drivers/media/platform/ti-vpe/
+
 TI WILINK WIRELESS DRIVERS
 L:     linux-wireless@vger.kernel.org
 W:     http://wireless.kernel.org/en/users/Drivers/wl12xx
@@ -13133,16 +13156,6 @@ S:     Orphan
 F:     drivers/net/wireless/ti/
 F:     include/linux/wl12xx.h
 
-TIPC NETWORK LAYER
-M:     Jon Maloy <jon.maloy@ericsson.com>
-M:     Ying Xue <ying.xue@windriver.com>
-L:     netdev@vger.kernel.org (core kernel code)
-L:     tipc-discussion@lists.sourceforge.net (user apps, general discussion)
-W:     http://tipc.sourceforge.net/
-S:     Maintained
-F:     include/uapi/linux/tipc*.h
-F:     net/tipc/
-
 TILE ARCHITECTURE
 M:     Chris Metcalf <cmetcalf@mellanox.com>
 W:     http://www.mellanox.com/repository/solutions/tile-scm/
@@ -13158,6 +13171,34 @@ F:     drivers/tty/serial/tilegx.c
 F:     drivers/usb/host/*-tilegx.c
 F:     include/linux/usb/tilegx.h
 
+TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
+M:     John Stultz <john.stultz@linaro.org>
+M:     Thomas Gleixner <tglx@linutronix.de>
+R:     Stephen Boyd <sboyd@codeaurora.org>
+L:     linux-kernel@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
+S:     Supported
+F:     include/linux/clocksource.h
+F:     include/linux/time.h
+F:     include/linux/timex.h
+F:     include/uapi/linux/time.h
+F:     include/uapi/linux/timex.h
+F:     kernel/time/clocksource.c
+F:     kernel/time/time*.c
+F:     kernel/time/alarmtimer.c
+F:     kernel/time/ntp.c
+F:     tools/testing/selftests/timers/
+
+TIPC NETWORK LAYER
+M:     Jon Maloy <jon.maloy@ericsson.com>
+M:     Ying Xue <ying.xue@windriver.com>
+L:     netdev@vger.kernel.org (core kernel code)
+L:     tipc-discussion@lists.sourceforge.net (user apps, general discussion)
+W:     http://tipc.sourceforge.net/
+S:     Maintained
+F:     include/uapi/linux/tipc*.h
+F:     net/tipc/
+
 TLAN NETWORK DRIVER
 M:     Samuel Chessman <chessman@tux.org>
 L:     tlan-devel@lists.sourceforge.net (subscribers-only)
@@ -13166,6 +13207,38 @@ S:     Maintained
 F:     Documentation/networking/tlan.txt
 F:     drivers/net/ethernet/ti/tlan.*
 
+TM6000 VIDEO4LINUX DRIVER
+M:     Mauro Carvalho Chehab <mchehab@s-opensource.com>
+M:     Mauro Carvalho Chehab <mchehab@kernel.org>
+L:     linux-media@vger.kernel.org
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Odd fixes
+F:     drivers/media/usb/tm6000/
+F:     Documentation/media/v4l-drivers/tm6000*
+
+TMIO/SDHI MMC DRIVER
+M:     Wolfram Sang <wsa+renesas@sang-engineering.com>
+L:     linux-mmc@vger.kernel.org
+S:     Supported
+F:     drivers/mmc/host/tmio_mmc*
+F:     drivers/mmc/host/renesas_sdhi*
+F:     include/linux/mfd/tmio.h
+
+TMP401 HARDWARE MONITOR DRIVER
+M:     Guenter Roeck <linux@roeck-us.net>
+L:     linux-hwmon@vger.kernel.org
+S:     Maintained
+F:     Documentation/hwmon/tmp401
+F:     drivers/hwmon/tmp401.c
+
+TMPFS (SHMEM FILESYSTEM)
+M:     Hugh Dickins <hughd@google.com>
+L:     linux-mm@kvack.org
+S:     Maintained
+F:     include/linux/shmem_fs.h
+F:     mm/shmem.c
+
 TOMOYO SECURITY MODULE
 M:     Kentaro Takeda <takedakn@nttdata.co.jp>
 M:     Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
@@ -13202,12 +13275,6 @@ L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     drivers/platform/x86/toshiba_haps.c
 
-TOSHIBA WMI HOTKEYS DRIVER
-M:     Azael Avalos <coproscefalo@gmail.com>
-L:     platform-driver-x86@vger.kernel.org
-S:     Maintained
-F:     drivers/platform/x86/toshiba-wmi.c
-
 TOSHIBA SMM DRIVER
 M:     Jonathan Buzzard <jonathan@buzzard.org.uk>
 W:     http://www.buzzard.org.uk/toshiba/
@@ -13223,62 +13290,11 @@ S:    Maintained
 F:     drivers/media/i2c/tc358743*
 F:     include/media/i2c/tc358743.h
 
-TMIO/SDHI MMC DRIVER
-M:     Wolfram Sang <wsa+renesas@sang-engineering.com>
-L:     linux-mmc@vger.kernel.org
-S:     Supported
-F:     drivers/mmc/host/tmio_mmc*
-F:     drivers/mmc/host/renesas_sdhi*
-F:     include/linux/mfd/tmio.h
-
-TMP401 HARDWARE MONITOR DRIVER
-M:     Guenter Roeck <linux@roeck-us.net>
-L:     linux-hwmon@vger.kernel.org
-S:     Maintained
-F:     Documentation/hwmon/tmp401
-F:     drivers/hwmon/tmp401.c
-
-TMPFS (SHMEM FILESYSTEM)
-M:     Hugh Dickins <hughd@google.com>
-L:     linux-mm@kvack.org
-S:     Maintained
-F:     include/linux/shmem_fs.h
-F:     mm/shmem.c
-
-TM6000 VIDEO4LINUX DRIVER
-M:     Mauro Carvalho Chehab <mchehab@s-opensource.com>
-M:     Mauro Carvalho Chehab <mchehab@kernel.org>
-L:     linux-media@vger.kernel.org
-W:     https://linuxtv.org
-T:     git git://linuxtv.org/media_tree.git
-S:     Odd fixes
-F:     drivers/media/usb/tm6000/
-F:     Documentation/media/v4l-drivers/tm6000*
-
-TW5864 VIDEO4LINUX DRIVER
-M:     Bluecherry Maintainers <maintainers@bluecherrydvr.com>
-M:     Anton Sviridenko <anton@corp.bluecherry.net>
-M:     Andrey Utkin <andrey.utkin@corp.bluecherry.net>
-M:     Andrey Utkin <andrey_utkin@fastmail.com>
-L:     linux-media@vger.kernel.org
-S:     Supported
-F:     drivers/media/pci/tw5864/
-
-TW68 VIDEO4LINUX DRIVER
-M:     Hans Verkuil <hverkuil@xs4all.nl>
-L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
-S:     Odd Fixes
-F:     drivers/media/pci/tw68/
-
-TW686X VIDEO4LINUX DRIVER
-M:     Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
-L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
+TOSHIBA WMI HOTKEYS DRIVER
+M:     Azael Avalos <coproscefalo@gmail.com>
+L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
-F:     drivers/media/pci/tw686x/
+F:     drivers/platform/x86/toshiba-wmi.c
 
 TPM DEVICE DRIVER
 M:     Peter Huewe <peterhuewe@gmx.de>
@@ -13380,6 +13396,31 @@ S:     Maintained
 F:     drivers/tc/
 F:     include/linux/tc.h
 
+TW5864 VIDEO4LINUX DRIVER
+M:     Bluecherry Maintainers <maintainers@bluecherrydvr.com>
+M:     Anton Sviridenko <anton@corp.bluecherry.net>
+M:     Andrey Utkin <andrey.utkin@corp.bluecherry.net>
+M:     Andrey Utkin <andrey_utkin@fastmail.com>
+L:     linux-media@vger.kernel.org
+S:     Supported
+F:     drivers/media/pci/tw5864/
+
+TW68 VIDEO4LINUX DRIVER
+M:     Hans Verkuil <hverkuil@xs4all.nl>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+W:     https://linuxtv.org
+S:     Odd Fixes
+F:     drivers/media/pci/tw68/
+
+TW686X VIDEO4LINUX DRIVER
+M:     Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+W:     http://linuxtv.org
+S:     Maintained
+F:     drivers/media/pci/tw686x/
+
 UBI FILE SYSTEM (UBIFS)
 M:     Richard Weinberger <richard@nod.at>
 M:     Artem Bityutskiy <dedekind1@gmail.com>
@@ -13429,6 +13470,13 @@ S:     Maintained
 F:     drivers/hid/uhid.c
 F:     include/uapi/linux/uhid.h
 
+ULPI BUS
+M:     Heikki Krogerus <heikki.krogerus@linux.intel.com>
+L:     linux-usb@vger.kernel.org
+S:     Maintained
+F:     drivers/usb/common/ulpi.c
+F:     include/linux/ulpi/
+
 ULTRA-WIDEBAND (UWB) SUBSYSTEM:
 L:     linux-usb@vger.kernel.org
 S:     Orphan
@@ -13489,6 +13537,14 @@ F:     drivers/mtd/ubi/
 F:     include/linux/mtd/ubi.h
 F:     include/uapi/mtd/ubi-user.h
 
+USB "USBNET" DRIVER FRAMEWORK
+M:     Oliver Neukum <oneukum@suse.com>
+L:     netdev@vger.kernel.org
+W:     http://www.linux-usb.org/usbnet
+S:     Maintained
+F:     drivers/net/usb/usbnet.c
+F:     include/linux/usb/usbnet.h
+
 USB ACM DRIVER
 M:     Oliver Neukum <oneukum@suse.com>
 L:     linux-usb@vger.kernel.org
@@ -13712,14 +13768,6 @@ L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/usb/host/uhci*
 
-USB "USBNET" DRIVER FRAMEWORK
-M:     Oliver Neukum <oneukum@suse.com>
-L:     netdev@vger.kernel.org
-W:     http://www.linux-usb.org/usbnet
-S:     Maintained
-F:     drivers/net/usb/usbnet.c
-F:     include/linux/usb/usbnet.h
-
 USB VIDEO CLASS
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-uvc-devel@lists.sourceforge.net (subscribers-only)
@@ -13768,18 +13816,11 @@ USB ZR364XX DRIVER
 M:     Antoine Jacquet <royale@zerezo.com>
 L:     linux-usb@vger.kernel.org
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     http://royale.zerezo.com/zr364xx/
-S:     Maintained
-F:     Documentation/media/v4l-drivers/zr364xx*
-F:     drivers/media/usb/zr364xx/
-
-ULPI BUS
-M:     Heikki Krogerus <heikki.krogerus@linux.intel.com>
-L:     linux-usb@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+W:     http://royale.zerezo.com/zr364xx/
 S:     Maintained
-F:     drivers/usb/common/ulpi.c
-F:     include/linux/ulpi/
+F:     Documentation/media/v4l-drivers/zr364xx*
+F:     drivers/media/usb/zr364xx/
 
 USER-MODE LINUX (UML)
 M:     Jeff Dike <jdike@addtoit.com>
@@ -13874,6 +13915,37 @@ F:     drivers/gpu/vga/vga_switcheroo.c
 F:     include/linux/vga_switcheroo.h
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 
+VIA RHINE NETWORK DRIVER
+S:     Orphan
+F:     drivers/net/ethernet/via/via-rhine.c
+
+VIA SD/MMC CARD CONTROLLER DRIVER
+M:     Bruce Chang <brucechang@via.com.tw>
+M:     Harald Welte <HaraldWelte@viatech.com>
+S:     Maintained
+F:     drivers/mmc/host/via-sdmmc.c
+
+VIA UNICHROME(PRO)/CHROME9 FRAMEBUFFER DRIVER
+M:     Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+L:     linux-fbdev@vger.kernel.org
+S:     Maintained
+F:     include/linux/via-core.h
+F:     include/linux/via-gpio.h
+F:     include/linux/via_i2c.h
+F:     drivers/video/fbdev/via/
+
+VIA VELOCITY NETWORK DRIVER
+M:     Francois Romieu <romieu@fr.zoreil.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ethernet/via/via-velocity.*
+
+VIDEO MULTIPLEXER DRIVER
+M:     Philipp Zabel <p.zabel@pengutronix.de>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     drivers/media/platform/video-mux.c
+
 VIDEOBUF2 FRAMEWORK
 M:     Pawel Osciak <pawel@osciak.com>
 M:     Marek Szyprowski <m.szyprowski@samsung.com>
@@ -13883,11 +13955,20 @@ S:    Maintained
 F:     drivers/media/v4l2-core/videobuf2-*
 F:     include/media/videobuf2-*
 
-VIDEO MULTIPLEXER DRIVER
-M:     Philipp Zabel <p.zabel@pengutronix.de>
+VIMC VIRTUAL MEDIA CONTROLLER DRIVER
+M:     Helen Koike <helen.koike@collabora.com>
 L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+W:     https://linuxtv.org
 S:     Maintained
-F:     drivers/media/platform/video-mux.c
+F:     drivers/media/platform/vimc/*
+
+VIRT LIB
+M:     Alex Williamson <alex.williamson@redhat.com>
+M:     Paolo Bonzini <pbonzini@redhat.com>
+L:     kvm@vger.kernel.org
+S:     Supported
+F:     virt/lib/
 
 VIRTIO AND VHOST VSOCK DRIVER
 M:     Stefan Hajnoczi <stefanha@redhat.com>
@@ -13905,12 +13986,6 @@ F:     drivers/net/vsockmon.c
 F:     drivers/vhost/vsock.c
 F:     drivers/vhost/vsock.h
 
-VIRTUAL SERIO DEVICE DRIVER
-M:     Stephen Chandler Paul <thatslyude@gmail.com>
-S:     Maintained
-F:     drivers/input/serio/userio.c
-F:     include/uapi/linux/userio.h
-
 VIRTIO CONSOLE DRIVER
 M:     Amit Shah <amit@kernel.org>
 L:     virtualization@lists.linux-foundation.org
@@ -13933,6 +14008,14 @@ F:     include/linux/virtio*.h
 F:     include/uapi/linux/virtio_*.h
 F:     drivers/crypto/virtio/
 
+VIRTIO CRYPTO DRIVER
+M:     Gonglei <arei.gonglei@huawei.com>
+L:     virtualization@lists.linux-foundation.org
+L:     linux-crypto@vger.kernel.org
+S:     Maintained
+F:     drivers/crypto/virtio/
+F:     include/uapi/linux/virtio_crypto.h
+
 VIRTIO DRIVERS FOR S390
 M:     Cornelia Huck <cohuck@redhat.com>
 M:     Halil Pasic <pasic@linux.vnet.ibm.com>
@@ -13969,45 +14052,11 @@ S:    Maintained
 F:     drivers/virtio/virtio_input.c
 F:     include/uapi/linux/virtio_input.h
 
-VIRTIO CRYPTO DRIVER
-M:  Gonglei <arei.gonglei@huawei.com>
-L:  virtualization@lists.linux-foundation.org
-L:  linux-crypto@vger.kernel.org
-S:  Maintained
-F:  drivers/crypto/virtio/
-F:  include/uapi/linux/virtio_crypto.h
-
-VIA RHINE NETWORK DRIVER
-S:     Orphan
-F:     drivers/net/ethernet/via/via-rhine.c
-
-VIA SD/MMC CARD CONTROLLER DRIVER
-M:     Bruce Chang <brucechang@via.com.tw>
-M:     Harald Welte <HaraldWelte@viatech.com>
-S:     Maintained
-F:     drivers/mmc/host/via-sdmmc.c
-
-VIA UNICHROME(PRO)/CHROME9 FRAMEBUFFER DRIVER
-M:     Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
-L:     linux-fbdev@vger.kernel.org
-S:     Maintained
-F:     include/linux/via-core.h
-F:     include/linux/via-gpio.h
-F:     include/linux/via_i2c.h
-F:     drivers/video/fbdev/via/
-
-VIA VELOCITY NETWORK DRIVER
-M:     Francois Romieu <romieu@fr.zoreil.com>
-L:     netdev@vger.kernel.org
+VIRTUAL SERIO DEVICE DRIVER
+M:     Stephen Chandler Paul <thatslyude@gmail.com>
 S:     Maintained
-F:     drivers/net/ethernet/via/via-velocity.*
-
-VIRT LIB
-M:     Alex Williamson <alex.williamson@redhat.com>
-M:     Paolo Bonzini <pbonzini@redhat.com>
-L:     kvm@vger.kernel.org
-S:     Supported
-F:     virt/lib/
+F:     drivers/input/serio/userio.c
+F:     include/uapi/linux/userio.h
 
 VIVID VIRTUAL VIDEO DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
@@ -14017,14 +14066,6 @@ W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/platform/vivid/*
 
-VIMC VIRTUAL MEDIA CONTROLLER DRIVER
-M:     Helen Koike <helen.koike@collabora.com>
-L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
-S:     Maintained
-F:     drivers/media/platform/vimc/*
-
 VLYNQ BUS
 M:     Florian Fainelli <f.fainelli@gmail.com>
 L:     openwrt-devel@lists.openwrt.org (subscribers-only)
@@ -14044,12 +14085,6 @@ F:     drivers/staging/vme/
 F:     drivers/vme/
 F:     include/linux/vme*
 
-VMWARE HYPERVISOR INTERFACE
-M:     Alok Kataria <akataria@vmware.com>
-L:     virtualization@lists.linux-foundation.org
-S:     Supported
-F:     arch/x86/kernel/cpu/vmware.c
-
 VMWARE BALLOON DRIVER
 M:     Xavier Deguillard <xdeguillard@vmware.com>
 M:     Philip Moltmann <moltmann@vmware.com>
@@ -14058,6 +14093,27 @@ L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/misc/vmw_balloon.c
 
+VMWARE HYPERVISOR INTERFACE
+M:     Alok Kataria <akataria@vmware.com>
+L:     virtualization@lists.linux-foundation.org
+S:     Supported
+F:     arch/x86/kernel/cpu/vmware.c
+
+VMWARE PVRDMA DRIVER
+M:     Adit Ranadive <aditr@vmware.com>
+M:     VMware PV-Drivers <pv-drivers@vmware.com>
+L:     linux-rdma@vger.kernel.org
+S:     Maintained
+F:     drivers/infiniband/hw/vmw_pvrdma/
+
+VMware PVSCSI driver
+M:     Jim Gill <jgill@vmware.com>
+M:     VMware PV-Drivers <pv-drivers@vmware.com>
+L:     linux-scsi@vger.kernel.org
+S:     Maintained
+F:     drivers/scsi/vmw_pvscsi.c
+F:     drivers/scsi/vmw_pvscsi.h
+
 VMWARE VMMOUSE SUBDRIVER
 M:     "VMware Graphics" <linux-graphics-maintainer@vmware.com>
 M:     "VMware, Inc." <pv-drivers@vmware.com>
@@ -14073,21 +14129,6 @@ L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/vmxnet3/
 
-VMware PVSCSI driver
-M:     Jim Gill <jgill@vmware.com>
-M:     VMware PV-Drivers <pv-drivers@vmware.com>
-L:     linux-scsi@vger.kernel.org
-S:     Maintained
-F:     drivers/scsi/vmw_pvscsi.c
-F:     drivers/scsi/vmw_pvscsi.h
-
-VMWARE PVRDMA DRIVER
-M:     Adit Ranadive <aditr@vmware.com>
-M:     VMware PV-Drivers <pv-drivers@vmware.com>
-L:     linux-rdma@vger.kernel.org
-S:     Maintained
-F:     drivers/infiniband/hw/vmw_pvrdma/
-
 VOLTAGE AND CURRENT REGULATOR FRAMEWORK
 M:     Liam Girdwood <lgirdwood@gmail.com>
 M:     Mark Brown <broonie@kernel.org>
@@ -14186,6 +14227,27 @@ L:     linux-input@vger.kernel.org
 S:     Maintained
 F:     drivers/hid/hid-wiimote*
 
+WILOCITY WIL6210 WIRELESS DRIVER
+M:     Maya Erez <qca_merez@qca.qualcomm.com>
+L:     linux-wireless@vger.kernel.org
+L:     wil6210@qca.qualcomm.com
+S:     Supported
+W:     http://wireless.kernel.org/en/users/Drivers/wil6210
+F:     drivers/net/wireless/ath/wil6210/
+F:     include/uapi/linux/wil6210_uapi.h
+
+WIMAX STACK
+M:     Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+M:     linux-wimax@intel.com
+L:     wimax@linuxwimax.org (subscribers-only)
+S:     Supported
+W:     http://linuxwimax.org
+F:     Documentation/wimax/README.wimax
+F:     include/linux/wimax/debug.h
+F:     include/net/wimax.h
+F:     include/uapi/linux/wimax.h
+F:     net/wimax/
+
 WINBOND CIR DRIVER
 M:     David Härdeman <david@hardeman.nu>
 S:     Maintained
@@ -14203,18 +14265,6 @@ L:     linux-gpio@vger.kernel.org
 S:     Maintained
 F:     drivers/gpio/gpio-ws16c48.c
 
-WIMAX STACK
-M:     Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
-M:     linux-wimax@intel.com
-L:     wimax@linuxwimax.org (subscribers-only)
-S:     Supported
-W:     http://linuxwimax.org
-F:     Documentation/wimax/README.wimax
-F:     include/linux/wimax/debug.h
-F:     include/net/wimax.h
-F:     include/uapi/linux/wimax.h
-F:     net/wimax/
-
 WISTRON LAPTOP BUTTON DRIVER
 M:     Miloslav Trmac <mitr@volny.cz>
 S:     Maintained
@@ -14299,15 +14349,6 @@ S:     Maintained
 F:     Documentation/x86/
 F:     arch/x86/
 
-X86 PLATFORM DRIVERS
-M:     Darren Hart <dvhart@infradead.org>
-M:     Andy Shevchenko <andy@infradead.org>
-L:     platform-driver-x86@vger.kernel.org
-T:     git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git
-S:     Maintained
-F:     drivers/platform/x86/
-F:     drivers/platform/olpc/
-
 X86 MCE INFRASTRUCTURE
 M:     Tony Luck <tony.luck@intel.com>
 M:     Borislav Petkov <bp@alien8.de>
@@ -14320,6 +14361,15 @@ M:     Borislav Petkov <bp@alien8.de>
 S:     Maintained
 F:     arch/x86/kernel/cpu/microcode/*
 
+X86 PLATFORM DRIVERS
+M:     Darren Hart <dvhart@infradead.org>
+M:     Andy Shevchenko <andy@infradead.org>
+L:     platform-driver-x86@vger.kernel.org
+T:     git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git
+S:     Maintained
+F:     drivers/platform/x86/
+F:     drivers/platform/olpc/
+
 X86 VDSO
 M:     Andy Lutomirski <luto@amacapital.net>
 L:     linux-kernel@vger.kernel.org
@@ -14336,20 +14386,13 @@ T:    git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/tuners/tuner-xc2028.*
 
-XEN HYPERVISOR INTERFACE
-M:     Boris Ostrovsky <boris.ostrovsky@oracle.com>
-M:     Juergen Gross <jgross@suse.com>
+XEN BLOCK SUBSYSTEM
+M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+M:     Roger Pau Monné <roger.pau@citrix.com>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git
 S:     Supported
-F:     arch/x86/xen/
-F:     drivers/*/xen-*front.c
-F:     drivers/xen/
-F:     arch/x86/include/asm/xen/
-F:     include/xen/
-F:     include/uapi/xen/
-F:     Documentation/ABI/stable/sysfs-hypervisor-xen
-F:     Documentation/ABI/testing/sysfs-hypervisor-xen
+F:     drivers/block/xen-blkback/*
+F:     drivers/block/xen*
 
 XEN HYPERVISOR ARM
 M:     Stefano Stabellini <sstabellini@kernel.org>
@@ -14365,6 +14408,21 @@ S:     Maintained
 F:     arch/arm64/xen/
 F:     arch/arm64/include/asm/xen/
 
+XEN HYPERVISOR INTERFACE
+M:     Boris Ostrovsky <boris.ostrovsky@oracle.com>
+M:     Juergen Gross <jgross@suse.com>
+L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git
+S:     Supported
+F:     arch/x86/xen/
+F:     drivers/*/xen-*front.c
+F:     drivers/xen/
+F:     arch/x86/include/asm/xen/
+F:     include/xen/
+F:     include/uapi/xen/
+F:     Documentation/ABI/stable/sysfs-hypervisor-xen
+F:     Documentation/ABI/testing/sysfs-hypervisor-xen
+
 XEN NETWORK BACKEND DRIVER
 M:     Wei Liu <wei.liu2@citrix.com>
 M:     Paul Durrant <paul.durrant@citrix.com>
@@ -14380,14 +14438,6 @@ S:     Supported
 F:     arch/x86/pci/*xen*
 F:     drivers/pci/*xen*
 
-XEN BLOCK SUBSYSTEM
-M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-M:     Roger Pau Monné <roger.pau@citrix.com>
-L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
-S:     Supported
-F:     drivers/block/xen-blkback/*
-F:     drivers/block/xen*
-
 XEN PVSCSI DRIVERS
 M:     Juergen Gross <jgross@suse.com>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
@@ -14464,6 +14514,13 @@ S:     Maintained
 F:     drivers/net/hamradio/yam*
 F:     include/linux/yam.h
 
+YAMA SECURITY MODULE
+M:     Kees Cook <keescook@chromium.org>
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip
+S:     Supported
+F:     security/yama/
+F:     Documentation/admin-guide/LSM/Yama.rst
+
 YEALINK PHONE DRIVER
 M:     Henk Vergonet <Henk.Vergonet@gmail.com>
 L:     usbb2k-api-dev@nongnu.org
@@ -14498,23 +14555,23 @@ L:    zd1211-devs@lists.sourceforge.net (subscribers-only)
 S:     Maintained
 F:     drivers/net/wireless/zydas/zd1211rw/
 
-ZD1301_DEMOD MEDIA DRIVER
+ZD1301 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
 W:     https://linuxtv.org/
 W:     http://palosaari.fi/linux/
 Q:     https://patchwork.linuxtv.org/project/linux-media/list/
 S:     Maintained
-F:     drivers/media/dvb-frontends/zd1301_demod*
+F:     drivers/media/usb/dvb-usb-v2/zd1301*
 
-ZD1301 MEDIA DRIVER
+ZD1301_DEMOD MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
 W:     https://linuxtv.org/
 W:     http://palosaari.fi/linux/
 Q:     https://patchwork.linuxtv.org/project/linux-media/list/
 S:     Maintained
-F:     drivers/media/usb/dvb-usb-v2/zd1301*
+F:     drivers/media/dvb-frontends/zd1301_demod*
 
 ZPOOL COMPRESSED PAGE STORAGE API
 M:     Dan Streetman <ddstreet@ieee.org>
index 547947f..37087b4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
-PATCHLEVEL = 12
+PATCHLEVEL = 13
 SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = -rc3
 NAME = Fearless Coyote
 
 # *DOCUMENTATION*
@@ -294,10 +294,17 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
          else if [ -x /bin/bash ]; then echo /bin/bash; \
          else echo sh; fi ; fi)
 
+HOST_LFS_CFLAGS := $(shell getconf LFS_CFLAGS)
+HOST_LFS_LDFLAGS := $(shell getconf LFS_LDFLAGS)
+HOST_LFS_LIBS := $(shell getconf LFS_LIBS)
+
 HOSTCC       = gcc
 HOSTCXX      = g++
-HOSTCFLAGS   := -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89
-HOSTCXXFLAGS = -O2
+HOSTCFLAGS   := -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 \
+               -fomit-frame-pointer -std=gnu89 $(HOST_LFS_CFLAGS)
+HOSTCXXFLAGS := -O2 $(HOST_LFS_CFLAGS)
+HOSTLDFLAGS  := $(HOST_LFS_LDFLAGS)
+HOST_LOADLIBES := $(HOST_LFS_LIBS)
 
 ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1)
 HOSTCFLAGS  += -Wno-unused-value -Wno-unused-parameter \
@@ -408,7 +415,7 @@ KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(S
 
 export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
 export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
-export CPP AR NM STRIP OBJCOPY OBJDUMP
+export CPP AR NM STRIP OBJCOPY OBJDUMP HOSTLDFLAGS HOST_LOADLIBES
 export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE
 export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
 
@@ -456,10 +463,11 @@ ifneq ($(KBUILD_SRC),)
 endif
 
 # Support for using generic headers in asm-generic
-PHONY += asm-generic
-asm-generic:
+PHONY += asm-generic uapi-asm-generic
+asm-generic: uapi-asm-generic
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.asm-generic \
                    src=asm obj=arch/$(SRCARCH)/include/generated/asm
+uapi-asm-generic:
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.asm-generic \
                    src=uapi/asm obj=arch/$(SRCARCH)/include/generated/uapi/asm
 
@@ -1136,7 +1144,7 @@ firmware_install:
 #Default location for installed headers
 export INSTALL_HDR_PATH = $(objtree)/usr
 
-# If we do an all arch process set dst to asm-$(hdr-arch)
+# If we do an all arch process set dst to include/arch-$(hdr-arch)
 hdr-dst = $(if $(KBUILD_HEADERS), dst=include/arch-$(hdr-arch), dst=include)
 
 PHONY += archheaders
@@ -1146,7 +1154,7 @@ PHONY += archscripts
 archscripts:
 
 PHONY += __headers
-__headers: $(version_h) scripts_basic asm-generic archheaders archscripts
+__headers: $(version_h) scripts_basic uapi-asm-generic archheaders archscripts
        $(Q)$(MAKE) $(build)=scripts build_unifdef
 
 PHONY += headers_install_all
@@ -1157,7 +1165,7 @@ PHONY += headers_install
 headers_install: __headers
        $(if $(wildcard $(srctree)/arch/$(hdr-arch)/include/uapi/asm/Kbuild),, \
          $(error Headers not exportable for the $(SRCARCH) architecture))
-       $(Q)$(MAKE) $(hdr-inst)=include/uapi
+       $(Q)$(MAKE) $(hdr-inst)=include/uapi dst=include
        $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi $(hdr-dst)
 
 PHONY += headers_check_all
@@ -1166,7 +1174,7 @@ headers_check_all: headers_install_all
 
 PHONY += headers_check
 headers_check: headers_install
-       $(Q)$(MAKE) $(hdr-inst)=include/uapi HDRCHECK=1
+       $(Q)$(MAKE) $(hdr-inst)=include/uapi dst=include HDRCHECK=1
        $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi $(hdr-dst) HDRCHECK=1
 
 # ---------------------------------------------------------------------------
index cae0958..21d0089 100644 (file)
@@ -198,9 +198,6 @@ config HAVE_KPROBES_ON_FTRACE
 config HAVE_NMI
        bool
 
-config HAVE_NMI_WATCHDOG
-       depends on HAVE_NMI
-       bool
 #
 # An arch should select this if it provides all these things:
 #
@@ -226,6 +223,12 @@ config GENERIC_SMP_IDLE_THREAD
 config GENERIC_IDLE_POLL_SETUP
        bool
 
+config ARCH_HAS_FORTIFY_SOURCE
+       bool
+       help
+         An architecture should select this when it can successfully
+         build and run with CONFIG_FORTIFY_SOURCE.
+
 # Select if arch has all set_memory_ro/rw/x/nx() functions in asm/cacheflush.h
 config ARCH_HAS_SET_MEMORY
        bool
@@ -288,6 +291,28 @@ config HAVE_PERF_EVENTS_NMI
          subsystem.  Also has support for calculating CPU cycle events
          to determine how many clock cycles in a given period.
 
+config HAVE_HARDLOCKUP_DETECTOR_PERF
+       bool
+       depends on HAVE_PERF_EVENTS_NMI
+       help
+         The arch chooses to use the generic perf-NMI-based hardlockup
+         detector. Must define HAVE_PERF_EVENTS_NMI.
+
+config HAVE_NMI_WATCHDOG
+       depends on HAVE_NMI
+       bool
+       help
+         The arch provides a low level NMI watchdog. It provides
+         asm/nmi.h, and defines its own arch_touch_nmi_watchdog().
+
+config HAVE_HARDLOCKUP_DETECTOR_ARCH
+       bool
+       select HAVE_NMI_WATCHDOG
+       help
+         The arch chooses to provide its own hardlockup detector, which is
+         a superset of the HAVE_NMI_WATCHDOG. It also conforms to config
+         interfaces and parameters provided by hardlockup detector subsystem.
+
 config HAVE_PERF_REGS
        bool
        help
index ff67b83..1cd7dc7 100644 (file)
 #define TIOCGPKT       _IOR('T', 0x38, int) /* Get packet mode state */
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
-#define TIOCGPTPEER    _IOR('T', 0x41, int) /* Safely open the slave */
+#define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
 
 #define TIOCSERCONFIG  0x5453
 #define TIOCSERGWILD   0x5454
index 3e74ca5..353dae3 100644 (file)
@@ -1,51 +1,27 @@
-generic-y += auxvec.h
-generic-y += bitsperlong.h
 generic-y += bugs.h
 generic-y += clkdev.h
 generic-y += device.h
 generic-y += div64.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += extable.h
 generic-y += fb.h
-generic-y += fcntl.h
 generic-y += ftrace.h
 generic-y += hardirq.h
 generic-y += hw_irq.h
-generic-y += ioctl.h
-generic-y += ioctls.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kmap_types.h
-generic-y += kvm_para.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
-generic-y += msgbuf.h
 generic-y += msi.h
-generic-y += param.h
 generic-y += parport.h
 generic-y += pci.h
 generic-y += percpu.h
-generic-y += poll.h
-generic-y += posix_types.h
 generic-y += preempt.h
-generic-y += resource.h
-generic-y += sembuf.h
-generic-y += shmbuf.h
-generic-y += socket.h
-generic-y += sockios.h
-generic-y += stat.h
-generic-y += statfs.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += topology.h
 generic-y += trace_clock.h
-generic-y += types.h
-generic-y += ucontext.h
 generic-y += user.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
index b55fc2a..fa6d0ff 100644 (file)
@@ -1,4 +1,28 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += auxvec.h
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += kvm_para.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += shmbuf.h
 generic-y += siginfo.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
+generic-y += ucontext.h
index 2a07e6e..71d3eff 100644 (file)
@@ -117,7 +117,7 @@ static int arc_dma_mmap(struct device *dev, struct vm_area_struct *vma,
 
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-       if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+       if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;
 
        if (off < count && user_count <= (count - off)) {
index d836050..721ab5e 100644 (file)
@@ -1,39 +1,23 @@
-
-
-generic-y += bitsperlong.h
 generic-y += clkdev.h
 generic-y += current.h
 generic-y += early_ioremap.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += exec.h
 generic-y += extable.h
-generic-y += ioctl.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mm-arch-hooks.h
-generic-y += msgbuf.h
 generic-y += msi.h
-generic-y += param.h
 generic-y += parport.h
-generic-y += poll.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += rwsem.h
 generic-y += seccomp.h
 generic-y += segment.h
-generic-y += sembuf.h
 generic-y += serial.h
-generic-y += shmbuf.h
 generic-y += simd.h
 generic-y += sizes.h
-generic-y += socket.h
-generic-y += sockios.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += timex.h
 generic-y += trace_clock.h
 generic-y += unaligned.h
index 4e6e88a..2244a94 100644 (file)
@@ -37,7 +37,7 @@ do {                                                          \
                ".pushsection .rodata.str, \"aMS\", %progbits, 1\n" \
                "2:\t.asciz " #__file "\n"                      \
                ".popsection\n"                                 \
-               ".pushsection __bug_table,\"a\"\n"              \
+               ".pushsection __bug_table,\"aw\"\n"             \
                ".align 2\n"                                    \
                "3:\t.word 1b, 2b\n"                            \
                "\t.hword " #__line ", 0\n"                     \
index d69bebf..74504b1 100644 (file)
@@ -116,7 +116,7 @@ struct cpu_cache_fns {
        void (*dma_unmap_area)(const void *, size_t, int);
 
        void (*dma_flush_range)(const void *, const void *);
-};
+} __no_randomize_layout;
 
 /*
  * Select the calling method
index acf1d14..29d3a15 100644 (file)
@@ -5,12 +5,31 @@
 #ifndef __ARM_FLAT_H__
 #define __ARM_FLAT_H__
 
+#include <linux/uaccess.h>
+
 #define        flat_argvp_envp_on_stack()              1
 #define        flat_old_ram_flag(flags)                (flags)
 #define        flat_reloc_valid(reloc, size)           ((reloc) <= (size))
-#define        flat_get_addr_from_rp(rp, relval, flags, persistent) \
-       ({ unsigned long __val; __get_user_unaligned(__val, rp); __val; })
-#define        flat_put_addr_at_rp(rp, val, relval)    __put_user_unaligned(val, rp)
+
+static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
+                                       u32 *addr, u32 *persistent)
+{
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+       return copy_from_user(addr, rp, 4) ? -EFAULT : 0;
+#else
+       return get_user(*addr, rp);
+#endif
+}
+
+static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel)
+{
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+       return copy_to_user(rp, &addr, 4) ? -EFAULT : 0;
+#else
+       return put_user(addr, rp);
+#endif
+}
+
 #define        flat_get_relocate_addr(rel)             (rel)
 #define        flat_set_persistent(relval, p)          0
 
index 1869af6..25021b7 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#define ARCH_HAS_KIMAGE_ARCH
+struct kimage_arch {
+       u32 kernel_r2;
+};
+
 /**
  * crash_setup_regs() - save registers for the panic kernel
  * @newregs: registers are saved here
index 5850890..14b5903 100644 (file)
@@ -110,8 +110,8 @@ void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
 
-void asmlinkage __vfp_save_state(struct vfp_hard_struct *vfp);
-void asmlinkage __vfp_restore_state(struct vfp_hard_struct *vfp);
+asmlinkage void __vfp_save_state(struct vfp_hard_struct *vfp);
+asmlinkage void __vfp_restore_state(struct vfp_hard_struct *vfp);
 static inline bool __vfp_enabled(void)
 {
        return !(read_sysreg(HCPTR) & (HCPTR_TCP(11) | HCPTR_TCP(10)));
@@ -120,8 +120,8 @@ static inline bool __vfp_enabled(void)
 void __hyp_text __banked_save_state(struct kvm_cpu_context *ctxt);
 void __hyp_text __banked_restore_state(struct kvm_cpu_context *ctxt);
 
-int asmlinkage __guest_enter(struct kvm_vcpu *vcpu,
+asmlinkage int __guest_enter(struct kvm_vcpu *vcpu,
                             struct kvm_cpu_context *host);
-int asmlinkage __hyp_do_panic(const char *, int, u32);
+asmlinkage int __hyp_do_panic(const char *, int, u32);
 
 #endif /* __ARM_KVM_HYP_H__ */
index 6838abc..0bf2347 100644 (file)
 #include <asm/unified.h>
 #include <asm/compiler.h>
 
-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
-#include <asm-generic/uaccess-unaligned.h>
-#else
-#define __get_user_unaligned __get_user
-#define __put_user_unaligned __put_user
-#endif
-
 #include <asm/extable.h>
 
 /*
index 14749ae..921d827 100644 (file)
@@ -35,6 +35,12 @@ struct ucontext {
  * bytes, to prevent unpredictable padding in the signal frame.
  */
 
+/*
+ * Dummy padding block: if this magic is encountered, the block should
+ * be skipped using the corresponding size field.
+ */
+#define DUMMY_MAGIC            0xb0d9ed01
+
 #ifdef CONFIG_CRUNCH
 #define CRUNCH_MAGIC           0x5065cf03
 #define CRUNCH_STORAGE_SIZE    (CRUNCH_SIZE + 8)
index 5fb3368..8e17fe8 100644 (file)
@@ -5,4 +5,18 @@ generated-y += unistd-common.h
 generated-y += unistd-oabi.h
 generated-y += unistd-eabi.h
 
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += ioctl.h
+generic-y += ipcbuf.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += poll.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += shmbuf.h
 generic-y += siginfo.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += termbits.h
+generic-y += termios.h
index 56dc1a3..c1809fb 100644 (file)
@@ -480,7 +480,7 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
 
                        ret = pcibios_init_resource(nr, sys, hw->io_optional);
                        if (ret)  {
-                               kfree(sys);
+                               pci_free_host_bridge(bridge);
                                break;
                        }
 
index 1549588..fe1419e 100644 (file)
@@ -30,7 +30,6 @@ extern unsigned long kexec_boot_atags;
 
 static atomic_t waiting_for_crash_ipi;
 
-static unsigned long dt_mem;
 /*
  * Provide a dummy crash_notes definition while crash dump arrives to arm.
  * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
@@ -42,6 +41,9 @@ int machine_kexec_prepare(struct kimage *image)
        __be32 header;
        int i, err;
 
+       image->arch.kernel_r2 = image->start - KEXEC_ARM_ZIMAGE_OFFSET
+                                    + KEXEC_ARM_ATAGS_OFFSET;
+
        /*
         * Validate that if the current HW supports SMP, then the SW supports
         * and implements CPU hotplug for the current HW. If not, we won't be
@@ -66,8 +68,8 @@ int machine_kexec_prepare(struct kimage *image)
                if (err)
                        return err;
 
-               if (be32_to_cpu(header) == OF_DT_HEADER)
-                       dt_mem = current_segment->mem;
+               if (header == cpu_to_be32(OF_DT_HEADER))
+                       image->arch.kernel_r2 = current_segment->mem;
        }
        return 0;
 }
@@ -165,8 +167,7 @@ void machine_kexec(struct kimage *image)
        kexec_start_address = image->start;
        kexec_indirection_page = page_list;
        kexec_mach_type = machine_arch_type;
-       kexec_boot_atags = dt_mem ?: image->start - KEXEC_ARM_ZIMAGE_OFFSET
-                                    + KEXEC_ARM_ATAGS_OFFSET;
+       kexec_boot_atags = image->arch.kernel_r2;
 
        /* copy our kernel relocation code to the control code page */
        reboot_entry = fncpy(reboot_code_buffer,
index 4e80bf7..8e9a3e4 100644 (file)
@@ -987,6 +987,9 @@ static void __init reserve_crashkernel(void)
 
        if (crash_base <= 0) {
                unsigned long long crash_max = idmap_to_phys((u32)~0);
+               unsigned long long lowmem_max = __pa(high_memory - 1) + 1;
+               if (crash_max > lowmem_max)
+                       crash_max = lowmem_max;
                crash_base = memblock_find_in_range(CRASH_ALIGN, crash_max,
                                                    crash_size, CRASH_ALIGN);
                if (!crash_base) {
index 7b8f214..5814298 100644 (file)
@@ -40,8 +40,10 @@ static int preserve_crunch_context(struct crunch_sigframe __user *frame)
        return __copy_to_user(frame, kframe, sizeof(*frame));
 }
 
-static int restore_crunch_context(struct crunch_sigframe __user *frame)
+static int restore_crunch_context(char __user **auxp)
 {
+       struct crunch_sigframe __user *frame =
+               (struct crunch_sigframe __user *)*auxp;
        char kbuf[sizeof(*frame) + 8];
        struct crunch_sigframe *kframe;
 
@@ -52,6 +54,7 @@ static int restore_crunch_context(struct crunch_sigframe __user *frame)
        if (kframe->magic != CRUNCH_MAGIC ||
            kframe->size != CRUNCH_STORAGE_SIZE)
                return -1;
+       *auxp += CRUNCH_STORAGE_SIZE;
        crunch_task_restore(current_thread_info(), &kframe->storage);
        return 0;
 }
@@ -59,21 +62,39 @@ static int restore_crunch_context(struct crunch_sigframe __user *frame)
 
 #ifdef CONFIG_IWMMXT
 
-static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
+static int preserve_iwmmxt_context(struct iwmmxt_sigframe __user *frame)
 {
        char kbuf[sizeof(*frame) + 8];
        struct iwmmxt_sigframe *kframe;
+       int err = 0;
 
        /* the iWMMXt context must be 64 bit aligned */
        kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7);
-       kframe->magic = IWMMXT_MAGIC;
-       kframe->size = IWMMXT_STORAGE_SIZE;
-       iwmmxt_task_copy(current_thread_info(), &kframe->storage);
-       return __copy_to_user(frame, kframe, sizeof(*frame));
+
+       if (test_thread_flag(TIF_USING_IWMMXT)) {
+               kframe->magic = IWMMXT_MAGIC;
+               kframe->size = IWMMXT_STORAGE_SIZE;
+               iwmmxt_task_copy(current_thread_info(), &kframe->storage);
+
+               err = __copy_to_user(frame, kframe, sizeof(*frame));
+       } else {
+               /*
+                * For bug-compatibility with older kernels, some space
+                * has to be reserved for iWMMXt even if it's not used.
+                * Set the magic and size appropriately so that properly
+                * written userspace can skip it reliably:
+                */
+               __put_user_error(DUMMY_MAGIC, &frame->magic, err);
+               __put_user_error(IWMMXT_STORAGE_SIZE, &frame->size, err);
+       }
+
+       return err;
 }
 
-static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)
+static int restore_iwmmxt_context(char __user **auxp)
 {
+       struct iwmmxt_sigframe __user *frame =
+               (struct iwmmxt_sigframe __user *)*auxp;
        char kbuf[sizeof(*frame) + 8];
        struct iwmmxt_sigframe *kframe;
 
@@ -81,10 +102,28 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)
        kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7);
        if (__copy_from_user(kframe, frame, sizeof(*frame)))
                return -1;
-       if (kframe->magic != IWMMXT_MAGIC ||
-           kframe->size != IWMMXT_STORAGE_SIZE)
+
+       /*
+        * For non-iWMMXt threads: a single iwmmxt_sigframe-sized dummy
+        * block is discarded for compatibility with setup_sigframe() if
+        * present, but we don't mandate its presence.  If some other
+        * magic is here, it's not for us:
+        */
+       if (!test_thread_flag(TIF_USING_IWMMXT) &&
+           kframe->magic != DUMMY_MAGIC)
+               return 0;
+
+       if (kframe->size != IWMMXT_STORAGE_SIZE)
                return -1;
-       iwmmxt_task_restore(current_thread_info(), &kframe->storage);
+
+       if (test_thread_flag(TIF_USING_IWMMXT)) {
+               if (kframe->magic != IWMMXT_MAGIC)
+                       return -1;
+
+               iwmmxt_task_restore(current_thread_info(), &kframe->storage);
+       }
+
+       *auxp += IWMMXT_STORAGE_SIZE;
        return 0;
 }
 
@@ -107,8 +146,10 @@ static int preserve_vfp_context(struct vfp_sigframe __user *frame)
        return vfp_preserve_user_clear_hwstate(&frame->ufp, &frame->ufp_exc);
 }
 
-static int restore_vfp_context(struct vfp_sigframe __user *frame)
+static int restore_vfp_context(char __user **auxp)
 {
+       struct vfp_sigframe __user *frame =
+               (struct vfp_sigframe __user *)*auxp;
        unsigned long magic;
        unsigned long size;
        int err = 0;
@@ -121,6 +162,7 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame)
        if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE)
                return -EINVAL;
 
+       *auxp += size;
        return vfp_restore_user_hwstate(&frame->ufp, &frame->ufp_exc);
 }
 
@@ -141,7 +183,7 @@ struct rt_sigframe {
 
 static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
 {
-       struct aux_sigframe __user *aux;
+       char __user *aux;
        sigset_t set;
        int err;
 
@@ -169,18 +211,18 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
 
        err |= !valid_user_regs(regs);
 
-       aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
+       aux = (char __user *) sf->uc.uc_regspace;
 #ifdef CONFIG_CRUNCH
        if (err == 0)
-               err |= restore_crunch_context(&aux->crunch);
+               err |= restore_crunch_context(&aux);
 #endif
 #ifdef CONFIG_IWMMXT
-       if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
-               err |= restore_iwmmxt_context(&aux->iwmmxt);
+       if (err == 0)
+               err |= restore_iwmmxt_context(&aux);
 #endif
 #ifdef CONFIG_VFP
        if (err == 0)
-               err |= restore_vfp_context(&aux->vfp);
+               err |= restore_vfp_context(&aux);
 #endif
 
        return err;
@@ -286,7 +328,7 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
                err |= preserve_crunch_context(&aux->crunch);
 #endif
 #ifdef CONFIG_IWMMXT
-       if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
+       if (err == 0)
                err |= preserve_iwmmxt_context(&aux->iwmmxt);
 #endif
 #ifdef CONFIG_VFP
index be517b0..5b61438 100644 (file)
@@ -32,120 +32,6 @@ static u16 control_devconf1_offset;
 
 #define HSMMC_NAME_LEN 9
 
-static void omap_hsmmc1_before_set_reg(struct device *dev,
-                                      int power_on, int vdd)
-{
-       u32 reg, prog_io;
-       struct omap_hsmmc_platform_data *mmc = dev->platform_data;
-
-       if (mmc->remux)
-               mmc->remux(dev, power_on);
-
-       /*
-        * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the
-        * card with Vcc regulator (from twl4030 or whatever).  OMAP has both
-        * 1.8V and 3.0V modes, controlled by the PBIAS register.
-        *
-        * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which
-        * is most naturally TWL VSIM; those pins also use PBIAS.
-        *
-        * FIXME handle VMMC1A as needed ...
-        */
-       if (power_on) {
-               if (cpu_is_omap2430()) {
-                       reg = omap_ctrl_readl(OMAP243X_CONTROL_DEVCONF1);
-                       if ((1 << vdd) >= MMC_VDD_30_31)
-                               reg |= OMAP243X_MMC1_ACTIVE_OVERWRITE;
-                       else
-                               reg &= ~OMAP243X_MMC1_ACTIVE_OVERWRITE;
-                       omap_ctrl_writel(reg, OMAP243X_CONTROL_DEVCONF1);
-               }
-
-               if (mmc->internal_clock) {
-                       reg = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
-                       reg |= OMAP2_MMCSDIO1ADPCLKISEL;
-                       omap_ctrl_writel(reg, OMAP2_CONTROL_DEVCONF0);
-               }
-
-               reg = omap_ctrl_readl(control_pbias_offset);
-               if (cpu_is_omap3630()) {
-                       /* Set MMC I/O to 52MHz */
-                       prog_io = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1);
-                       prog_io |= OMAP3630_PRG_SDMMC1_SPEEDCTRL;
-                       omap_ctrl_writel(prog_io, OMAP343X_CONTROL_PROG_IO1);
-               } else {
-                       reg |= OMAP2_PBIASSPEEDCTRL0;
-               }
-               reg &= ~OMAP2_PBIASLITEPWRDNZ0;
-               omap_ctrl_writel(reg, control_pbias_offset);
-       } else {
-               reg = omap_ctrl_readl(control_pbias_offset);
-               reg &= ~OMAP2_PBIASLITEPWRDNZ0;
-               omap_ctrl_writel(reg, control_pbias_offset);
-       }
-}
-
-static void omap_hsmmc1_after_set_reg(struct device *dev, int power_on, int vdd)
-{
-       u32 reg;
-
-       /* 100ms delay required for PBIAS configuration */
-       msleep(100);
-
-       if (power_on) {
-               reg = omap_ctrl_readl(control_pbias_offset);
-               reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0);
-               if ((1 << vdd) <= MMC_VDD_165_195)
-                       reg &= ~OMAP2_PBIASLITEVMODE0;
-               else
-                       reg |= OMAP2_PBIASLITEVMODE0;
-               omap_ctrl_writel(reg, control_pbias_offset);
-       } else {
-               reg = omap_ctrl_readl(control_pbias_offset);
-               reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 |
-                       OMAP2_PBIASLITEVMODE0);
-               omap_ctrl_writel(reg, control_pbias_offset);
-       }
-}
-
-static void hsmmc2_select_input_clk_src(struct omap_hsmmc_platform_data *mmc)
-{
-       u32 reg;
-
-       reg = omap_ctrl_readl(control_devconf1_offset);
-       if (mmc->internal_clock)
-               reg |= OMAP2_MMCSDIO2ADPCLKISEL;
-       else
-               reg &= ~OMAP2_MMCSDIO2ADPCLKISEL;
-       omap_ctrl_writel(reg, control_devconf1_offset);
-}
-
-static void hsmmc2_before_set_reg(struct device *dev, int power_on, int vdd)
-{
-       struct omap_hsmmc_platform_data *mmc = dev->platform_data;
-
-       if (mmc->remux)
-               mmc->remux(dev, power_on);
-
-       if (power_on)
-               hsmmc2_select_input_clk_src(mmc);
-}
-
-static int am35x_hsmmc2_set_power(struct device *dev, int power_on, int vdd)
-{
-       struct omap_hsmmc_platform_data *mmc = dev->platform_data;
-
-       if (power_on)
-               hsmmc2_select_input_clk_src(mmc);
-
-       return 0;
-}
-
-static int nop_mmc_set_power(struct device *dev, int power_on, int vdd)
-{
-       return 0;
-}
-
 static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
                                        struct omap_hsmmc_platform_data *mmc)
 {
@@ -157,101 +43,11 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
                return -ENOMEM;
        }
 
-       if (c->name)
-               strncpy(hc_name, c->name, HSMMC_NAME_LEN);
-       else
-               snprintf(hc_name, (HSMMC_NAME_LEN + 1), "mmc%islot%i",
-                                                               c->mmc, 1);
+       snprintf(hc_name, (HSMMC_NAME_LEN + 1), "mmc%islot%i", c->mmc, 1);
        mmc->name = hc_name;
        mmc->caps = c->caps;
-       mmc->internal_clock = !c->ext_clock;
        mmc->reg_offset = 0;
 
-       if (c->cover_only) {
-               /* detect if mobile phone cover removed */
-               mmc->gpio_cd = -EINVAL;
-               mmc->gpio_cod = c->gpio_cd;
-       } else {
-               /* card detect pin on the mmc socket itself */
-               mmc->gpio_cd = c->gpio_cd;
-               mmc->gpio_cod = -EINVAL;
-       }
-       mmc->gpio_wp = c->gpio_wp;
-
-       mmc->remux = c->remux;
-       mmc->init_card = c->init_card;
-
-       if (c->nonremovable)
-               mmc->nonremovable = 1;
-
-       /*
-        * NOTE:  MMC slots should have a Vcc regulator set up.
-        * This may be from a TWL4030-family chip, another
-        * controllable regulator, or a fixed supply.
-        *
-        * temporary HACK: ocr_mask instead of fixed supply
-        */
-       if (soc_is_am35xx())
-               mmc->ocr_mask = MMC_VDD_165_195 |
-                                        MMC_VDD_26_27 |
-                                        MMC_VDD_27_28 |
-                                        MMC_VDD_29_30 |
-                                        MMC_VDD_30_31 |
-                                        MMC_VDD_31_32;
-       else
-               mmc->ocr_mask = c->ocr_mask;
-
-       if (!soc_is_am35xx())
-               mmc->features |= HSMMC_HAS_PBIAS;
-
-       switch (c->mmc) {
-       case 1:
-               if (mmc->features & HSMMC_HAS_PBIAS) {
-                       /* on-chip level shifting via PBIAS0/PBIAS1 */
-                       mmc->before_set_reg =
-                                       omap_hsmmc1_before_set_reg;
-                       mmc->after_set_reg =
-                                       omap_hsmmc1_after_set_reg;
-               }
-
-               if (soc_is_am35xx())
-                       mmc->set_power = nop_mmc_set_power;
-
-               /* OMAP3630 HSMMC1 supports only 4-bit */
-               if (cpu_is_omap3630() &&
-                               (c->caps & MMC_CAP_8_BIT_DATA)) {
-                       c->caps &= ~MMC_CAP_8_BIT_DATA;
-                       c->caps |= MMC_CAP_4_BIT_DATA;
-                       mmc->caps = c->caps;
-               }
-               break;
-       case 2:
-               if (soc_is_am35xx())
-                       mmc->set_power = am35x_hsmmc2_set_power;
-
-               if (c->ext_clock)
-                       c->transceiver = 1;
-               if (c->transceiver && (c->caps & MMC_CAP_8_BIT_DATA)) {
-                       c->caps &= ~MMC_CAP_8_BIT_DATA;
-                       c->caps |= MMC_CAP_4_BIT_DATA;
-               }
-               if (mmc->features & HSMMC_HAS_PBIAS) {
-                       /* off-chip level shifting, or none */
-                       mmc->before_set_reg = hsmmc2_before_set_reg;
-                       mmc->after_set_reg = NULL;
-               }
-               break;
-       case 3:
-       case 4:
-       case 5:
-               mmc->before_set_reg = NULL;
-               mmc->after_set_reg = NULL;
-               break;
-       default:
-               pr_err("MMC%d configuration not supported!\n", c->mmc);
-               kfree(hc_name);
-               return -ENODEV;
-       }
        return 0;
 }
 
@@ -260,7 +56,6 @@ static int omap_hsmmc_done;
 void omap_hsmmc_late_init(struct omap2_hsmmc_info *c)
 {
        struct platform_device *pdev;
-       struct omap_hsmmc_platform_data *mmc_pdata;
        int res;
 
        if (omap_hsmmc_done != 1)
@@ -269,32 +64,12 @@ void omap_hsmmc_late_init(struct omap2_hsmmc_info *c)
        omap_hsmmc_done++;
 
        for (; c->mmc; c++) {
-               if (!c->deferred)
-                       continue;
-
                pdev = c->pdev;
                if (!pdev)
                        continue;
-
-               mmc_pdata = pdev->dev.platform_data;
-               if (!mmc_pdata)
-                       continue;
-
-               if (c->cover_only) {
-                       /* detect if mobile phone cover removed */
-                       mmc_pdata->gpio_cd = -EINVAL;
-                       mmc_pdata->gpio_cod = c->gpio_cd;
-               } else {
-                       /* card detect pin on the mmc socket itself */
-                       mmc_pdata->gpio_cd = c->gpio_cd;
-                       mmc_pdata->gpio_cod = -EINVAL;
-               }
-               mmc_pdata->gpio_wp = c->gpio_wp;
-
                res = omap_device_register(pdev);
                if (res)
-                       pr_err("Could not late init MMC %s\n",
-                              c->name);
+                       pr_err("Could not late init MMC\n");
        }
 }
 
@@ -336,13 +111,6 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo,
        if (oh->dev_attr != NULL) {
                mmc_dev_attr = oh->dev_attr;
                mmc_data->controller_flags = mmc_dev_attr->flags;
-               /*
-                * erratum 2.1.1.128 doesn't apply if board has
-                * a transceiver is attached
-                */
-               if (hsmmcinfo->transceiver)
-                       mmc_data->controller_flags &=
-                               ~OMAP_HSMMC_BROKEN_MULTIBLOCK_READ;
        }
 
        pdev = platform_device_alloc(name, ctrl_nr - 1);
@@ -367,9 +135,6 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo,
 
        hsmmcinfo->pdev = pdev;
 
-       if (hsmmcinfo->deferred)
-               goto free_mmc;
-
        res = omap_device_register(pdev);
        if (res) {
                pr_err("Could not register od for %s\n", name);
index 69b619d..af9af50 100644 (file)
@@ -12,18 +12,9 @@ struct omap2_hsmmc_info {
        u8      mmc;            /* controller 1/2/3 */
        u32     caps;           /* 4/8 wires and any additional host
                                 * capabilities OR'd (ref. linux/mmc/host.h) */
-       bool    transceiver;    /* MMC-2 option */
-       bool    ext_clock;      /* use external pin for input clock */
-       bool    cover_only;     /* No card detect - just cover switch */
-       bool    nonremovable;   /* Nonremovable e.g. eMMC */
-       bool    deferred;       /* mmc needs a deferred probe */
        int     gpio_cd;        /* or -EINVAL */
        int     gpio_wp;        /* or -EINVAL */
-       char    *name;          /* or NULL for default */
        struct platform_device *pdev;   /* mmc controller instance */
-       int     ocr_mask;       /* temporary HACK */
-       /* Remux (pad configuration) when powering on/off */
-       void (*remux)(struct device *dev, int power_on);
        /* init some special card */
        void (*init_card)(struct mmc_card *card);
 };
index b143c46..7fc11a3 100644 (file)
@@ -33,7 +33,7 @@ static unsigned long jornada_ssp_flags;
  * we need to reverse all data we receive from the mcu due to its physical location
  * returns : 01110111 -> 11101110
  */
-u8 inline jornada_ssp_reverse(u8 byte)
+inline u8 jornada_ssp_reverse(u8 byte)
 {
        return
                ((0x80 & byte) >> 7) |
index 28083ef..71a34e8 100644 (file)
@@ -133,6 +133,7 @@ static irqreturn_t db8500_pmu_handler(int irq, void *dev, irq_handler_t handler)
 
 static struct arm_pmu_platdata db8500_pmu_platdata = {
        .handle_irq             = db8500_pmu_handler,
+       .irq_flags              = IRQF_NOBALANCING | IRQF_NO_THREAD,
 };
 
 static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
index 90ee354..6db5fc2 100644 (file)
@@ -40,9 +40,21 @@ static void *arm_nommu_dma_alloc(struct device *dev, size_t size,
 
 {
        const struct dma_map_ops *ops = &dma_noop_ops;
+       void *ret;
 
        /*
-        * We are here because:
+        * Try generic allocator first if we are advertised that
+        * consistency is not required.
+        */
+
+       if (attrs & DMA_ATTR_NON_CONSISTENT)
+               return ops->alloc(dev, size, dma_handle, gfp, attrs);
+
+       ret = dma_alloc_from_global_coherent(size, dma_handle);
+
+       /*
+        * dma_alloc_from_global_coherent() may fail because:
+        *
         * - no consistent DMA region has been defined, so we can't
         *   continue.
         * - there is no space left in consistent DMA region, so we
@@ -50,11 +62,8 @@ static void *arm_nommu_dma_alloc(struct device *dev, size_t size,
         *   advertised that consistency is not required.
         */
 
-       if (attrs & DMA_ATTR_NON_CONSISTENT)
-               return ops->alloc(dev, size, dma_handle, gfp, attrs);
-
-       WARN_ON_ONCE(1);
-       return NULL;
+       WARN_ON_ONCE(ret == NULL);
+       return ret;
 }
 
 static void arm_nommu_dma_free(struct device *dev, size_t size,
@@ -63,14 +72,31 @@ static void arm_nommu_dma_free(struct device *dev, size_t size,
 {
        const struct dma_map_ops *ops = &dma_noop_ops;
 
-       if (attrs & DMA_ATTR_NON_CONSISTENT)
+       if (attrs & DMA_ATTR_NON_CONSISTENT) {
                ops->free(dev, size, cpu_addr, dma_addr, attrs);
-       else
-               WARN_ON_ONCE(1);
+       } else {
+               int ret = dma_release_from_global_coherent(get_order(size),
+                                                          cpu_addr);
+
+               WARN_ON_ONCE(ret == 0);
+       }
 
        return;
 }
 
+static int arm_nommu_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+                             void *cpu_addr, dma_addr_t dma_addr, size_t size,
+                             unsigned long attrs)
+{
+       int ret;
+
+       if (dma_mmap_from_global_coherent(vma, cpu_addr, size, &ret))
+               return ret;
+
+       return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+
+
 static void __dma_page_cpu_to_dev(phys_addr_t paddr, size_t size,
                                  enum dma_data_direction dir)
 {
@@ -173,6 +199,7 @@ static void arm_nommu_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist
 const struct dma_map_ops arm_nommu_dma_ops = {
        .alloc                  = arm_nommu_dma_alloc,
        .free                   = arm_nommu_dma_free,
+       .mmap                   = arm_nommu_dma_mmap,
        .map_page               = arm_nommu_dma_map_page,
        .unmap_page             = arm_nommu_dma_unmap_page,
        .map_sg                 = arm_nommu_dma_map_sg,
index e7380ba..fcf1473 100644 (file)
@@ -851,7 +851,7 @@ static int __arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
        unsigned long pfn = dma_to_pfn(dev, dma_addr);
        unsigned long off = vma->vm_pgoff;
 
-       if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+       if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;
 
        if (off < nr_pages && nr_vma_pages <= (nr_pages - off)) {
index 8addb85..dfd9086 100644 (file)
@@ -12,6 +12,7 @@ config ARM64
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
        select ARCH_HAS_ELF_RANDOMIZE
+       select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_GCOV_PROFILE_ALL
        select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA
        select ARCH_HAS_KCOV
index a7a97a6..f81c7b6 100644 (file)
@@ -6,41 +6,24 @@ generic-y += dma.h
 generic-y += dma-contiguous.h
 generic-y += early_ioremap.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += hw_irq.h
-generic-y += ioctl.h
-generic-y += ioctls.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
-generic-y += kvm_para.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
-generic-y += msgbuf.h
 generic-y += msi.h
-generic-y += poll.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += rwsem.h
 generic-y += segment.h
-generic-y += sembuf.h
 generic-y += serial.h
 generic-y += set_memory.h
-generic-y += shmbuf.h
 generic-y += simd.h
 generic-y += sizes.h
-generic-y += socket.h
-generic-y += sockios.h
-generic-y += swab.h
 generic-y += switch_to.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += trace_clock.h
-generic-y += types.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
index 99fa69c..9ef0797 100644 (file)
@@ -435,7 +435,7 @@ static inline long atomic64_dec_if_positive(atomic64_t *v)
        "       sub     x30, x30, %[ret]\n"
        "       cbnz    x30, 1b\n"
        "2:")
-       : [ret] "+&r" (x0), [v] "+Q" (v->counter)
+       : [ret] "+r" (x0), [v] "+Q" (v->counter)
        :
        : __LL_SC_CLOBBERS, "cc", "memory");
 
index 366448e..a02a571 100644 (file)
@@ -36,7 +36,7 @@
 #ifdef CONFIG_GENERIC_BUG
 
 #define __BUG_ENTRY(flags)                             \
-               ".pushsection __bug_table,\"a\"\n\t"    \
+               ".pushsection __bug_table,\"aw\"\n\t"   \
                ".align 2\n\t"                          \
        "0:     .long 1f - 0b\n\t"                      \
 _BUGVERBOSE_LOCATION(__FILE__, __LINE__)               \
index fe5e287..b86a086 100644 (file)
@@ -30,6 +30,7 @@ static __always_inline void boot_init_stack_canary(void)
        /* Try to get a semi random initial value. */
        get_random_bytes(&canary, sizeof(canary));
        canary ^= LINUX_VERSION_CODE;
+       canary &= CANARY_MASK;
 
        current->stack_canary = canary;
        __stack_chk_guard = current->stack_canary;
index 2eb714c..d0aa429 100644 (file)
@@ -63,6 +63,11 @@ extern int memcmp(const void *, const void *, size_t);
 #define memcpy(dst, src, len) __memcpy(dst, src, len)
 #define memmove(dst, src, len) __memmove(dst, src, len)
 #define memset(s, c, n) __memset(s, c, n)
+
+#ifndef __NO_FORTIFY
+#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */
+#endif
+
 #endif
 
 #endif
index 16e44fa..248339e 100644 (file)
@@ -492,7 +492,7 @@ asm(
  * the "%x0" template means XZR.
  */
 #define write_sysreg(v, r) do {                                        \
-       u64 __val = (u64)v;                                     \
+       u64 __val = (u64)(v);                                   \
        asm volatile("msr " __stringify(r) ", %x0"              \
                     : : "rZ" (__val));                         \
 } while (0)
@@ -508,7 +508,7 @@ asm(
 })
 
 #define write_sysreg_s(v, r) do {                                      \
-       u64 __val = (u64)v;                                             \
+       u64 __val = (u64)(v);                                           \
        asm volatile("msr_s " __stringify(r) ", %x0" : : "rZ" (__val)); \
 } while (0)
 
index 59f09e6..fab46a0 100644 (file)
@@ -69,7 +69,7 @@ static inline void set_fs(mm_segment_t fs)
  */
 #define __range_ok(addr, size)                                         \
 ({                                                                     \
-       unsigned long __addr = (unsigned long __force)(addr);           \
+       unsigned long __addr = (unsigned long)(addr);                   \
        unsigned long flag, roksum;                                     \
        __chk_user_ptr(addr);                                           \
        asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls"         \
@@ -254,8 +254,6 @@ do {                                                                        \
        (void)0;                                                        \
 })
 
-#define __get_user_unaligned __get_user
-
 #define get_user(x, ptr)                                               \
 ({                                                                     \
        __typeof__(*(ptr)) __user *__p = (ptr);                         \
@@ -320,8 +318,6 @@ do {                                                                        \
        (void)0;                                                        \
 })
 
-#define __put_user_unaligned __put_user
-
 #define put_user(x, ptr)                                               \
 ({                                                                     \
        __typeof__(*(ptr)) __user *__p = (ptr);                         \
index 13a97aa..fc28bd9 100644 (file)
@@ -1,4 +1,20 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += errno.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
 generic-y += kvm_para.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += poll.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += shmbuf.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += swab.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
index e137cea..d169782 100644 (file)
@@ -82,8 +82,8 @@ static const char *__init cpu_read_enable_method(int cpu)
                         * Don't warn spuriously.
                         */
                        if (cpu != 0)
-                               pr_err("%s: missing enable-method property\n",
-                                       dn->full_name);
+                               pr_err("%pOF: missing enable-method property\n",
+                                       dn);
                }
        } else {
                enable_method = acpi_get_enable_method(cpu);
index 3211198..dc66e6e 100644 (file)
@@ -469,7 +469,7 @@ static u64 __init of_get_cpu_mpidr(struct device_node *dn)
         */
        cell = of_get_property(dn, "reg", NULL);
        if (!cell) {
-               pr_err("%s: missing reg property\n", dn->full_name);
+               pr_err("%pOF: missing reg property\n", dn);
                return INVALID_HWID;
        }
 
@@ -478,7 +478,7 @@ static u64 __init of_get_cpu_mpidr(struct device_node *dn)
         * Non affinity bits must be set to 0 in the DT
         */
        if (hwid & ~MPIDR_HWID_BITMASK) {
-               pr_err("%s: invalid reg property\n", dn->full_name);
+               pr_err("%pOF: invalid reg property\n", dn);
                return INVALID_HWID;
        }
        return hwid;
@@ -627,8 +627,8 @@ static void __init of_parse_and_init_cpus(void)
                        goto next;
 
                if (is_mpidr_duplicate(cpu_count, hwid)) {
-                       pr_err("%s: duplicate cpu reg properties in the DT\n",
-                               dn->full_name);
+                       pr_err("%pOF: duplicate cpu reg properties in the DT\n",
+                               dn);
                        goto next;
                }
 
@@ -640,8 +640,8 @@ static void __init of_parse_and_init_cpus(void)
                 */
                if (hwid == cpu_logical_map(0)) {
                        if (bootcpu_valid) {
-                               pr_err("%s: duplicate boot cpu reg property in DT\n",
-                                       dn->full_name);
+                               pr_err("%pOF: duplicate boot cpu reg property in DT\n",
+                                       dn);
                                goto next;
                        }
 
index 79244c7..8d48b23 100644 (file)
@@ -45,7 +45,7 @@ static int __init get_cpu_for_node(struct device_node *node)
                }
        }
 
-       pr_crit("Unable to find CPU node for %s\n", cpu_node->full_name);
+       pr_crit("Unable to find CPU node for %pOF\n", cpu_node);
 
        of_node_put(cpu_node);
        return -1;
@@ -71,8 +71,8 @@ static int __init parse_core(struct device_node *core, int cluster_id,
                                cpu_topology[cpu].core_id = core_id;
                                cpu_topology[cpu].thread_id = i;
                        } else {
-                               pr_err("%s: Can't get CPU for thread\n",
-                                      t->full_name);
+                               pr_err("%pOF: Can't get CPU for thread\n",
+                                      t);
                                of_node_put(t);
                                return -EINVAL;
                        }
@@ -84,15 +84,15 @@ static int __init parse_core(struct device_node *core, int cluster_id,
        cpu = get_cpu_for_node(core);
        if (cpu >= 0) {
                if (!leaf) {
-                       pr_err("%s: Core has both threads and CPU\n",
-                              core->full_name);
+                       pr_err("%pOF: Core has both threads and CPU\n",
+                              core);
                        return -EINVAL;
                }
 
                cpu_topology[cpu].cluster_id = cluster_id;
                cpu_topology[cpu].core_id = core_id;
        } else if (leaf) {
-               pr_err("%s: Can't get CPU for leaf core\n", core->full_name);
+               pr_err("%pOF: Can't get CPU for leaf core\n", core);
                return -EINVAL;
        }
 
@@ -137,8 +137,8 @@ static int __init parse_cluster(struct device_node *cluster, int depth)
                        has_cores = true;
 
                        if (depth == 0) {
-                               pr_err("%s: cpu-map children should be clusters\n",
-                                      c->full_name);
+                               pr_err("%pOF: cpu-map children should be clusters\n",
+                                      c);
                                of_node_put(c);
                                return -EINVAL;
                        }
@@ -146,8 +146,8 @@ static int __init parse_cluster(struct device_node *cluster, int depth)
                        if (leaf) {
                                ret = parse_core(c, cluster_id, core_id++);
                        } else {
-                               pr_err("%s: Non-leaf cluster with core %s\n",
-                                      cluster->full_name, name);
+                               pr_err("%pOF: Non-leaf cluster with core %s\n",
+                                      cluster, name);
                                ret = -EINVAL;
                        }
 
@@ -159,7 +159,7 @@ static int __init parse_cluster(struct device_node *cluster, int depth)
        } while (c);
 
        if (leaf && !has_cores)
-               pr_warn("%s: empty cluster\n", cluster->full_name);
+               pr_warn("%pOF: empty cluster\n", cluster);
 
        if (leaf)
                cluster_id++;
index c7c7088..d48f470 100644 (file)
@@ -274,10 +274,12 @@ static DEFINE_RAW_SPINLOCK(die_lock);
 void die(const char *str, struct pt_regs *regs, int err)
 {
        int ret;
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&die_lock, flags);
 
        oops_enter();
 
-       raw_spin_lock_irq(&die_lock);
        console_verbose();
        bust_spinlocks(1);
        ret = __die(str, err, regs);
@@ -287,13 +289,15 @@ void die(const char *str, struct pt_regs *regs, int err)
 
        bust_spinlocks(0);
        add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
-       raw_spin_unlock_irq(&die_lock);
        oops_exit();
 
        if (in_interrupt())
                panic("Fatal exception in interrupt");
        if (panic_on_oops)
                panic("Fatal exception");
+
+       raw_spin_unlock_irqrestore(&die_lock, flags);
+
        if (ret != NOTIFY_STOP)
                do_exit(SIGSEGV);
 }
index c3cd65e..076c437 100644 (file)
  */
 ENTRY(copy_page)
 alternative_if ARM64_HAS_NO_HW_PREFETCH
-       # Prefetch two cache lines ahead.
-       prfm    pldl1strm, [x1, #128]
-       prfm    pldl1strm, [x1, #256]
+       // Prefetch three cache lines ahead.
+       prfm    pldl1strm, [x1, #128]
+       prfm    pldl1strm, [x1, #256]
+       prfm    pldl1strm, [x1, #384]
 alternative_else_nop_endif
 
        ldp     x2, x3, [x1]
@@ -50,7 +51,7 @@ alternative_else_nop_endif
        subs    x18, x18, #128
 
 alternative_if ARM64_HAS_NO_HW_PREFETCH
-       prfm    pldl1strm, [x1, #384]
+       prfm    pldl1strm, [x1, #384]
 alternative_else_nop_endif
 
        stnp    x2, x3, [x0]
index e90cd1d..f27d4dd 100644 (file)
@@ -329,7 +329,7 @@ static int __swiotlb_mmap(struct device *dev,
        vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot,
                                             is_device_dma_coherent(dev));
 
-       if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+       if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;
 
        return __swiotlb_mmap_pfn(vma, pfn, size);
@@ -706,7 +706,7 @@ static int __iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
        vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot,
                                             is_device_dma_coherent(dev));
 
-       if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+       if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;
 
        if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
index adc208c..decccff 100644 (file)
@@ -35,7 +35,7 @@
  * Leave enough space between the mmap area and the stack to honour ulimit in
  * the face of randomisation.
  */
-#define MIN_GAP (SZ_128M + ((STACK_RND_MASK << PAGE_SHIFT) + 1))
+#define MIN_GAP (SZ_128M)
 #define MAX_GAP        (STACK_TOP/6*5)
 
 static int mmap_is_legacy(void)
@@ -65,6 +65,11 @@ unsigned long arch_mmap_rnd(void)
 static unsigned long mmap_base(unsigned long rnd)
 {
        unsigned long gap = rlimit(RLIMIT_STACK);
+       unsigned long pad = (STACK_RND_MASK << PAGE_SHIFT) + stack_guard_gap;
+
+       /* Values close to RLIM_INFINITY can overflow. */
+       if (gap + pad > gap)
+               gap += pad;
 
        if (gap < MIN_GAP)
                gap = MIN_GAP;
index 23c2d89..f1eb15e 100644 (file)
@@ -496,7 +496,7 @@ void mark_rodata_ro(void)
 
 static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end,
                                      pgprot_t prot, struct vm_struct *vma,
-                                     int flags)
+                                     int flags, unsigned long vm_flags)
 {
        phys_addr_t pa_start = __pa_symbol(va_start);
        unsigned long size = va_end - va_start;
@@ -507,10 +507,13 @@ static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end,
        __create_pgd_mapping(pgd, pa_start, (unsigned long)va_start, size, prot,
                             early_pgtable_alloc, flags);
 
+       if (!(vm_flags & VM_NO_GUARD))
+               size += PAGE_SIZE;
+
        vma->addr       = va_start;
        vma->phys_addr  = pa_start;
        vma->size       = size;
-       vma->flags      = VM_MAP;
+       vma->flags      = VM_MAP | vm_flags;
        vma->caller     = __builtin_return_address(0);
 
        vm_area_add_early(vma);
@@ -541,14 +544,15 @@ static void __init map_kernel(pgd_t *pgd)
         * Only rodata will be remapped with different permissions later on,
         * all other segments are allowed to use contiguous mappings.
         */
-       map_kernel_segment(pgd, _text, _etext, text_prot, &vmlinux_text, 0);
+       map_kernel_segment(pgd, _text, _etext, text_prot, &vmlinux_text, 0,
+                          VM_NO_GUARD);
        map_kernel_segment(pgd, __start_rodata, __inittext_begin, PAGE_KERNEL,
-                          &vmlinux_rodata, NO_CONT_MAPPINGS);
+                          &vmlinux_rodata, NO_CONT_MAPPINGS, VM_NO_GUARD);
        map_kernel_segment(pgd, __inittext_begin, __inittext_end, text_prot,
-                          &vmlinux_inittext, 0);
+                          &vmlinux_inittext, 0, VM_NO_GUARD);
        map_kernel_segment(pgd, __initdata_begin, __initdata_end, PAGE_KERNEL,
-                          &vmlinux_initdata, 0);
-       map_kernel_segment(pgd, _data, _end, PAGE_KERNEL, &vmlinux_data, 0);
+                          &vmlinux_initdata, 0, VM_NO_GUARD);
+       map_kernel_segment(pgd, _data, _end, PAGE_KERNEL, &vmlinux_data, 0, 0);
 
        if (!pgd_val(*pgd_offset_raw(pgd, FIXADDR_START))) {
                /*
index b388a99..dad128b 100644 (file)
@@ -208,8 +208,6 @@ int __init numa_add_memblk(int nid, u64 start, u64 end)
        }
 
        node_set(nid, numa_nodes_parsed);
-       pr_info("Adding memblock [0x%llx - 0x%llx] on node %d\n",
-                       start, (end - 1), nid);
        return ret;
 }
 
@@ -223,10 +221,7 @@ static void __init setup_node_data(int nid, u64 start_pfn, u64 end_pfn)
        void *nd;
        int tnid;
 
-       if (start_pfn < end_pfn)
-               pr_info("Initmem setup node %d [mem %#010Lx-%#010Lx]\n", nid,
-                       start_pfn << PAGE_SHIFT, (end_pfn << PAGE_SHIFT) - 1);
-       else
+       if (start_pfn >= end_pfn)
                pr_info("Initmem setup node %d [<memory-less node>]\n", nid);
 
        nd_pa = memblock_alloc_try_nid(nd_size, SMP_CACHE_BYTES, nid);
index dc4ef9a..fe73697 100644 (file)
@@ -1,50 +1,28 @@
-
-generic-y += auxvec.h
-generic-y += bitsperlong.h
 generic-y += bugs.h
 generic-y += current.h
 generic-y += device.h
 generic-y += div64.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += extable.h
 generic-y += fb.h
 generic-y += futex.h
 generic-y += hw_irq.h
-generic-y += ioctl.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
-generic-y += kvm_para.h
+generic-y += kprobes.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
-generic-y += msgbuf.h
-generic-y += param.h
 generic-y += percpu.h
 generic-y += pgalloc.h
 generic-y += preempt.h
-generic-y += resource.h
-generic-y += sembuf.h
 generic-y += serial.h
-generic-y += setup.h
-generic-y += shmbuf.h
-generic-y += shmparam.h
-generic-y += socket.h
-generic-y += sockios.h
-generic-y += statfs.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += topology.h
 generic-y += trace_clock.h
-generic-y += types.h
-generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += kprobes.h
index 8d9b1eb..76b2e82 100644 (file)
@@ -21,7 +21,7 @@
 #define _BUG_OR_WARN(flags)                                            \
        asm volatile(                                                   \
                "1:     .hword  %0\n"                                   \
-               "       .section __bug_table,\"a\",@progbits\n"         \
+               "       .section __bug_table,\"aw\",@progbits\n"        \
                "2:     .long   1b\n"                                   \
                "       .long   %1\n"                                   \
                "       .short  %2\n"                                   \
@@ -38,7 +38,7 @@
 #define _BUG_OR_WARN(flags)                                            \
        asm volatile(                                                   \
                "1:     .hword  %0\n"                                   \
-               "       .section __bug_table,\"a\",@progbits\n"         \
+               "       .section __bug_table,\"aw\",@progbits\n"        \
                "2:     .long   1b\n"                                   \
                "       .short  %1\n"                                   \
                "       .org    2b + %2\n"                              \
index c1314c5..f1d6ba7 100644 (file)
 #define        flat_argvp_envp_on_stack()              0
 #define        flat_old_ram_flag(flags)                (flags)
 
-extern unsigned long bfin_get_addr_from_rp (unsigned long *ptr,
-                                       unsigned long relval,
-                                       unsigned long flags,
-                                       unsigned long *persistent);
+extern unsigned long bfin_get_addr_from_rp (u32 *ptr, u32 relval,
+                                       u32 flags, u32 *persistent);
 
-extern void bfin_put_addr_at_rp(unsigned long *ptr, unsigned long addr,
-                               unsigned long relval);
+extern void bfin_put_addr_at_rp(u32 *ptr, u32 addr, u32 relval);
 
 /* The amount by which a relocation can exceed the program image limits
    without being regarded as an error.  */
 
 #define        flat_reloc_valid(reloc, size)   ((reloc) <= (size))
 
-#define        flat_get_addr_from_rp(rp, relval, flags, persistent)    \
-       bfin_get_addr_from_rp(rp, relval, flags, persistent)
-#define        flat_put_addr_at_rp(rp, val, relval)    \
-       bfin_put_addr_at_rp(rp, val, relval)
+static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
+                                       u32 *addr, u32 *persistent)
+{
+       *addr = bfin_get_addr_from_rp(rp, relval, flags, persistent);
+       return 0;
+}
+
+static inline int flat_put_addr_at_rp(u32 __user *rp, u32 val, u32 relval)
+{
+       bfin_put_addr_at_rp(rp, val, relval);
+       return 0;
+}
 
 /* Convert a relocation entry into an address.  */
 static inline unsigned long
@@ -39,8 +44,7 @@ flat_get_relocate_addr (unsigned long relval)
        return relval & 0x03ffffff; /* Mask out top 6 bits */
 }
 
-static inline int flat_set_persistent(unsigned long relval,
-                                     unsigned long *persistent)
+static inline int flat_set_persistent(u32 relval, u32 *persistent)
 {
        int type = (relval >> 26) & 7;
        if (type == 3) {
index b9caac4..107d237 100644 (file)
@@ -9,4 +9,6 @@
 
 #include <linux/nmi.h>
 
+extern void arch_touch_nmi_watchdog(void);
+
 #endif
index b15bf6b..aa624b4 100644 (file)
@@ -1,2 +1,24 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
+
+generic-y += auxvec.h
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += ioctl.h
+generic-y += ipcbuf.h
+generic-y += kvm_para.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += setup.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += statfs.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
+generic-y += ucontext.h
index b5b6584..8ebc54d 100644 (file)
 #define FLAT_BFIN_RELOC_TYPE_16H_BIT 1
 #define FLAT_BFIN_RELOC_TYPE_32_BIT 2
 
-unsigned long bfin_get_addr_from_rp(unsigned long *ptr,
-               unsigned long relval,
-               unsigned long flags,
-               unsigned long *persistent)
+unsigned long bfin_get_addr_from_rp(u32 *ptr,
+               u32 relval,
+               u32 flags,
+               u32 *persistent)
 {
        unsigned short *usptr = (unsigned short *)ptr;
        int type = (relval >> 26) & 7;
-       unsigned long val;
+       u32 val;
 
        switch (type) {
        case FLAT_BFIN_RELOC_TYPE_16_BIT:
@@ -32,7 +32,7 @@ unsigned long bfin_get_addr_from_rp(unsigned long *ptr,
                break;
 
        case FLAT_BFIN_RELOC_TYPE_32_BIT:
-               pr_debug("*ptr = %lx", get_unaligned(ptr));
+               pr_debug("*ptr = %x", get_unaligned(ptr));
                val = get_unaligned(ptr);
                break;
 
@@ -59,8 +59,7 @@ EXPORT_SYMBOL(bfin_get_addr_from_rp);
  * Insert the address ADDR into the symbol reference at RP;
  * RELVAL is the raw relocation-table entry from which RP is derived
  */
-void bfin_put_addr_at_rp(unsigned long *ptr, unsigned long addr,
-               unsigned long relval)
+void bfin_put_addr_at_rp(u32 *ptr, u32 addr, u32 relval)
 {
        unsigned short *usptr = (unsigned short *)ptr;
        int type = (relval >> 26) & 7;
@@ -78,7 +77,7 @@ void bfin_put_addr_at_rp(unsigned long *ptr, unsigned long addr,
 
        case FLAT_BFIN_RELOC_TYPE_32_BIT:
                put_unaligned(addr, ptr);
-               pr_debug("new ptr =%lx", get_unaligned(ptr));
+               pr_debug("new ptr =%x", get_unaligned(ptr));
                break;
        }
 }
index 633c370..1e71432 100644 (file)
@@ -190,7 +190,7 @@ static int __init init_nmi_wdt(void)
 }
 device_initcall(init_nmi_wdt);
 
-void touch_nmi_watchdog(void)
+void arch_touch_nmi_watchdog(void)
 {
        atomic_set(&nmi_touched[smp_processor_id()], 1);
 }
index a3c8d05..d717329 100644 (file)
@@ -1,8 +1,5 @@
-
 generic-y += atomic.h
-generic-y += auxvec.h
 generic-y += barrier.h
-generic-y += bitsperlong.h
 generic-y += bugs.h
 generic-y += clkdev.h
 generic-y += current.h
@@ -10,55 +7,32 @@ generic-y += device.h
 generic-y += div64.h
 generic-y += dma.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += exec.h
 generic-y += extable.h
 generic-y += fb.h
-generic-y += fcntl.h
 generic-y += futex.h
 generic-y += hw_irq.h
 generic-y += io.h
-generic-y += ioctl.h
-generic-y += ioctls.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
+generic-y += kprobes.h
 generic-y += local.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
 generic-y += mmu.h
 generic-y += mmu_context.h
-generic-y += msgbuf.h
-generic-y += param.h
 generic-y += pci.h
 generic-y += percpu.h
 generic-y += pgalloc.h
-generic-y += poll.h
-generic-y += posix_types.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += segment.h
-generic-y += sembuf.h
 generic-y += serial.h
-generic-y += shmbuf.h
-generic-y += shmparam.h
-generic-y += signal.h
-generic-y += socket.h
-generic-y += sockios.h
-generic-y += stat.h
-generic-y += statfs.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += tlbflush.h
 generic-y += topology.h
 generic-y += trace_clock.h
-generic-y += types.h
-generic-y += ucontext.h
 generic-y += user.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += kprobes.h
index a1858bd..6f1feb0 100644 (file)
@@ -1,11 +1,22 @@
 #ifndef __ASM_C6X_FLAT_H
 #define __ASM_C6X_FLAT_H
 
+#include <asm/unaligned.h>
+
 #define flat_argvp_envp_on_stack()                     0
 #define flat_old_ram_flag(flags)                       (flags)
 #define flat_reloc_valid(reloc, size)                  ((reloc) <= (size))
-#define flat_get_addr_from_rp(rp, relval, flags, p)    get_unaligned(rp)
-#define flat_put_addr_at_rp(rp, val, relval)           put_unaligned(val, rp)
+static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
+                                       u32 *addr, u32 *persistent)
+{
+       *addr = get_unaligned((__force u32 *)rp);
+       return 0;
+}
+static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel)
+{
+       put_unaligned(addr, (__force u32 *)rp);
+       return 0;
+}
 #define flat_get_relocate_addr(rel)                    (rel)
 #define flat_set_persistent(relval, p)                 0
 
index 1c44d3b..67ee896 100644 (file)
@@ -1,5 +1,30 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += auxvec.h
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
 generic-y += kvm_para.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
 generic-y += siginfo.h
+generic-y += signal.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
+generic-y += ucontext.h
index 64285e0..dfd3b3b 100644 (file)
@@ -399,7 +399,7 @@ out:
 /* Main device API. ioctl's to read/set/clear bits, as well as to
  * set alarms to wait for using a subsequent select().
  */
-unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
+inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg)
 {
        /* Set direction 0=unchanged 1=input,
         * return mask with 1=input */
@@ -450,7 +450,7 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
        return dir_g_in_bits;
 } /* setget_input */
 
-unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
+inline unsigned long setget_output(struct gpio_private *priv, unsigned long arg)
 {
        if (USE_PORTS(priv)) {
                *priv->dir = *priv->dir_shadow |=
index acc5781..460349c 100644 (file)
@@ -1,48 +1,31 @@
 generic-y += atomic.h
-generic-y += auxvec.h
 generic-y += barrier.h
-generic-y += bitsperlong.h
 generic-y += clkdev.h
 generic-y += cmpxchg.h
 generic-y += current.h
 generic-y += device.h
 generic-y += div64.h
-generic-y += errno.h
+generic-y += emergency-restart.h
 generic-y += exec.h
 generic-y += extable.h
-generic-y += emergency-restart.h
-generic-y += fcntl.h
 generic-y += futex.h
 generic-y += hardirq.h
-generic-y += ioctl.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
-generic-y += kvm_para.h
+generic-y += kprobes.h
 generic-y += linkage.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
 generic-y += module.h
-generic-y += msgbuf.h
 generic-y += percpu.h
-generic-y += poll.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += sections.h
-generic-y += sembuf.h
-generic-y += shmbuf.h
-generic-y += socket.h
-generic-y += sockios.h
-generic-y += statfs.h
 generic-y += topology.h
 generic-y += trace_clock.h
-generic-y += types.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += kprobes.h
index b55fc2a..3687b54 100644 (file)
@@ -1,4 +1,21 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += auxvec.h
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ipcbuf.h
+generic-y += kvm_para.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += poll.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += shmbuf.h
 generic-y += siginfo.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += statfs.h
+generic-y += types.h
index 7ac5eaf..7587942 100644 (file)
 #ifdef CONFIG_MMU
 
 #ifndef __ASSEMBLY__
-extern void asmlinkage __flush_tlb_all(void);
-extern void asmlinkage __flush_tlb_mm(unsigned long contextid);
-extern void asmlinkage __flush_tlb_page(unsigned long contextid, unsigned long start);
-extern void asmlinkage __flush_tlb_range(unsigned long contextid,
+extern asmlinkage void __flush_tlb_all(void);
+extern asmlinkage void __flush_tlb_mm(unsigned long contextid);
+extern asmlinkage void __flush_tlb_page(unsigned long contextid, unsigned long start);
+extern asmlinkage void __flush_tlb_range(unsigned long contextid,
                                         unsigned long start, unsigned long end);
 #endif /* !__ASSEMBLY__ */
 
index 99c8246..bc07749 100644 (file)
@@ -1,5 +1,4 @@
 generic-y += asm-offsets.h
-generic-y += auxvec.h
 generic-y += barrier.h
 generic-y += bugs.h
 generic-y += cacheflush.h
@@ -11,66 +10,41 @@ generic-y += device.h
 generic-y += div64.h
 generic-y += dma.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += exec.h
 generic-y += extable.h
 generic-y += fb.h
-generic-y += fcntl.h
 generic-y += ftrace.h
 generic-y += futex.h
 generic-y += hardirq.h
 generic-y += hash.h
 generic-y += hw_irq.h
-generic-y += ioctl.h
-generic-y += ioctls.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
-generic-y += kvm_para.h
+generic-y += kprobes.h
 generic-y += linkage.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
 generic-y += mmu.h
 generic-y += mmu_context.h
 generic-y += module.h
-generic-y += msgbuf.h
-generic-y += param.h
 generic-y += parport.h
 generic-y += percpu.h
 generic-y += pgalloc.h
-generic-y += poll.h
-generic-y += posix_types.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += scatterlist.h
 generic-y += sections.h
-generic-y += sembuf.h
 generic-y += serial.h
-generic-y += setup.h
-generic-y += shmbuf.h
-generic-y += shmparam.h
 generic-y += sizes.h
-generic-y += socket.h
-generic-y += sockios.h
 generic-y += spinlock.h
-generic-y += stat.h
-generic-y += statfs.h
-generic-y += swab.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += timex.h
 generic-y += tlbflush.h
-generic-y += trace_clock.h
 generic-y += topology.h
-generic-y += types.h
-generic-y += ucontext.h
+generic-y += trace_clock.h
 generic-y += unaligned.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += kprobes.h
index a4898ec..7e0bd6f 100644 (file)
@@ -5,6 +5,8 @@
 #ifndef __H8300_FLAT_H__
 #define __H8300_FLAT_H__
 
+#include <asm/unaligned.h>
+
 #define        flat_argvp_envp_on_stack()              1
 #define        flat_old_ram_flag(flags)                1
 #define        flat_reloc_valid(reloc, size)           ((reloc) <= (size))
  */
 
 #define        flat_get_relocate_addr(rel)             (rel & ~0x00000001)
-#define flat_get_addr_from_rp(rp, relval, flags, persistent) \
-       ({(void)persistent; \
-               get_unaligned(rp) & (((flags) & FLAT_FLAG_GOTPIC) ?     \
-                                    0xffffffff : 0x00ffffff); })
-#define flat_put_addr_at_rp(rp, addr, rel) \
-       put_unaligned(((*(char *)(rp)) << 24) | ((addr) & 0x00ffffff), (rp))
+static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
+                                       u32 *addr, u32 *persistent)
+{
+       u32 val = get_unaligned((__force u32 *)rp);
+       if (!(flags & FLAT_FLAG_GOTPIC))
+               val &= 0x00ffffff;
+       *addr = val;
+       return 0;
+}
+
+static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel)
+{
+       u32 *p = (__force u32 *)rp;
+       put_unaligned((addr & 0x00ffffff) | (*(char *)p << 24), p);
+       return 0;
+}
 
 #endif /* __H8300_FLAT_H__ */
index b55fc2a..187aed8 100644 (file)
@@ -1,4 +1,30 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += auxvec.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += kvm_para.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += setup.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
 generic-y += siginfo.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += swab.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
+generic-y += ucontext.h
index 0fc9cb0..3401368 100644 (file)
@@ -1,4 +1,3 @@
-generic-y += auxvec.h
 generic-y += barrier.h
 generic-y += bug.h
 generic-y += bugs.h
@@ -7,53 +6,32 @@ generic-y += current.h
 generic-y += device.h
 generic-y += div64.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += extable.h
 generic-y += fb.h
-generic-y += fcntl.h
 generic-y += ftrace.h
 generic-y += hardirq.h
 generic-y += hw_irq.h
-generic-y += ioctl.h
-generic-y += ioctls.h
 generic-y += iomap.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
+generic-y += kprobes.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
-generic-y += msgbuf.h
 generic-y += pci.h
 generic-y += percpu.h
-generic-y += poll.h
-generic-y += posix_types.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += rwsem.h
 generic-y += sections.h
 generic-y += segment.h
-generic-y += sembuf.h
 generic-y += serial.h
-generic-y += shmbuf.h
-generic-y += shmparam.h
 generic-y += sizes.h
-generic-y += socket.h
-generic-y += sockios.h
-generic-y += stat.h
-generic-y += statfs.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += topology.h
 generic-y += trace_clock.h
-generic-y += types.h
-generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += kprobes.h
index b55fc2a..cb5df3a 100644 (file)
@@ -1,4 +1,26 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += auxvec.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
 generic-y += siginfo.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
+generic-y += ucontext.h
index 502a91d..1d7641f 100644 (file)
@@ -1,8 +1,6 @@
-
 generic-y += clkdev.h
 generic-y += exec.h
 generic-y += irq_work.h
-generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
 generic-y += preempt.h
index b2106b0..0890ded 100644 (file)
@@ -87,42 +87,6 @@ static inline int __access_ok(const void __user *p, unsigned long size)
 #define __put_user(x, ptr)     __put_user_nocheck((__typeof__(*(ptr))) (x), (ptr), sizeof(*(ptr)))
 #define __get_user(x, ptr)     __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
 
-extern long __put_user_unaligned_unknown (void);
-
-#define __put_user_unaligned(x, ptr)                                                           \
-({                                                                                             \
-       long __ret;                                                                             \
-       switch (sizeof(*(ptr))) {                                                               \
-               case 1: __ret = __put_user((x), (ptr)); break;                                  \
-               case 2: __ret = (__put_user((x), (u8 __user *)(ptr)))                           \
-                       | (__put_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break;              \
-               case 4: __ret = (__put_user((x), (u16 __user *)(ptr)))                          \
-                       | (__put_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break;            \
-               case 8: __ret = (__put_user((x), (u32 __user *)(ptr)))                          \
-                       | (__put_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break;            \
-               default: __ret = __put_user_unaligned_unknown();                                \
-       }                                                                                       \
-       __ret;                                                                                  \
-})
-
-extern long __get_user_unaligned_unknown (void);
-
-#define __get_user_unaligned(x, ptr)                                                           \
-({                                                                                             \
-       long __ret;                                                                             \
-       switch (sizeof(*(ptr))) {                                                               \
-               case 1: __ret = __get_user((x), (ptr)); break;                                  \
-               case 2: __ret = (__get_user((x), (u8 __user *)(ptr)))                           \
-                       | (__get_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break;              \
-               case 4: __ret = (__get_user((x), (u16 __user *)(ptr)))                          \
-                       | (__get_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break;            \
-               case 8: __ret = (__get_user((x), (u32 __user *)(ptr)))                          \
-                       | (__get_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break;            \
-               default: __ret = __get_user_unaligned_unknown();                                \
-       }                                                                                       \
-       __ret;                                                                                  \
-})
-
 #ifdef ASM_SUPPORTED
   struct __large_struct { unsigned long buf[100]; };
 # define __m(x) (*(struct __large_struct __user *)(x))
index 599507b..c14815d 100644 (file)
@@ -163,8 +163,3 @@ void arch_crash_save_vmcoreinfo(void)
 #endif
 }
 
-phys_addr_t paddr_vmcoreinfo_note(void)
-{
-       return ia64_tpa((unsigned long)(char *)&vmcoreinfo_note);
-}
-
index 79c7c46..555b111 100644 (file)
@@ -334,7 +334,7 @@ static void ia64_mlogbuf_dump_from_init(void)
        ia64_mlogbuf_dump();
 }
 
-static void inline
+static inline void
 ia64_mca_spin(const char *func)
 {
        if (monarch_cpu == smp_processor_id())
index 5bc34ea..b67bb4c 100644 (file)
@@ -140,7 +140,7 @@ static inline u64 __iomem *pcibr_ate_addr(struct pcibus_info *pcibus_info,
 /*
  * Update the ate.
  */
-void inline
+inline void
 ate_write(struct pcibus_info *pcibus_info, int ate_index, int count,
          volatile u64 ate)
 {
index 46d3df4..3bd9abc 100644 (file)
@@ -52,7 +52,7 @@
  * All registers defined in struct tioce will meet that criteria.
  */
 
-static void inline
+static inline void
 tioce_mmr_war_pre(struct tioce_kernel *kern, void __iomem *mmr_addr)
 {
        u64 mmr_base;
@@ -78,7 +78,7 @@ tioce_mmr_war_pre(struct tioce_kernel *kern, void __iomem *mmr_addr)
        }
 }
 
-static void inline
+static inline void
 tioce_mmr_war_post(struct tioce_kernel *kern, void __iomem *mmr_addr)
 {
        u64 mmr_base;
index c000ffa..7e11b12 100644 (file)
@@ -1,10 +1,9 @@
-
 generic-y += clkdev.h
 generic-y += current.h
 generic-y += exec.h
 generic-y += extable.h
 generic-y += irq_work.h
-generic-y += kvm_para.h
+generic-y += kprobes.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
 generic-y += module.h
@@ -12,4 +11,3 @@ generic-y += preempt.h
 generic-y += sections.h
 generic-y += trace_clock.h
 generic-y += word-at-a-time.h
-generic-y += kprobes.h
index 5d711c4..455ce7d 100644 (file)
 #define        flat_set_persistent(relval, p)          0
 #define        flat_reloc_valid(reloc, size)           \
        (((reloc) - textlen_for_m32r_lo16_data) <= (size))
-#define flat_get_addr_from_rp(rp, relval, flags, persistent) \
-       m32r_flat_get_addr_from_rp(rp, relval, (text_len) )
-
-#define flat_put_addr_at_rp(rp, addr, relval) \
-       m32r_flat_put_addr_at_rp(rp, addr, relval)
 
 /* Convert a relocation entry into an address.  */
 static inline unsigned long
@@ -57,9 +52,9 @@ flat_get_relocate_addr (unsigned long relval)
 
 static unsigned long textlen_for_m32r_lo16_data = 0;
 
-static inline unsigned long m32r_flat_get_addr_from_rp (unsigned long *rp,
-                                                        unsigned long relval,
-                                                       unsigned long textlen)
+static inline unsigned long m32r_flat_get_addr_from_rp (u32 *rp,
+                                                        u32 relval,
+                                                       u32 textlen)
 {
         unsigned int reloc = flat_m32r_get_reloc_type (relval);
        textlen_for_m32r_lo16_data = 0;
@@ -100,9 +95,7 @@ static inline unsigned long m32r_flat_get_addr_from_rp (unsigned long *rp,
        return ~0;      /* bogus value */
 }
 
-static inline void m32r_flat_put_addr_at_rp (unsigned long *rp,
-                                            unsigned long addr,
-                                             unsigned long relval)
+static inline void flat_put_addr_at_rp(u32 *rp, u32 addr, u32 relval)
 {
         unsigned int reloc = flat_m32r_get_reloc_type (relval);
        if (reloc & 0xf0) {
@@ -142,4 +135,8 @@ static inline void m32r_flat_put_addr_at_rp (unsigned long *rp,
        }
 }
 
+// kludge - text_len is a local variable in the only user.
+#define flat_get_addr_from_rp(rp, relval, flags, addr, persistent) \
+       (m32r_flat_get_addr_from_rp(rp, relval, text_len), 0)
+
 #endif /* __ASM_M32R_FLAT_H */
index c94ee54..1c44d3b 100644 (file)
@@ -1,4 +1,5 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
-generic-y      += siginfo.h
+generic-y += kvm_para.h
+generic-y += siginfo.h
index 7cf2c15..15c4b7a 100644 (file)
@@ -35,7 +35,7 @@
 #define        EINT7   67      /* EDGE Port interrupt 7 */
 
 static unsigned int irqebitmap[] = { 0, 1, 4, 7 };
-static unsigned int inline irq2ebit(unsigned int irq)
+static inline unsigned int irq2ebit(unsigned int irq)
 {
        return irqebitmap[irq - EINT0];
 }
@@ -51,7 +51,7 @@ static unsigned int inline irq2ebit(unsigned int irq)
 #define        EINT1   65      /* EDGE Port interrupt 1 */
 #define        EINT7   71      /* EDGE Port interrupt 7 */
 
-static unsigned int inline irq2ebit(unsigned int irq)
+static inline unsigned int irq2ebit(unsigned int irq)
 {
        return irq - EINT0;
 }
index 5ecf4e4..59d6d0d 100644 (file)
@@ -1,36 +1,25 @@
 generic-y += barrier.h
-generic-y += bitsperlong.h
 generic-y += clkdev.h
 generic-y += device.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += exec.h
 generic-y += extable.h
 generic-y += futex.h
 generic-y += hw_irq.h
-generic-y += ioctl.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
-generic-y += kvm_para.h
+generic-y += kprobes.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
 generic-y += percpu.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += sections.h
-generic-y += shmparam.h
 generic-y += spinlock.h
-generic-y += statfs.h
-generic-y += termios.h
 generic-y += topology.h
 generic-y += trace_clock.h
-generic-y += types.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += kprobes.h
index 00c392b..b2a41f5 100644 (file)
@@ -5,16 +5,32 @@
 #ifndef __M68KNOMMU_FLAT_H__
 #define __M68KNOMMU_FLAT_H__
 
+#include <linux/uaccess.h>
+
 #define        flat_argvp_envp_on_stack()              1
 #define        flat_old_ram_flag(flags)                (flags)
 #define        flat_reloc_valid(reloc, size)           ((reloc) <= (size))
-#define        flat_get_addr_from_rp(rp, relval, flags, p) \
-       ({ unsigned long __val; __get_user_unaligned(__val, rp); __val; })
-#define        flat_put_addr_at_rp(rp, val, relval)    __put_user_unaligned(val, rp)
+static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
+                                       u32 *addr, u32 *persistent)
+{
+#ifdef CONFIG_CPU_HAS_NO_UNALIGNED
+       return copy_from_user(addr, rp, 4) ? -EFAULT : 0;
+#else
+       return get_user(*addr, rp);
+#endif
+}
+
+static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel)
+{
+#ifdef CONFIG_CPU_HAS_NO_UNALIGNED
+       return copy_to_user(rp, &addr, 4) ? -EFAULT : 0;
+#else
+       return put_user(addr, rp);
+#endif
+}
 #define        flat_get_relocate_addr(rel)             (rel)
 
-static inline int flat_set_persistent(unsigned long relval,
-                                     unsigned long *persistent)
+static inline int flat_set_persistent(u32 relval, u32 *persistent)
 {
        return 0;
 }
index 67b3481..63ba18e 100644 (file)
@@ -3,11 +3,4 @@
 #else
 #include <asm/uaccess_mm.h>
 #endif
-
 #include <asm/extable.h>
-#ifdef CONFIG_CPU_HAS_NO_UNALIGNED
-#include <asm-generic/uaccess-unaligned.h>
-#else
-#define __get_user_unaligned(x, ptr)   __get_user((x), (ptr))
-#define __put_user_unaligned(x, ptr)   __put_user((x), (ptr))
-#endif
index 68b45cc..3717b64 100644 (file)
@@ -2,11 +2,21 @@
 include include/uapi/asm-generic/Kbuild.asm
 
 generic-y += auxvec.h
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += ioctl.h
+generic-y += ipcbuf.h
+generic-y += kvm_para.h
+generic-y += mman.h
 generic-y += msgbuf.h
+generic-y += resource.h
 generic-y += sembuf.h
 generic-y += shmbuf.h
+generic-y += shmparam.h
 generic-y += siginfo.h
 generic-y += socket.h
 generic-y += sockios.h
+generic-y += statfs.h
 generic-y += termbits.h
 generic-y += termios.h
+generic-y += types.h
index 8f94055..3fba97e 100644 (file)
@@ -1,58 +1,34 @@
-generic-y += auxvec.h
-generic-y += bitsperlong.h
 generic-y += bugs.h
 generic-y += clkdev.h
 generic-y += current.h
 generic-y += device.h
 generic-y += dma.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += exec.h
 generic-y += extable.h
 generic-y += fb.h
-generic-y += fcntl.h
 generic-y += futex.h
 generic-y += hardirq.h
 generic-y += hw_irq.h
-generic-y += ioctl.h
-generic-y += ioctls.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
-generic-y += kvm_para.h
+generic-y += kprobes.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += msgbuf.h
-generic-y += param.h
 generic-y += pci.h
 generic-y += percpu.h
-generic-y += poll.h
-generic-y += posix_types.h
 generic-y += preempt.h
 generic-y += sections.h
-generic-y += sembuf.h
 generic-y += serial.h
-generic-y += shmbuf.h
-generic-y += shmparam.h
-generic-y += signal.h
-generic-y += socket.h
-generic-y += sockios.h
-generic-y += stat.h
-generic-y += statfs.h
 generic-y += switch_to.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += timex.h
 generic-y += trace_clock.h
-generic-y += types.h
-generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += kprobes.h
index b29731e..6ac763d 100644 (file)
@@ -1,6 +1,30 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += auxvec.h
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += kvm_para.h
 generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += poll.h
+generic-y += posix_types.h
 generic-y += resource.h
+generic-y += sembuf.h
 generic-y += setup.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
+generic-y += signal.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
+generic-y += ucontext.h
index 83a4ef3..9d66f77 100644 (file)
@@ -1,22 +1,15 @@
-
 generic-y += barrier.h
 generic-y += bitops.h
-generic-y += bitsperlong.h
 generic-y += bug.h
 generic-y += bugs.h
 generic-y += clkdev.h
 generic-y += device.h
 generic-y += div64.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += exec.h
 generic-y += extable.h
 generic-y += fb.h
-generic-y += fcntl.h
 generic-y += hardirq.h
-generic-y += ioctl.h
-generic-y += ioctls.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
@@ -27,31 +20,13 @@ generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
-generic-y += msgbuf.h
-generic-y += param.h
 generic-y += parport.h
 generic-y += percpu.h
-generic-y += poll.h
 generic-y += preempt.h
-generic-y += resource.h
-generic-y += sembuf.h
 generic-y += serial.h
-generic-y += shmbuf.h
-generic-y += shmparam.h
-generic-y += siginfo.h
-generic-y += signal.h
-generic-y += socket.h
-generic-y += sockios.h
-generic-y += stat.h
-generic-y += statfs.h
-generic-y += swab.h
 generic-y += syscalls.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += topology.h
 generic-y += trace_clock.h
-generic-y += ucontext.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
index 6847c15..f23c3d2 100644 (file)
  * reference
  */
 
-static inline unsigned long
-flat_get_addr_from_rp(unsigned long *rp, unsigned long relval,
-                       unsigned long flags, unsigned long *persistent)
+static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
+                                       u32 *addr, u32 *persistent)
 {
-       unsigned long addr;
-       (void)flags;
+       u32 *p = (__force u32 *)rp;
 
        /* Is it a split 64/32 reference? */
        if (relval & 0x80000000) {
                /* Grab the two halves of the reference */
-               unsigned long val_hi, val_lo;
+               u32 val_hi, val_lo;
 
-               val_hi = get_unaligned(rp);
-               val_lo = get_unaligned(rp+1);
+               val_hi = get_unaligned(p);
+               val_lo = get_unaligned(p+1);
 
                /* Crack the address out */
-               addr = ((val_hi & 0xffff) << 16) + (val_lo & 0xffff);
+               *addr = ((val_hi & 0xffff) << 16) + (val_lo & 0xffff);
        } else {
                /* Get the address straight out */
-               addr = get_unaligned(rp);
+               *addr = get_unaligned(p);
        }
 
-       return addr;
+       return 0;
 }
 
 /*
@@ -63,25 +61,27 @@ flat_get_addr_from_rp(unsigned long *rp, unsigned long relval,
  */
 
 static inline void
-flat_put_addr_at_rp(unsigned long *rp, unsigned long addr, unsigned long relval)
+flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 relval)
 {
+       u32 *p = (__force u32 *)rp;
        /* Is this a split 64/32 reloc? */
        if (relval & 0x80000000) {
                /* Get the two "halves" */
-               unsigned long val_hi = get_unaligned(rp);
-               unsigned long val_lo = get_unaligned(rp + 1);
+               unsigned long val_hi = get_unaligned(p);
+               unsigned long val_lo = get_unaligned(p + 1);
 
                /* insert the address */
                val_hi = (val_hi & 0xffff0000) | addr >> 16;
                val_lo = (val_lo & 0xffff0000) | (addr & 0xffff);
 
                /* store the two halves back into memory */
-               put_unaligned(val_hi, rp);
-               put_unaligned(val_lo, rp+1);
+               put_unaligned(val_hi, p);
+               put_unaligned(val_lo, p+1);
        } else {
                /* Put it straight in, no messing around */
-               put_unaligned(addr, rp);
+               put_unaligned(addr, p);
        }
+       return 0;
 }
 
 #define        flat_get_relocate_addr(rel)     (rel & 0x7fffffff)
index cb6784f..e77a596 100644 (file)
@@ -1,5 +1,28 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
-generic-y += types.h
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += poll.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
 generic-y += siginfo.h
+generic-y += signal.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += swab.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
+generic-y += ucontext.h
index 45bcd1c..8dd2035 100644 (file)
@@ -1,75 +1,77 @@
 config MIPS
        bool
        default y
-       select ARCH_SUPPORTS_UPROBES
+       select ARCH_BINFMT_ELF_STATE
+       select ARCH_CLOCKSOURCE_DATA
+       select ARCH_DISCARD_MEMBLOCK
+       select ARCH_HAS_ELF_RANDOMIZE
+       select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
        select ARCH_MIGHT_HAVE_PC_PARPORT
        select ARCH_MIGHT_HAVE_PC_SERIO
-       select ARCH_USE_CMPXCHG_LOCKREF if 64BIT
+       select ARCH_SUPPORTS_UPROBES
        select ARCH_USE_BUILTIN_BSWAP
-       select HAVE_CONTEXT_TRACKING
-       select HAVE_GENERIC_DMA_COHERENT
-       select HAVE_IDE
-       select HAVE_IRQ_EXIT_ON_IRQ_STACK
-       select HAVE_OPROFILE
-       select HAVE_PERF_EVENTS
-       select PERF_USE_VMALLOC
+       select ARCH_USE_CMPXCHG_LOCKREF if 64BIT
+       select ARCH_USE_QUEUED_RWLOCKS
+       select ARCH_USE_QUEUED_SPINLOCKS
+       select ARCH_WANT_IPC_PARSE_VERSION
+       select BUILDTIME_EXTABLE_SORT
+       select CLONE_BACKWARDS
+       select CPU_PM if CPU_IDLE
+       select GENERIC_ATOMIC64 if !64BIT
+       select GENERIC_CLOCKEVENTS
+       select GENERIC_CMOS_UPDATE
+       select GENERIC_CPU_AUTOPROBE
+       select GENERIC_IRQ_PROBE
+       select GENERIC_IRQ_SHOW
+       select GENERIC_PCI_IOMAP
+       select GENERIC_SCHED_CLOCK if !CAVIUM_OCTEON_SOC
+       select GENERIC_SMP_IDLE_THREAD
+       select GENERIC_TIME_VSYSCALL
+       select HANDLE_DOMAIN_IRQ
+       select HAVE_ARCH_JUMP_LABEL
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_MMAP_RND_BITS if MMU
        select HAVE_ARCH_MMAP_RND_COMPAT_BITS if MMU && COMPAT
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
-       select HAVE_CBPF_JIT if !CPU_MICROMIPS
-       select HAVE_FUNCTION_TRACER
+       select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES && 64BIT
+       select HAVE_CBPF_JIT if (!64BIT && !CPU_MICROMIPS)
+       select HAVE_EBPF_JIT if (64BIT && !CPU_MICROMIPS)
+       select HAVE_CC_STACKPROTECTOR
+       select HAVE_CONTEXT_TRACKING
+       select HAVE_COPY_THREAD_TLS
+       select HAVE_C_RECORDMCOUNT
+       select HAVE_DEBUG_KMEMLEAK
+       select HAVE_DEBUG_STACKOVERFLOW
+       select HAVE_DMA_API_DEBUG
+       select HAVE_DMA_CONTIGUOUS
        select HAVE_DYNAMIC_FTRACE
+       select HAVE_EXIT_THREAD
        select HAVE_FTRACE_MCOUNT_RECORD
-       select HAVE_C_RECORDMCOUNT
        select HAVE_FUNCTION_GRAPH_TRACER
+       select HAVE_FUNCTION_TRACER
+       select HAVE_GENERIC_DMA_COHERENT
+       select HAVE_IDE
+       select HAVE_IRQ_EXIT_ON_IRQ_STACK
+       select HAVE_IRQ_TIME_ACCOUNTING
        select HAVE_KPROBES
        select HAVE_KRETPROBES
-       select HAVE_SYSCALL_TRACEPOINTS
-       select HAVE_DEBUG_KMEMLEAK
-       select HAVE_SYSCALL_TRACEPOINTS
-       select ARCH_HAS_ELF_RANDOMIZE
-       select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES && 64BIT
-       select RTC_LIB if !MACH_LOONGSON64
-       select GENERIC_ATOMIC64 if !64BIT
-       select HAVE_DMA_CONTIGUOUS
-       select HAVE_DMA_API_DEBUG
-       select GENERIC_IRQ_PROBE
-       select GENERIC_IRQ_SHOW
-       select GENERIC_PCI_IOMAP
-       select HAVE_ARCH_JUMP_LABEL
-       select ARCH_WANT_IPC_PARSE_VERSION
-       select IRQ_FORCED_THREADING
        select HAVE_MEMBLOCK
        select HAVE_MEMBLOCK_NODE_MAP
-       select ARCH_DISCARD_MEMBLOCK
-       select GENERIC_SMP_IDLE_THREAD
-       select BUILDTIME_EXTABLE_SORT
-       select GENERIC_CPU_AUTOPROBE
-       select GENERIC_CLOCKEVENTS
-       select GENERIC_SCHED_CLOCK if !CAVIUM_OCTEON_SOC
-       select GENERIC_CMOS_UPDATE
        select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_NMI
-       select VIRT_TO_BUS
-       select MODULES_USE_ELF_REL if MODULES
+       select HAVE_OPROFILE
+       select HAVE_PERF_EVENTS
+       select HAVE_REGS_AND_STACK_ACCESS_API
+       select HAVE_SYSCALL_TRACEPOINTS
+       select HAVE_VIRT_CPU_ACCOUNTING_GEN
+       select IRQ_FORCED_THREADING
        select MODULES_USE_ELF_RELA if MODULES && 64BIT
-       select CLONE_BACKWARDS
-       select HAVE_DEBUG_STACKOVERFLOW
-       select HAVE_CC_STACKPROTECTOR
-       select CPU_PM if CPU_IDLE
-       select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
-       select ARCH_BINFMT_ELF_STATE
+       select MODULES_USE_ELF_REL if MODULES
+       select PERF_USE_VMALLOC
+       select RTC_LIB if !MACH_LOONGSON64
        select SYSCTL_EXCEPTION_TRACE
-       select HAVE_VIRT_CPU_ACCOUNTING_GEN
-       select HAVE_IRQ_TIME_ACCOUNTING
-       select GENERIC_TIME_VSYSCALL
-       select ARCH_CLOCKSOURCE_DATA
-       select HANDLE_DOMAIN_IRQ
-       select HAVE_EXIT_THREAD
-       select HAVE_REGS_AND_STACK_ACCESS_API
-       select HAVE_COPY_THREAD_TLS
+       select VIRT_TO_BUS
 
 menu "Machine selection"
 
@@ -1179,6 +1181,15 @@ config SYS_SUPPORTS_RELOCATABLE
         The platform must provide plat_get_fdt() if it selects CONFIG_USE_OF
         to allow access to command line and entropy sources.
 
+config MIPS_CBPF_JIT
+       def_bool y
+       depends on BPF_JIT && HAVE_CBPF_JIT
+
+config MIPS_EBPF_JIT
+       def_bool y
+       depends on BPF_JIT && HAVE_EBPF_JIT
+
+
 #
 # Endianness selection.  Sufficiently obscure so many users don't know what to
 # answer,so we try hard to limit the available choices.  Also the use of a
@@ -2062,7 +2073,7 @@ config CPU_SUPPORTS_UNCACHED_ACCELERATED
        bool
 config MIPS_PGD_C0_CONTEXT
        bool
-       default y if 64BIT && CPU_MIPSR2 && !CPU_XLP
+       default y if 64BIT && (CPU_MIPSR2 || CPU_MIPSR6) && !CPU_XLP
 
 #
 # Set to y for ptrace access to watch registers.
@@ -2370,6 +2381,7 @@ config MIPS_CPS
        select SMP
        select SYNC_R4K if (CEVT_R4K || CSRC_R4K)
        select SYS_SUPPORTS_HOTPLUG_CPU
+       select SYS_SUPPORTS_SCHED_SMT if CPU_MIPSR6
        select SYS_SUPPORTS_SMP
        select WEAK_ORDERING
        help
index 02a1787..0434362 100644 (file)
@@ -160,7 +160,7 @@ cflags-$(CONFIG_CPU_MIPS32_R1)      += $(call cc-option,-march=mips32,-mips32 -U_MIPS
                        -Wa,-mips32 -Wa,--trap
 cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
                        -Wa,-mips32r2 -Wa,--trap
-cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap
+cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap -modd-spreg
 cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
                        -Wa,-mips64 -Wa,--trap
 cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips64r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
index 69a65f0..3d70958 100644 (file)
@@ -1,6 +1,7 @@
-dtb-$(CONFIG_MACH_PISTACHIO)   += pistachio_marduk.dtb
+dtb-$(CONFIG_FIT_IMAGE_FDT_BOSTON)     += boston.dtb
 
-obj-y                          += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
+dtb-$(CONFIG_MACH_PISTACHIO)   += pistachio_marduk.dtb
+obj-$(CONFIG_MACH_PISTACHIO)   += pistachio_marduk.dtb.o
 
 # Force kbuild to make empty built-in.o if necessary
 obj-                           += dummy.o
diff --git a/arch/mips/boot/dts/img/boston.dts b/arch/mips/boot/dts/img/boston.dts
new file mode 100644 (file)
index 0000000..53bfa29
--- /dev/null
@@ -0,0 +1,224 @@
+/dts-v1/;
+
+#include <dt-bindings/clock/boston-clock.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/mips-gic.h>
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       compatible = "img,boston";
+
+       chosen {
+               stdout-path = "uart0:115200";
+       };
+
+       aliases {
+               uart0 = &uart0;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       compatible = "img,mips";
+                       reg = <0>;
+                       clocks = <&clk_boston BOSTON_CLK_CPU>;
+               };
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x10000000>;
+       };
+
+       pci0: pci@10000000 {
+               compatible = "xlnx,axi-pcie-host-1.00.a";
+               device_type = "pci";
+               reg = <0x10000000 0x2000000>;
+
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_SHARED 2 IRQ_TYPE_LEVEL_HIGH>;
+
+               ranges = <0x02000000 0 0x40000000
+                         0x40000000 0 0x40000000>;
+
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pci0_intc 1>,
+                               <0 0 0 2 &pci0_intc 2>,
+                               <0 0 0 3 &pci0_intc 3>,
+                               <0 0 0 4 &pci0_intc 4>;
+
+               pci0_intc: interrupt-controller {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+               };
+       };
+
+       pci1: pci@12000000 {
+               compatible = "xlnx,axi-pcie-host-1.00.a";
+               device_type = "pci";
+               reg = <0x12000000 0x2000000>;
+
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_SHARED 1 IRQ_TYPE_LEVEL_HIGH>;
+
+               ranges = <0x02000000 0 0x20000000
+                         0x20000000 0 0x20000000>;
+
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pci1_intc 1>,
+                               <0 0 0 2 &pci1_intc 2>,
+                               <0 0 0 3 &pci1_intc 3>,
+                               <0 0 0 4 &pci1_intc 4>;
+
+               pci1_intc: interrupt-controller {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+               };
+       };
+
+       pci2: pci@14000000 {
+               compatible = "xlnx,axi-pcie-host-1.00.a";
+               device_type = "pci";
+               reg = <0x14000000 0x2000000>;
+
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_SHARED 0 IRQ_TYPE_LEVEL_HIGH>;
+
+               ranges = <0x02000000 0 0x16000000
+                         0x16000000 0 0x100000>;
+
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pci2_intc 1>,
+                               <0 0 0 2 &pci2_intc 2>,
+                               <0 0 0 3 &pci2_intc 3>,
+                               <0 0 0 4 &pci2_intc 4>;
+
+               pci2_intc: interrupt-controller {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+               };
+
+               pci2_root@0,0,0 {
+                       compatible = "pci10ee,7021";
+                       reg = <0x00000000 0 0 0 0>;
+
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       #interrupt-cells = <1>;
+
+                       eg20t_bridge@1,0,0 {
+                               compatible = "pci8086,8800";
+                               reg = <0x00010000 0 0 0 0>;
+
+                               #address-cells = <3>;
+                               #size-cells = <2>;
+                               #interrupt-cells = <1>;
+
+                               eg20t_mac@2,0,1 {
+                                       compatible = "pci8086,8802";
+                                       reg = <0x00020100 0 0 0 0>;
+                                       phy-reset-gpios = <&eg20t_gpio 6
+                                                          GPIO_ACTIVE_LOW>;
+                               };
+
+                               eg20t_gpio: eg20t_gpio@2,0,2 {
+                                       compatible = "pci8086,8803";
+                                       reg = <0x00020200 0 0 0 0>;
+
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                               };
+
+                               eg20t_i2c@2,12,2 {
+                                       compatible = "pci8086,8817";
+                                       reg = <0x00026200 0 0 0 0>;
+
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       rtc@0x68 {
+                                               compatible = "st,m41t81s";
+                                               reg = <0x68>;
+                                       };
+                               };
+                       };
+               };
+       };
+
+       gic: interrupt-controller@16120000 {
+               compatible = "mti,gic";
+               reg = <0x16120000 0x20000>;
+
+               interrupt-controller;
+               #interrupt-cells = <3>;
+
+               timer {
+                       compatible = "mti,gic-timer";
+                       interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>;
+                       clocks = <&clk_boston BOSTON_CLK_CPU>;
+               };
+       };
+
+       cdmm@16140000 {
+               compatible = "mti,mips-cdmm";
+               reg = <0x16140000 0x8000>;
+       };
+
+       cpc@16200000 {
+               compatible = "mti,mips-cpc";
+               reg = <0x16200000 0x8000>;
+       };
+
+       plat_regs: system-controller@17ffd000 {
+               compatible = "img,boston-platform-regs", "syscon";
+               reg = <0x17ffd000 0x1000>;
+
+               clk_boston: clock {
+                       compatible = "img,boston-clock";
+                       #clock-cells = <1>;
+               };
+       };
+
+       reboot: syscon-reboot {
+               compatible = "syscon-reboot";
+               regmap = <&plat_regs>;
+               offset = <0x10>;
+               mask = <0x10>;
+       };
+
+       uart0: uart@17ffe000 {
+               compatible = "ns16550a";
+               reg = <0x17ffe000 0x1000>;
+               reg-shift = <2>;
+
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>;
+
+               clocks = <&clk_boston BOSTON_CLK_SYS>;
+       };
+
+       lcd: lcd@17fff000 {
+               compatible = "img,boston-lcd";
+               reg = <0x17fff000 0x8>;
+       };
+};
index b112879..4f8bc83 100644 (file)
        #size-cells = <1>;
        compatible = "mti,sead-3";
        model = "MIPS SEAD-3";
-       interrupt-parent = <&gic>;
 
        chosen {
-               stdout-path = "uart1:115200";
+               stdout-path = "serial1:115200";
        };
 
        aliases {
-               uart0 = &uart0;
-               uart1 = &uart1;
+               serial0 = &uart0;
+               serial1 = &uart1;
        };
 
        cpus {
                 * controller & should be probed first.
                 */
                interrupt-parent = <&cpu_intc>;
-
-               timer {
-                       compatible = "mti,gic-timer";
-                       interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>;
-               };
        };
 
        ehci@1b200000 {
                compatible = "generic-ehci";
                reg = <0x1b200000 0x1000>;
 
-               interrupts = <0>; /* GIC 0 or CPU 6 */
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_SHARED 0 IRQ_TYPE_LEVEL_HIGH>; /* GIC 0 or CPU 6 */
 
                has-transaction-translator;
        };
 
                clock-frequency = <14745600>;
 
-               interrupts = <3>; /* GIC 3 or CPU 4 */
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>; /* GIC 3 or CPU 4 */
 
                no-loopback-test;
        };
 
                clock-frequency = <14745600>;
 
-               interrupts = <2>; /* GIC 2 or CPU 4 */
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_SHARED 2 IRQ_TYPE_LEVEL_HIGH>; /* GIC 2 or CPU 4 */
 
                no-loopback-test;
        };
                reg = <0x1f010000 0x10000>;
                reg-io-width = <4>;
 
-               interrupts = <0>; /* GIC 0 or CPU 6 */
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_SHARED 0 IRQ_TYPE_LEVEL_HIGH>; /* GIC 0 or CPU 6 */
 
                phy-mode = "mii";
                smsc,irq-push-pull;
index 320772c..92fca3c 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_HIGH_RES_TIMERS=y
 CONFIG_HZ_100=y
 CONFIG_KEXEC=y
 # CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_KERNEL_LZMA=y
 CONFIG_SYSVIPC=y
@@ -41,7 +40,6 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 CONFIG_TCP_CONG_ADVANCED=y
 # CONFIG_TCP_CONG_BIC is not set
@@ -86,7 +84,6 @@ CONFIG_MAC80211_RC_DEFAULT_PID=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FIRMWARE_IN_KERNEL is not set
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
@@ -99,8 +96,6 @@ CONFIG_FIXED_PHY=y
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 CONFIG_CPMAC=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_PPP=m
 CONFIG_PPP_MULTILINK=y
 CONFIG_PPP_FILTER=y
@@ -142,7 +137,6 @@ CONFIG_BSD_DISKLABEL=y
 # CONFIG_ENABLE_MUST_CHECK is not set
 CONFIG_STRIP_ASM_SYMS=y
 CONFIG_DEBUG_FS=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
 CONFIG_CRYPTO=y
index 134879c..25ed914 100644 (file)
@@ -7,7 +7,6 @@ CONFIG_ATH79_MACH_PB44=y
 CONFIG_ATH79_MACH_UBNT_XM=y
 CONFIG_HZ_100=y
 # CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -35,7 +34,6 @@ CONFIG_IP_ADVANCED_ROUTER=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
 CONFIG_CFG80211=m
 CONFIG_MAC80211=m
index 5599a9f..131b350 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_BCM63XX_CPU_6348=y
 CONFIG_BCM63XX_CPU_6358=y
 CONFIG_NO_HZ=y
 # CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 # CONFIG_SWAP is not set
 CONFIG_TINY_RCU=y
@@ -33,7 +32,6 @@ CONFIG_INET=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 CONFIG_CFG80211=y
@@ -50,13 +48,10 @@ CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
 # CONFIG_BLK_DEV is not set
-# CONFIG_MISC_DEVICES is not set
 CONFIG_NETDEVICES=y
 CONFIG_BCM63XX_PHY=y
 CONFIG_NET_ETHERNET=y
 CONFIG_BCM63XX_ENET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_B43=y
 # CONFIG_B43_PHY_LP is not set
 # CONFIG_INPUT is not set
@@ -70,7 +65,6 @@ CONFIG_SERIAL_BCM63XX_CONSOLE=y
 # CONFIG_HWMON is not set
 # CONFIG_VGA_ARB is not set
 CONFIG_USB=y
-# CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
 CONFIG_USB_OHCI_HCD=y
@@ -84,7 +78,6 @@ CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
 CONFIG_PROC_KCORE=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0,115200"
 # CONFIG_CRYPTO_HW is not set
index d20b09d..a55009e 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_SMP=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_HZ_1000=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
@@ -60,7 +59,6 @@ CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
 CONFIG_INET_XFRM_MODE_TRANSPORT=m
 CONFIG_INET_XFRM_MODE_TUNNEL=m
-# CONFIG_INET_LRO is not set
 CONFIG_TCP_MD5SIG=y
 CONFIG_IPV6_ROUTER_PREF=y
 CONFIG_IPV6_ROUTE_INFO=y
@@ -182,7 +180,6 @@ CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 # CONFIG_PRINT_QUOTA_WARNING is not set
 CONFIG_QFMT_V2=m
-CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 CONFIG_FUSE_FS=m
 CONFIG_ISO9660_FS=m
@@ -284,7 +281,6 @@ CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_ZLIB=m
 CONFIG_CRYPTO_LZO=m
 CONFIG_CRC_T10DIF=m
 CONFIG_CRC7=m
index acf7785..a7072a1 100644 (file)
@@ -23,7 +23,6 @@ CONFIG_INET=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 CONFIG_CFG80211=y
 CONFIG_NL80211_TESTMODE=y
index 2924ba3..bd80b5c 100644 (file)
@@ -1,6 +1,5 @@
 CONFIG_MACH_VR41XX=y
 CONFIG_ZAO_CAPCELLA=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -46,8 +45,6 @@ CONFIG_SMSC_PHY=m
 CONFIG_NET_ETHERNET=y
 CONFIG_NET_PCI=y
 CONFIG_8139TOO=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
@@ -59,7 +56,6 @@ CONFIG_SERIAL_VR41XX_CONSOLE=y
 CONFIG_GPIO_VR41XX=y
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_VR41XX=y
index d4fda41..e5b18f1 100644 (file)
@@ -42,7 +42,6 @@ CONFIG_IP_MROUTE=y
 CONFIG_IP_PIMSM_V1=y
 CONFIG_IP_PIMSM_V2=y
 CONFIG_SYN_COOKIES=y
-# CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
index 43e0ba2..b42cfa7 100644 (file)
@@ -41,7 +41,6 @@ CONFIG_INET=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
index 23b6693..a9066f3 100644 (file)
@@ -1,5 +1,4 @@
 CONFIG_MIPS_COBALT=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
@@ -15,17 +14,14 @@ CONFIG_XFRM_USER=y
 CONFIG_NET_KEY=y
 CONFIG_NET_KEY_MIGRATE=y
 CONFIG_INET=y
-# CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_BLK_DEV_LOOP=y
-# CONFIG_MISC_DEVICES is not set
 CONFIG_RAID_ATTRS=y
 CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_LOWLEVEL is not set
@@ -36,8 +32,6 @@ CONFIG_NET_ETHERNET=y
 CONFIG_NET_TULIP=y
 CONFIG_DE2104X=y
 CONFIG_TULIP=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_KEYBOARD is not set
@@ -56,7 +50,6 @@ CONFIG_FB_COBALT=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_HID=m
 CONFIG_USB=m
-# CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_EHCI_HCD=m
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
 CONFIG_USB_OHCI_HCD=m
@@ -84,6 +77,5 @@ CONFIG_NFS_V3_ACL=y
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
 CONFIG_NFSD_V3_ACL=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_CRC16=y
 CONFIG_LIBCRC32C=y
index 2b6cb41..e149f78 100644 (file)
@@ -1,6 +1,5 @@
 CONFIG_MACH_DECSTATION=y
 CONFIG_CPU_R3000=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
index e94d266..c3ac020 100644 (file)
@@ -1,6 +1,5 @@
 CONFIG_MACH_VR41XX=y
 CONFIG_CASIO_E55=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -28,7 +27,6 @@ CONFIG_SERIAL_VR41XX_CONSOLE=y
 CONFIG_GPIO_VR41XX=y
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_VR41XX=y
index 8743589..499f514 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_64BIT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT_VOLUNTARY=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_LOCALVERSION="-fuloong2e"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
@@ -47,7 +46,6 @@ CONFIG_NET_IPGRE=m
 CONFIG_NET_IPGRE_BROADCAST=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
@@ -79,7 +77,6 @@ CONFIG_NETFILTER_XT_MATCH_STRING=m
 CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 CONFIG_NETFILTER_XT_MATCH_TIME=m
 CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
 CONFIG_IP_NF_MATCH_AH=m
@@ -88,7 +85,6 @@ CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_TTL=m
@@ -101,7 +97,6 @@ CONFIG_NET_9P=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_MTD=m
-CONFIG_MTD_CHAR=m
 CONFIG_MTD_BLOCK=m
 CONFIG_MTD_CFI=m
 CONFIG_MTD_JEDECPROBE=m
@@ -163,7 +158,6 @@ CONFIG_I2C=m
 CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_VIAPRO=m
 # CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
 CONFIG_FB_RADEON=y
 # CONFIG_FB_RADEON_I2C is not set
@@ -184,7 +178,6 @@ CONFIG_USB_KBD=y
 CONFIG_USB_MOUSE=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-# CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_OTG_WHITELIST=y
 CONFIG_USB_WUSB_CBAF=m
 CONFIG_USB_C67X00_HCD=m
@@ -201,7 +194,6 @@ CONFIG_USB_TMC=m
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_ONETOUCH=y
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
-CONFIG_USB_LIBUSUAL=y
 CONFIG_USB_SEVSEG=m
 CONFIG_USB_ISIGHTFW=m
 CONFIG_UIO=m
@@ -215,7 +207,6 @@ CONFIG_EXT4_FS=m
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
 CONFIG_REISERFS_FS=m
-CONFIG_AUTOFS_FS=y
 CONFIG_AUTOFS4_FS=y
 CONFIG_FUSE_FS=y
 CONFIG_ISO9660_FS=m
@@ -256,8 +247,6 @@ CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=y
 # CONFIG_ENABLE_MUST_CHECK is not set
 CONFIG_DEBUG_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_CRYPTO_FIPS=y
 CONFIG_CRYPTO_AUTHENC=m
 CONFIG_CRYPTO_CCM=m
diff --git a/arch/mips/configs/generic/board-boston.config b/arch/mips/configs/generic/board-boston.config
new file mode 100644 (file)
index 0000000..19560a4
--- /dev/null
@@ -0,0 +1,48 @@
+CONFIG_FIT_IMAGE_FDT_BOSTON=y
+
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+
+CONFIG_AUXDISPLAY=y
+CONFIG_IMG_ASCII_LCD=y
+
+CONFIG_COMMON_CLK_BOSTON=y
+
+CONFIG_DMADEVICES=y
+CONFIG_PCH_DMA=y
+
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_PCH=y
+
+CONFIG_I2C=y
+CONFIG_I2C_EG20T=y
+
+CONFIG_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PCI=y
+
+CONFIG_NETDEVICES=y
+CONFIG_PCH_GBE=y
+
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
+CONFIG_PCIE_XILINX=y
+
+CONFIG_PCH_PHUB=y
+
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_M41T80=y
+
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+
+CONFIG_SPI=y
+CONFIG_SPI_TOPCLIFF_PCH=y
+
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
index e24feb0..b191181 100644 (file)
@@ -2,7 +2,6 @@ CONFIG_MIPS_ALCHEMY=y
 CONFIG_MIPS_GPR=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT_VOLUNTARY=y
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -59,7 +58,6 @@ CONFIG_NETFILTER_XT_MATCH_REALM=m
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
 CONFIG_NETFILTER_XT_MATCH_STRING=m
 CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
 CONFIG_IP_NF_MATCH_AH=m
@@ -68,7 +66,6 @@ CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_TTL=m
@@ -166,7 +163,6 @@ CONFIG_YAM=m
 CONFIG_CFG80211=y
 CONFIG_MAC80211=y
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
@@ -200,8 +196,6 @@ CONFIG_SMSC_PHY=m
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 CONFIG_MIPS_AU1X00_ENET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_ATH_COMMON=y
 CONFIG_ATH_DEBUG=y
 CONFIG_ATH5K=y
@@ -286,14 +280,12 @@ CONFIG_USB_HIDDEV=y
 CONFIG_USB_KBD=m
 CONFIG_USB_MOUSE=m
 CONFIG_USB=y
-# CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_MON=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_ROOT_HUB_TT=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=m
-CONFIG_USB_LIBUSUAL=y
 CONFIG_USB_SERIAL=y
 CONFIG_USB_EZUSB=y
 CONFIG_USB_SERIAL_GENERIC=y
index ec8e968..83e8fe2 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_HZ_1000=y
 CONFIG_PREEMPT_VOLUNTARY=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -46,7 +45,6 @@ CONFIG_INET_IPCOMP=m
 CONFIG_INET_XFRM_MODE_TRANSPORT=m
 CONFIG_INET_XFRM_MODE_TUNNEL=m
 CONFIG_INET_XFRM_MODE_BEET=m
-# CONFIG_INET_LRO is not set
 CONFIG_TCP_MD5SIG=y
 CONFIG_IPV6_ROUTER_PREF=y
 CONFIG_IPV6_ROUTE_INFO=y
@@ -139,7 +137,6 @@ CONFIG_IP_VS_SED=m
 CONFIG_IP_VS_NQ=m
 CONFIG_IP_VS_FTP=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
 CONFIG_IP_NF_MATCH_AH=m
@@ -148,7 +145,6 @@ CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_NF_NAT=m
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_NETMAP=m
@@ -163,7 +159,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP6_NF_MATCH_AH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
@@ -174,7 +169,6 @@ CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_MH=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_TARGET_HL=m
-CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
@@ -215,7 +209,6 @@ CONFIG_RFKILL=m
 CONFIG_CONNECTOR=m
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
-# CONFIG_MISC_DEVICES is not set
 CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -245,8 +238,6 @@ CONFIG_MDIO_BITBANG=m
 CONFIG_NET_ETHERNET=y
 CONFIG_SMC91X=m
 CONFIG_SGISEEQ=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_HOSTAP=m
 CONFIG_INPUT_MOUSEDEV=m
 CONFIG_MOUSE_PS2=m
@@ -286,7 +277,6 @@ CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 # CONFIG_PRINT_QUOTA_WARNING is not set
 CONFIG_QFMT_V2=m
-CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 CONFIG_FUSE_FS=m
 CONFIG_ISO9660_FS=m
@@ -355,7 +345,6 @@ CONFIG_NLS_KOI8_U=m
 CONFIG_NLS_UTF8=m
 CONFIG_DLM=m
 CONFIG_DEBUG_MEMORY_INIT=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_KEYS=y
 CONFIG_CRYPTO_FIPS=y
 CONFIG_CRYPTO_NULL=m
index e582069..a0d5932 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_SMP=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_HZ_1000=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_IKCONFIG=y
@@ -104,7 +103,6 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_OSD=m
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
-# CONFIG_MISC_DEVICES is not set
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
@@ -325,7 +323,6 @@ CONFIG_XFS_POSIX_ACL=y
 CONFIG_BTRFS_FS=m
 CONFIG_BTRFS_FS_POSIX_ACL=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
-CONFIG_AUTOFS_FS=m
 CONFIG_FUSE_FS=m
 CONFIG_CUSE=m
 CONFIG_FSCACHE=m
@@ -342,7 +339,6 @@ CONFIG_NFS_V3=y
 CONFIG_RPCSEC_GSS_KRB5=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_DLM=m
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_KEYS=y
 CONFIG_SECURITYFS=y
 CONFIG_CRYPTO_FIPS=y
@@ -378,7 +374,6 @@ CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_ZLIB=m
 CONFIG_CRYPTO_LZO=m
 CONFIG_CRYPTO_DEV_HIFN_795X=m
 CONFIG_CRC_T10DIF=m
index 4dbf626..d0a4c2c 100644 (file)
@@ -1,7 +1,6 @@
 CONFIG_SGI_IP28=y
 CONFIG_ARC_CONSOLE=y
 CONFIG_PREEMPT_VOLUNTARY=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -35,10 +34,8 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 CONFIG_TCP_MD5SIG=y
 # CONFIG_IPV6 is not set
-# CONFIG_MISC_DEVICES is not set
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
@@ -48,8 +45,6 @@ CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
 CONFIG_NET_ETHERNET=y
 CONFIG_SGISEEQ=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 # CONFIG_MOUSE_PS2_ALPS is not set
 # CONFIG_MOUSE_PS2_SYNAPTICS is not set
 CONFIG_VT_HW_CONSOLE_BINDING=y
index f9af98f..1e26e58 100644 (file)
@@ -1,6 +1,5 @@
 CONFIG_SGI_IP32=y
 # CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
@@ -38,7 +37,6 @@ CONFIG_NET_IPGRE=m
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
-# CONFIG_INET_LRO is not set
 CONFIG_TCP_CONG_ADVANCED=y
 CONFIG_TCP_MD5SIG=y
 CONFIG_INET6_AH=m
@@ -76,8 +74,6 @@ CONFIG_NET_TULIP=y
 CONFIG_DE2104X=m
 CONFIG_TULIP=m
 CONFIG_TULIP_MMIO=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_INPUT_EVDEV=m
 # CONFIG_SERIO_I8042 is not set
 CONFIG_SERIO_MACEPS2=y
@@ -87,7 +83,6 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_HW_RANDOM=y
 CONFIG_WATCHDOG=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_GBE=y
@@ -117,7 +112,6 @@ CONFIG_EXT3_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QFMT_V1=m
 CONFIG_QFMT_V2=m
-CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 CONFIG_FUSE_FS=m
 CONFIG_ISO9660_FS=m
@@ -178,8 +172,6 @@ CONFIG_NLS_KOI8_R=m
 CONFIG_NLS_KOI8_U=m
 CONFIG_NLS_UTF8=m
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_KEYS=y
 CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_CBC=y
index 3019fce..9ad1c94 100644 (file)
@@ -1,7 +1,6 @@
 CONFIG_MACH_JAZZ=y
 CONFIG_OLIVETTI_M700=y
 CONFIG_PREEMPT_VOLUNTARY=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
@@ -85,7 +84,6 @@ CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
 CONFIG_NETFILTER_XT_MATCH_STRING=m
 CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
 CONFIG_IP_NF_MATCH_AH=m
@@ -94,7 +92,6 @@ CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_NF_NAT=m
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_NETMAP=m
@@ -109,7 +106,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP6_NF_MATCH_AH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
@@ -120,7 +116,6 @@ CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_MH=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_TARGET_HL=m
-CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
@@ -276,7 +271,6 @@ CONFIG_REISERFS_FS_POSIX_ACL=y
 CONFIG_REISERFS_FS_SECURITY=y
 CONFIG_XFS_FS=m
 CONFIG_XFS_QUOTA=y
-CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 CONFIG_FUSE_FS=m
 CONFIG_ISO9660_FS=m
index 9bc08f2..af12281 100644 (file)
@@ -18,23 +18,18 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
-# CONFIG_MISC_DEVICES is not set
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_NET_PCI=y
 CONFIG_TC35815=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -58,5 +53,3 @@ CONFIG_PROC_KCORE=y
 # CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
index e620a2c..947a35c 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_DS1603=y
 CONFIG_LASAT_SYSCTL=y
 CONFIG_HZ_1000=y
 # CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_EXPERT=y
@@ -31,7 +30,6 @@ CONFIG_INET=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
@@ -44,8 +42,6 @@ CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
@@ -56,7 +52,6 @@ CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_PCI is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
-# CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
index 8df80c6..1ec8ed8 100644 (file)
@@ -7,7 +7,6 @@ CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT=y
 CONFIG_KEXEC=y
 # CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
@@ -83,8 +82,6 @@ CONFIG_NET_SCHED=y
 CONFIG_NET_EMATCH=y
 CONFIG_NET_CLS_ACT=y
 CONFIG_BT=m
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=m
@@ -142,7 +139,6 @@ CONFIG_8139TOO=y
 # CONFIG_8139TOO_PIO is not set
 CONFIG_R8169=y
 CONFIG_R8169_VLAN=y
-# CONFIG_NETDEV_10000 is not set
 CONFIG_USB_USBNET=m
 CONFIG_USB_NET_CDC_EEM=m
 CONFIG_NETCONSOLE=m
@@ -205,7 +201,6 @@ CONFIG_USB_ZR364XX=m
 CONFIG_USB_STKWEBCAM=m
 CONFIG_USB_S2255=m
 # CONFIG_RADIO_ADAPTERS is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_MODE_HELPERS=y
@@ -290,7 +285,6 @@ CONFIG_HID_WACOM=m
 CONFIG_HID_ZEROPLUS=m
 CONFIG_ZEROPLUS_FF=y
 CONFIG_USB=y
-# CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_DYNAMIC_MINORS=y
 CONFIG_USB_OTG_WHITELIST=y
 CONFIG_USB_MON=y
@@ -313,10 +307,8 @@ CONFIG_USB_STORAGE_SDDR09=m
 CONFIG_USB_STORAGE_SDDR55=m
 CONFIG_USB_STORAGE_JUMPSHOT=m
 CONFIG_USB_STORAGE_ALAUDA=m
-CONFIG_USB_LIBUSUAL=y
 CONFIG_USB_SERIAL=m
 CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_LED=m
 CONFIG_USB_GADGET=m
 CONFIG_USB_GADGET_M66592=y
 CONFIG_MMC=m
@@ -341,7 +333,6 @@ CONFIG_XFS_POSIX_ACL=y
 CONFIG_BTRFS_FS=m
 CONFIG_QUOTA=y
 CONFIG_QFMT_V2=m
-CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 CONFIG_FSCACHE=m
 CONFIG_CACHEFILES=m
@@ -407,8 +398,6 @@ CONFIG_PRINTK_TIME=y
 CONFIG_FRAME_WARN=1024
 CONFIG_STRIP_ASM_SYMS=y
 CONFIG_DEBUG_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_KEYS=y
 CONFIG_CRYPTO_FIPS=y
 CONFIG_CRYPTO_NULL=m
@@ -446,6 +435,5 @@ CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_DEFLATE=m
-CONFIG_CRYPTO_ZLIB=m
 CONFIG_CRYPTO_LZO=m
 CONFIG_CRC_T10DIF=y
index 7f95c4b..324dfee 100644 (file)
@@ -95,7 +95,6 @@ CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_TTL=m
@@ -252,7 +251,6 @@ CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=m
 CONFIG_DRM=y
 CONFIG_DRM_RADEON=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB_RADEON=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_PLATFORM=m
@@ -335,7 +333,6 @@ CONFIG_STRIP_ASM_SYMS=y
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_RCU_CPU_STALL_VERBOSE is not set
 # CONFIG_FTRACE is not set
 CONFIG_SECURITY=y
 CONFIG_SECURITYFS=y
index e233f87..80ecd94 100644 (file)
@@ -133,7 +133,6 @@ CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_TARGET_ECN=m
index fbe085c..35ad1f8 100644 (file)
@@ -132,7 +132,6 @@ CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_TARGET_ECN=m
index cbf37dd..77145ec 100644 (file)
@@ -42,7 +42,6 @@ CONFIG_SYN_COOKIES=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
-# CONFIG_INET_LRO is not set
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
index 35f6ba2..cc2687c 100644 (file)
@@ -43,7 +43,6 @@ CONFIG_SYN_COOKIES=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
-# CONFIG_INET_LRO is not set
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
@@ -135,7 +134,6 @@ CONFIG_HW_RANDOM=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_SYSCON=y
 # CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_MATROX=y
index 900f145..55b68b9 100644 (file)
@@ -46,7 +46,6 @@ CONFIG_SYN_COOKIES=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
-# CONFIG_INET_LRO is not set
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
index 8e2738b..5ca590c 100644 (file)
@@ -47,7 +47,6 @@ CONFIG_SYN_COOKIES=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
-# CONFIG_INET_LRO is not set
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
@@ -140,7 +139,6 @@ CONFIG_HW_RANDOM=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_SYSCON=y
 # CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_MATROX=y
index 6dc4e30..7ea7c0b 100644 (file)
@@ -42,7 +42,6 @@ CONFIG_SYN_COOKIES=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
-# CONFIG_INET_LRO is not set
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
@@ -134,7 +133,6 @@ CONFIG_HW_RANDOM=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_SYSCON=y
 # CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_MATROX=y
index 0f08e46..43ce657 100644 (file)
@@ -1,7 +1,6 @@
 CONFIG_NEC_MARKEINS=y
 CONFIG_HZ_1000=y
 CONFIG_PREEMPT=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
@@ -92,7 +91,6 @@ CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_NF_NAT=m
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_NETMAP=m
@@ -117,7 +115,6 @@ CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_MH=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_TARGET_HL=m
-CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
@@ -125,7 +122,6 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_FW_LOADER=m
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
index 84cfcb4..accf0db 100644 (file)
@@ -39,7 +39,6 @@ CONFIG_IP_MROUTE=y
 CONFIG_IP_PIMSM_V1=y
 CONFIG_IP_PIMSM_V2=y
 CONFIG_SYN_COOKIES=y
-# CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
 # CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
index a2c045f..3486b03 100644 (file)
@@ -1,6 +1,5 @@
 CONFIG_MACH_VR41XX=y
 CONFIG_VICTOR_MPC30X=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
@@ -31,8 +30,6 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_ATA=y
 CONFIG_PATA_LEGACY=y
 CONFIG_NETDEVICES=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_USB_PEGASUS=m
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_KEYBOARD is not set
@@ -45,13 +42,11 @@ CONFIG_SERIAL_VR41XX_CONSOLE=y
 CONFIG_GPIO_VR41XX=y
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
 CONFIG_USB=m
 CONFIG_USB_OHCI_HCD=m
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_VR41XX=y
 CONFIG_EXT2_FS=y
-CONFIG_AUTOFS_FS=y
 CONFIG_AUTOFS4_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_CONFIGFS_FS=m
index 201edfb..3c8c16b 100644 (file)
@@ -2,7 +2,6 @@ CONFIG_PMC_MSP=y
 CONFIG_PMC_MSP7120_GW=y
 CONFIG_CPU_MIPS32_R2=y
 CONFIG_PREEMPT=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_LOCALVERSION="-pmc"
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
@@ -38,7 +37,6 @@ CONFIG_BRIDGE=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
index f3f6005..4011f18 100644 (file)
@@ -1,7 +1,6 @@
 CONFIG_MIPS_ALCHEMY=y
 CONFIG_MIPS_MTX1=y
 CONFIG_PREEMPT_VOLUNTARY=y
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -81,7 +80,6 @@ CONFIG_NETFILTER_XT_MATCH_REALM=m
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
 CONFIG_NETFILTER_XT_MATCH_STRING=m
 CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
 CONFIG_IP_NF_MATCH_AH=m
@@ -90,7 +88,6 @@ CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_TTL=m
@@ -98,7 +95,6 @@ CONFIG_IP_NF_RAW=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP6_NF_MATCH_AH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
@@ -108,7 +104,6 @@ CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_TARGET_HL=m
-CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
@@ -225,8 +220,6 @@ CONFIG_TOSHIBA_FIR=m
 CONFIG_VLSI_FIR=m
 CONFIG_MCS_FIR=m
 CONFIG_BT=m
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=m
@@ -246,7 +239,6 @@ CONFIG_BT_HCIBTUART=m
 CONFIG_BT_HCIVHCI=m
 CONFIG_CONNECTOR=m
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
@@ -257,7 +249,6 @@ CONFIG_MTD_PHYSMAP=y
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=65536
-# CONFIG_MISC_DEVICES is not set
 CONFIG_SCSI=m
 CONFIG_BLK_DEV_SD=m
 CONFIG_CHR_DEV_SG=m
@@ -596,7 +587,6 @@ CONFIG_USB_STORAGE_SDDR55=m
 CONFIG_USB_STORAGE_JUMPSHOT=m
 CONFIG_USB_STORAGE_ALAUDA=m
 CONFIG_USB_STORAGE_KARMA=m
-CONFIG_USB_LIBUSUAL=y
 CONFIG_USB_MDC800=m
 CONFIG_USB_MICROTEK=m
 CONFIG_USB_SERIAL=m
@@ -640,7 +630,6 @@ CONFIG_USB_ADUTUX=m
 CONFIG_USB_RIO500=m
 CONFIG_USB_LEGOTOWER=m
 CONFIG_USB_LCD=m
-CONFIG_USB_LED=m
 CONFIG_USB_CYPRESS_CY7C63=m
 CONFIG_USB_CYTHERM=m
 CONFIG_USB_IDMOUSE=m
index 07d0182..5720ce2 100644 (file)
@@ -6,7 +6,6 @@ CONFIG_KSM=y
 CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
 CONFIG_SMP=y
 # CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -183,14 +182,12 @@ CONFIG_IP_VS_SED=m
 CONFIG_IP_VS_NQ=m
 CONFIG_IP_VS_FTP=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_NF_NAT=m
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_NETMAP=m
@@ -317,7 +314,6 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_CONNECTOR=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_ADV_OPTIONS=y
@@ -607,7 +603,6 @@ CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_ZLIB=m
 CONFIG_CRYPTO_LZO=m
 CONFIG_CRC_CCITT=m
 CONFIG_CRC7=m
index f59969a..fea56c5 100644 (file)
@@ -7,7 +7,6 @@ CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_KEXEC=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_CROSS_COMPILE=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
@@ -163,7 +162,6 @@ CONFIG_IP_VS_SED=m
 CONFIG_IP_VS_NQ=m
 CONFIG_IP_VS_FTP=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -171,7 +169,6 @@ CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_NF_NAT=m
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_NETMAP=m
@@ -186,7 +183,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP6_NF_MATCH_AH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
@@ -197,7 +193,6 @@ CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_MH=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_TARGET_HL=m
-CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
@@ -308,7 +303,6 @@ CONFIG_BLK_DEV_OSD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=65536
 CONFIG_CDROM_PKTCDVD=y
-CONFIG_MISC_DEVICES=y
 CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -369,7 +363,6 @@ CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_DS1374=y
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_UIO=y
 CONFIG_UIO_PDRV=m
@@ -522,7 +515,6 @@ CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_MEMORY_INIT=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_SCHED_TRACER=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_KGDB=y
@@ -568,7 +560,6 @@ CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_ZLIB=m
 CONFIG_CRYPTO_LZO=m
 CONFIG_CRC_CCITT=m
 CONFIG_CRC7=m
index c887066..81b5eb8 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_HIGH_RES_TIMERS=y
 CONFIG_HZ_128=y
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
@@ -27,12 +26,10 @@ CONFIG_IP_MULTICAST=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_INET_AH=y
-# CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_ADV_OPTIONS=y
@@ -41,15 +38,12 @@ CONFIG_MTD_CFI_GEOMETRY=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_BLK_DEV_LOOP=y
-# CONFIG_MISC_DEVICES is not set
 CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_ATA=y
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=m
 CONFIG_INPUT_EVBUG=m
@@ -94,4 +88,3 @@ CONFIG_NLS_ASCII=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
-CONFIG_SYSCTL_SYSCALL_CHECK=y
index d7bb8cc..3f13335 100644 (file)
@@ -34,7 +34,6 @@ CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 CONFIG_TCP_CONG_ADVANCED=y
 # CONFIG_TCP_CONG_BIC is not set
@@ -109,7 +108,6 @@ CONFIG_USB_GADGET_DEBUG=y
 CONFIG_USB_ETH=y
 # CONFIG_USB_ETH_RNDIS is not set
 CONFIG_MMC=y
-CONFIG_MMC_UNSAFE_RESUME=y
 # CONFIG_MMC_BLOCK_BOUNCE is not set
 CONFIG_MMC_JZ4740=y
 CONFIG_RTC_CLASS=y
@@ -183,7 +181,6 @@ CONFIG_PANIC_ON_OOPS=y
 # CONFIG_FTRACE is not set
 CONFIG_KGDB=y
 CONFIG_RUNTIME_DEBUG=y
-CONFIG_CRYPTO_ZLIB=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_FONTS=y
 CONFIG_FONT_SUN8x16=y
index 5d9d708..6fa56c6 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_HZ_100=y
 # CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
@@ -39,7 +38,6 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=m
 CONFIG_TCP_CONG_ADVANCED=y
 CONFIG_TCP_CONG_CUBIC=m
@@ -114,7 +112,6 @@ CONFIG_NET_CLS_IND=y
 CONFIG_HAMRADIO=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_BLOCK2MTD=y
 CONFIG_MTD_NAND=y
@@ -129,8 +126,6 @@ CONFIG_NET_ETHERNET=y
 CONFIG_KORINA=y
 CONFIG_NET_PCI=y
 CONFIG_VIA_RHINE=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_ATMEL=m
 CONFIG_PPP=m
 CONFIG_PPP_MULTILINK=y
@@ -183,7 +178,6 @@ CONFIG_BSD_DISKLABEL=y
 CONFIG_STRIP_ASM_SYMS=y
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_ZLIB=y
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC16=m
 CONFIG_LIBCRC32C=m
index 43d55e5..fb195e2 100644 (file)
@@ -31,12 +31,10 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=m
 CONFIG_MTD_BLOCK_RO=m
 CONFIG_MTD_CFI=y
@@ -50,7 +48,6 @@ CONFIG_MTD_NAND_TXX9NDFMC=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_MISC_DEVICES is not set
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDE_TX4938=y
 CONFIG_BLK_DEV_IDE_TX4939=y
@@ -60,8 +57,6 @@ CONFIG_SMC91X=y
 CONFIG_NE2000=y
 CONFIG_NET_PCI=y
 CONFIG_TC35815=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 # CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
@@ -108,5 +103,3 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_STRIP_ASM_SYMS=y
 CONFIG_DEBUG_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
index c2b4e3f..99679e5 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_ARC_CONSOLE=y
 CONFIG_HZ_1000=y
 CONFIG_PREEMPT_VOLUNTARY=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
@@ -94,7 +93,6 @@ CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
 CONFIG_NETFILTER_XT_MATCH_STRING=m
 CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
 CONFIG_IP_NF_MATCH_AH=m
@@ -103,7 +101,6 @@ CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_NF_NAT=m
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_NETMAP=m
@@ -118,7 +115,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP6_NF_MATCH_AH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
@@ -129,7 +125,6 @@ CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_MH=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_TARGET_HL=m
-CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
@@ -214,7 +209,6 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_SX8=m
-CONFIG_BLK_DEV_UB=m
 CONFIG_BLK_DEV_RAM=m
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
@@ -353,7 +347,6 @@ CONFIG_USB_SERIAL_OMNINET=m
 CONFIG_USB_RIO500=m
 CONFIG_USB_LEGOTOWER=m
 CONFIG_USB_LCD=m
-CONFIG_USB_LED=m
 CONFIG_USB_CYTHERM=m
 CONFIG_USB_SISUSBVGA=m
 CONFIG_USB_LD=m
@@ -366,7 +359,6 @@ CONFIG_REISERFS_FS_POSIX_ACL=y
 CONFIG_REISERFS_FS_SECURITY=y
 CONFIG_XFS_FS=m
 CONFIG_XFS_QUOTA=y
-CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 CONFIG_FUSE_FS=m
 CONFIG_ISO9660_FS=m
index d14ae2f..c695b7b 100644 (file)
@@ -5,7 +5,6 @@ CONFIG_CPU_MIPS32_R2=y
 # CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_HZ_100=y
 # CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -44,7 +43,6 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 CONFIG_TCP_CONG_ADVANCED=y
 # CONFIG_TCP_CONG_BIC is not set
index 7fca09f..c724bdd 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_64BIT=y
 CONFIG_SMP=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_HZ_1000=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_CGROUPS=y
index 11f5150..4041597 100644 (file)
@@ -1,6 +1,5 @@
 CONFIG_MACH_VR41XX=y
 CONFIG_TANBAC_TB0219=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -31,7 +30,6 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
 CONFIG_NETWORK_SECMARK=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
@@ -40,7 +38,6 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_XIP=y
-# CONFIG_MISC_DEVICES is not set
 CONFIG_NETDEVICES=y
 CONFIG_PHYLIB=m
 CONFIG_MARVELL_PHY=m
@@ -57,7 +54,6 @@ CONFIG_VIA_RHINE=y
 CONFIG_VIA_RHINE_MMIO=y
 CONFIG_R8169=y
 CONFIG_VIA_VELOCITY=y
-# CONFIG_NETDEV_10000 is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
@@ -70,7 +66,6 @@ CONFIG_SERIAL_VR41XX_CONSOLE=y
 CONFIG_GPIO_TB0219=y
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
 CONFIG_USB=m
 CONFIG_USB_MON=m
 CONFIG_USB_EHCI_HCD=m
@@ -91,6 +86,5 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="cca=3 mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs"
index 9327b3a..565f044 100644 (file)
@@ -1,6 +1,5 @@
 CONFIG_MACH_VR41XX=y
 CONFIG_TANBAC_TB0226=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -29,7 +28,6 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
 CONFIG_NETWORK_SECMARK=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
@@ -37,7 +35,6 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_XIP=y
-# CONFIG_MISC_DEVICES is not set
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_MULTI_LUN=y
@@ -49,8 +46,6 @@ CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_NET_PCI=y
 CONFIG_E100=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_USB_CATC=m
 CONFIG_USB_KAWETH=m
 CONFIG_USB_PEGASUS=m
@@ -66,7 +61,6 @@ CONFIG_SERIAL_VR41XX_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -87,7 +81,6 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=m
 CONFIG_NFSD_V3=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="cca=3 mem=32M console=ttyVR0,115200"
 CONFIG_CRC32=m
index a967289..a702be6 100644 (file)
@@ -1,5 +1,4 @@
 CONFIG_MACH_VR41XX=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
@@ -31,7 +30,6 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 CONFIG_TCP_CONG_ADVANCED=y
 CONFIG_TCP_CONG_BIC=y
 CONFIG_TCP_CONG_CUBIC=m
@@ -43,7 +41,6 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_XIP=y
-# CONFIG_MISC_DEVICES is not set
 CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_SCAN_ASYNC=y
 # CONFIG_SCSI_LOWLEVEL is not set
@@ -64,7 +61,6 @@ CONFIG_VIA_RHINE=y
 CONFIG_VIA_RHINE_MMIO=y
 CONFIG_R8169=y
 CONFIG_VIA_VELOCITY=y
-# CONFIG_NETDEV_10000 is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
@@ -76,7 +72,6 @@ CONFIG_SERIAL_VR41XX_CONSOLE=y
 CONFIG_GPIO_VR41XX=y
 # CONFIG_HWMON is not set
 CONFIG_MFD_SM501=y
-CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
 CONFIG_FB_SM501=y
 # CONFIG_VGA_CONSOLE is not set
index ee4b2be..a84eac4 100644 (file)
@@ -1,6 +1,5 @@
 CONFIG_MACH_VR41XX=y
 CONFIG_IBM_WORKPAD=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -28,13 +27,10 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_IPV6 is not set
 CONFIG_NETWORK_SECMARK=y
 CONFIG_BLK_DEV_RAM=m
-# CONFIG_MISC_DEVICES is not set
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDECS=m
 CONFIG_IDE_GENERIC=y
 CONFIG_NETDEVICES=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_NET_PCMCIA=y
 CONFIG_PCMCIA_3C589=m
 CONFIG_PCMCIA_3C574=m
index a606b3f..51ffbba 100644 (file)
@@ -9,11 +9,31 @@ config LEGACY_BOARDS
          kernel is booted without being provided with an FDT via the UHI
          boot protocol.
 
+config YAMON_DT_SHIM
+       bool
+       help
+         Select this from your board if the board uses the YAMON bootloader
+         and you wish to include code which helps translate various
+         YAMON-provided environment variables into a device tree properties.
+
+comment "Legacy (non-UHI/non-FIT) Boards"
+
 config LEGACY_BOARD_SEAD3
        bool "Support MIPS SEAD-3 boards"
        select LEGACY_BOARDS
+       select YAMON_DT_SHIM
        help
          Enable this to include support for booting on MIPS SEAD-3 FPGA-based
          development boards, which boot using a legacy boot protocol.
 
+comment "FIT/UHI Boards"
+
+config FIT_IMAGE_FDT_BOSTON
+       bool "Include FDT for MIPS Boston boards"
+       help
+         Enable this to include the FDT for the MIPS Boston development board
+         from Imagination Technologies in the FIT kernel image. You should
+         enable this if you wish to boot on a MIPS Boston board, as it is
+         expected by the bootloader.
+
 endif
index acb9b6d..56b3ea5 100644 (file)
@@ -12,5 +12,6 @@ obj-y += init.o
 obj-y += irq.o
 obj-y += proc.o
 
+obj-$(CONFIG_YAMON_DT_SHIM)            += yamon-dt.o
 obj-$(CONFIG_LEGACY_BOARD_SEAD3)       += board-sead3.o
 obj-$(CONFIG_KEXEC)                    += kexec.o
index f4ae058..f109a6b 100644 (file)
 #include <linux/errno.h>
 #include <linux/libfdt.h>
 #include <linux/printk.h>
+#include <linux/sizes.h>
 
 #include <asm/fw/fw.h>
 #include <asm/io.h>
 #include <asm/machine.h>
+#include <asm/yamon-dt.h>
 
 #define SEAD_CONFIG                    CKSEG1ADDR(0x1b100110)
 #define SEAD_CONFIG_GIC_PRESENT                BIT(1)
 #define MIPS_REVISION_MACHINE          (0xf << 4)
 #define MIPS_REVISION_MACHINE_SEAD3    (0x4 << 4)
 
+/*
+ * Maximum 384MB RAM at physical address 0, preceding any I/O.
+ */
+static struct yamon_mem_region mem_regions[] __initdata = {
+       /* start        size */
+       { 0,            SZ_256M + SZ_128M },
+       {}
+};
+
 static __init bool sead3_detect(void)
 {
        uint32_t rev;
@@ -33,96 +44,9 @@ static __init bool sead3_detect(void)
        return (rev & MIPS_REVISION_MACHINE) == MIPS_REVISION_MACHINE_SEAD3;
 }
 
-static __init int append_cmdline(void *fdt)
-{
-       int err, chosen_off;
-
-       /* find or add chosen node */
-       chosen_off = fdt_path_offset(fdt, "/chosen");
-       if (chosen_off == -FDT_ERR_NOTFOUND)
-               chosen_off = fdt_path_offset(fdt, "/chosen@0");
-       if (chosen_off == -FDT_ERR_NOTFOUND)
-               chosen_off = fdt_add_subnode(fdt, 0, "chosen");
-       if (chosen_off < 0) {
-               pr_err("Unable to find or add DT chosen node: %d\n",
-                      chosen_off);
-               return chosen_off;
-       }
-
-       err = fdt_setprop_string(fdt, chosen_off, "bootargs", fw_getcmdline());
-       if (err) {
-               pr_err("Unable to set bootargs property: %d\n", err);
-               return err;
-       }
-
-       return 0;
-}
-
 static __init int append_memory(void *fdt)
 {
-       unsigned long phys_memsize, memsize;
-       __be32 mem_array[2];
-       int err, mem_off;
-       char *var;
-
-       /* find memory size from the bootloader environment */
-       var = fw_getenv("memsize");
-       if (var) {
-               err = kstrtoul(var, 0, &phys_memsize);
-               if (err) {
-                       pr_err("Failed to read memsize env variable '%s'\n",
-                              var);
-                       return -EINVAL;
-               }
-       } else {
-               pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n");
-               phys_memsize = 32 << 20;
-       }
-
-       /* default to using all available RAM */
-       memsize = phys_memsize;
-
-       /* allow the user to override the usable memory */
-       var = strstr(arcs_cmdline, "memsize=");
-       if (var)
-               memsize = memparse(var + strlen("memsize="), NULL);
-
-       /* if the user says there's more RAM than we thought, believe them */
-       phys_memsize = max_t(unsigned long, phys_memsize, memsize);
-
-       /* find or add a memory node */
-       mem_off = fdt_path_offset(fdt, "/memory");
-       if (mem_off == -FDT_ERR_NOTFOUND)
-               mem_off = fdt_add_subnode(fdt, 0, "memory");
-       if (mem_off < 0) {
-               pr_err("Unable to find or add memory DT node: %d\n", mem_off);
-               return mem_off;
-       }
-
-       err = fdt_setprop_string(fdt, mem_off, "device_type", "memory");
-       if (err) {
-               pr_err("Unable to set memory node device_type: %d\n", err);
-               return err;
-       }
-
-       mem_array[0] = 0;
-       mem_array[1] = cpu_to_be32(phys_memsize);
-       err = fdt_setprop(fdt, mem_off, "reg", mem_array, sizeof(mem_array));
-       if (err) {
-               pr_err("Unable to set memory regs property: %d\n", err);
-               return err;
-       }
-
-       mem_array[0] = 0;
-       mem_array[1] = cpu_to_be32(memsize);
-       err = fdt_setprop(fdt, mem_off, "linux,usable-memory",
-                         mem_array, sizeof(mem_array));
-       if (err) {
-               pr_err("Unable to set linux,usable-memory property: %d\n", err);
-               return err;
-       }
-
-       return 0;
+       return yamon_dt_append_memory(fdt, mem_regions);
 }
 
 static __init int remove_gic(void *fdt)
@@ -163,14 +87,16 @@ static __init int remove_gic(void *fdt)
                return -EINVAL;
        }
 
-       err = fdt_setprop_u32(fdt, 0, "interrupt-parent", cpu_phandle);
-       if (err) {
-               pr_err("unable to set root interrupt-parent: %d\n", err);
-               return err;
-       }
-
        uart_off = fdt_node_offset_by_compatible(fdt, -1, "ns16550a");
        while (uart_off >= 0) {
+               err = fdt_setprop_u32(fdt, uart_off, "interrupt-parent",
+                                     cpu_phandle);
+               if (err) {
+                       pr_warn("unable to set UART interrupt-parent: %d\n",
+                               err);
+                       return err;
+               }
+
                err = fdt_setprop_u32(fdt, uart_off, "interrupts",
                                      cpu_uart_int);
                if (err) {
@@ -193,6 +119,12 @@ static __init int remove_gic(void *fdt)
                return eth_off;
        }
 
+       err = fdt_setprop_u32(fdt, eth_off, "interrupt-parent", cpu_phandle);
+       if (err) {
+               pr_err("unable to set ethernet interrupt-parent: %d\n", err);
+               return err;
+       }
+
        err = fdt_setprop_u32(fdt, eth_off, "interrupts", cpu_eth_int);
        if (err) {
                pr_err("unable to set ethernet interrupts property: %d\n", err);
@@ -205,94 +137,29 @@ static __init int remove_gic(void *fdt)
                return ehci_off;
        }
 
-       err = fdt_setprop_u32(fdt, ehci_off, "interrupts", cpu_ehci_int);
+       err = fdt_setprop_u32(fdt, ehci_off, "interrupt-parent", cpu_phandle);
        if (err) {
-               pr_err("unable to set EHCI interrupts property: %d\n", err);
+               pr_err("unable to set EHCI interrupt-parent: %d\n", err);
                return err;
        }
 
-       return 0;
-}
-
-static __init int serial_config(void *fdt)
-{
-       const char *yamontty, *mode_var;
-       char mode_var_name[9], path[18], parity;
-       unsigned int uart, baud, stop_bits;
-       bool hw_flow;
-       int chosen_off, err;
-
-       yamontty = fw_getenv("yamontty");
-       if (!yamontty || !strcmp(yamontty, "tty0")) {
-               uart = 0;
-       } else if (!strcmp(yamontty, "tty1")) {
-               uart = 1;
-       } else {
-               pr_warn("yamontty environment variable '%s' invalid\n",
-                       yamontty);
-               uart = 0;
-       }
-
-       baud = stop_bits = 0;
-       parity = 0;
-       hw_flow = false;
-
-       snprintf(mode_var_name, sizeof(mode_var_name), "modetty%u", uart);
-       mode_var = fw_getenv(mode_var_name);
-       if (mode_var) {
-               while (mode_var[0] >= '0' && mode_var[0] <= '9') {
-                       baud *= 10;
-                       baud += mode_var[0] - '0';
-                       mode_var++;
-               }
-               if (mode_var[0] == ',')
-                       mode_var++;
-               if (mode_var[0])
-                       parity = mode_var[0];
-               if (mode_var[0] == ',')
-                       mode_var++;
-               if (mode_var[0])
-                       stop_bits = mode_var[0] - '0';
-               if (mode_var[0] == ',')
-                       mode_var++;
-               if (!strcmp(mode_var, "hw"))
-                       hw_flow = true;
-       }
-
-       if (!baud)
-               baud = 38400;
-
-       if (parity != 'e' && parity != 'n' && parity != 'o')
-               parity = 'n';
-
-       if (stop_bits != 7 && stop_bits != 8)
-               stop_bits = 8;
-
-       WARN_ON(snprintf(path, sizeof(path), "uart%u:%u%c%u%s",
-                        uart, baud, parity, stop_bits,
-                        hw_flow ? "r" : "") >= sizeof(path));
-
-       /* find or add chosen node */
-       chosen_off = fdt_path_offset(fdt, "/chosen");
-       if (chosen_off == -FDT_ERR_NOTFOUND)
-               chosen_off = fdt_path_offset(fdt, "/chosen@0");
-       if (chosen_off == -FDT_ERR_NOTFOUND)
-               chosen_off = fdt_add_subnode(fdt, 0, "chosen");
-       if (chosen_off < 0) {
-               pr_err("Unable to find or add DT chosen node: %d\n",
-                      chosen_off);
-               return chosen_off;
-       }
-
-       err = fdt_setprop_string(fdt, chosen_off, "stdout-path", path);
+       err = fdt_setprop_u32(fdt, ehci_off, "interrupts", cpu_ehci_int);
        if (err) {
-               pr_err("Unable to set stdout-path property: %d\n", err);
+               pr_err("unable to set EHCI interrupts property: %d\n", err);
                return err;
        }
 
        return 0;
 }
 
+static const struct mips_fdt_fixup sead3_fdt_fixups[] __initconst = {
+       { yamon_dt_append_cmdline, "append command line" },
+       { append_memory, "append memory" },
+       { remove_gic, "remove GIC when not present" },
+       { yamon_dt_serial_config, "append serial configuration" },
+       { },
+};
+
 static __init const void *sead3_fixup_fdt(const void *fdt,
                                          const void *match_data)
 {
@@ -307,29 +174,10 @@ static __init const void *sead3_fixup_fdt(const void *fdt,
 
        fw_init_cmdline();
 
-       err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf));
-       if (err)
-               panic("Unable to open FDT: %d", err);
-
-       err = append_cmdline(fdt_buf);
-       if (err)
-               panic("Unable to patch FDT: %d", err);
-
-       err = append_memory(fdt_buf);
-       if (err)
-               panic("Unable to patch FDT: %d", err);
-
-       err = remove_gic(fdt_buf);
-       if (err)
-               panic("Unable to patch FDT: %d", err);
-
-       err = serial_config(fdt_buf);
-       if (err)
-               panic("Unable to patch FDT: %d", err);
-
-       err = fdt_pack(fdt_buf);
+       err = apply_mips_fdt_fixups(fdt_buf, sizeof(fdt_buf),
+                                   fdt, sead3_fdt_fixups);
        if (err)
-               panic("Unable to pack FDT: %d\n", err);
+               panic("Unable to fixup FDT: %d", err);
 
        return fdt_buf;
 }
index 1231b5a..3f32b37 100644 (file)
@@ -122,6 +122,33 @@ void __init device_tree_init(void)
                err = register_up_smp_ops();
 }
 
+int __init apply_mips_fdt_fixups(void *fdt_out, size_t fdt_out_size,
+                                const void *fdt_in,
+                                const struct mips_fdt_fixup *fixups)
+{
+       int err;
+
+       err = fdt_open_into(fdt_in, fdt_out, fdt_out_size);
+       if (err) {
+               pr_err("Failed to open FDT\n");
+               return err;
+       }
+
+       for (; fixups->apply; fixups++) {
+               err = fixups->apply(fdt_out);
+               if (err) {
+                       pr_err("Failed to apply FDT fixup \"%s\"\n",
+                              fixups->description);
+                       return err;
+               }
+       }
+
+       err = fdt_pack(fdt_out);
+       if (err)
+               pr_err("Failed to pack FDT\n");
+       return err;
+}
+
 void __init plat_time_init(void)
 {
        struct device_node *np;
index f67fbf1..3390e2f 100644 (file)
                };
        };
 };
+
+#ifdef CONFIG_FIT_IMAGE_FDT_BOSTON
+/ {
+       images {
+               fdt@boston {
+                       description = "img,boston Device Tree";
+                       data = /incbin/("boot/dts/img/boston.dtb");
+                       type = "flat_dt";
+                       arch = "mips";
+                       compression = "none";
+                       hash@0 {
+                               algo = "sha1";
+                       };
+               };
+       };
+
+       configurations {
+               conf@boston {
+                       description = "Boston Linux kernel";
+                       kernel = "kernel@0";
+                       fdt = "fdt@boston";
+               };
+       };
+};
+#endif /* CONFIG_FIT_IMAGE_FDT_BOSTON */
diff --git a/arch/mips/generic/yamon-dt.c b/arch/mips/generic/yamon-dt.c
new file mode 100644 (file)
index 0000000..6077bca
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2016 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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.
+ */
+
+#define pr_fmt(fmt) "yamon-dt: " fmt
+
+#include <linux/bug.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/libfdt.h>
+#include <linux/printk.h>
+
+#include <asm/fw/fw.h>
+#include <asm/yamon-dt.h>
+
+#define MAX_MEM_ARRAY_ENTRIES  2
+
+__init int yamon_dt_append_cmdline(void *fdt)
+{
+       int err, chosen_off;
+
+       /* find or add chosen node */
+       chosen_off = fdt_path_offset(fdt, "/chosen");
+       if (chosen_off == -FDT_ERR_NOTFOUND)
+               chosen_off = fdt_path_offset(fdt, "/chosen@0");
+       if (chosen_off == -FDT_ERR_NOTFOUND)
+               chosen_off = fdt_add_subnode(fdt, 0, "chosen");
+       if (chosen_off < 0) {
+               pr_err("Unable to find or add DT chosen node: %d\n",
+                      chosen_off);
+               return chosen_off;
+       }
+
+       err = fdt_setprop_string(fdt, chosen_off, "bootargs", fw_getcmdline());
+       if (err) {
+               pr_err("Unable to set bootargs property: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static unsigned int __init gen_fdt_mem_array(
+                                       const struct yamon_mem_region *regions,
+                                       __be32 *mem_array,
+                                       unsigned int max_entries,
+                                       unsigned long memsize)
+{
+       const struct yamon_mem_region *mr;
+       unsigned long size;
+       unsigned int entries = 0;
+
+       for (mr = regions; mr->size && memsize; ++mr) {
+               if (entries >= max_entries) {
+                       pr_warn("Number of regions exceeds max %u\n",
+                               max_entries);
+                       break;
+               }
+
+               /* How much of the remaining RAM fits in the next region? */
+               size = min_t(unsigned long, memsize, mr->size);
+               memsize -= size;
+
+               /* Emit a memory region */
+               *(mem_array++) = cpu_to_be32(mr->start);
+               *(mem_array++) = cpu_to_be32(size);
+               ++entries;
+
+               /* Discard the next mr->discard bytes */
+               memsize -= min_t(unsigned long, memsize, mr->discard);
+       }
+       return entries;
+}
+
+__init int yamon_dt_append_memory(void *fdt,
+                                 const struct yamon_mem_region *regions)
+{
+       unsigned long phys_memsize, memsize;
+       __be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES];
+       unsigned int mem_entries;
+       int i, err, mem_off;
+       char *var, param_name[10], *var_names[] = {
+               "ememsize", "memsize",
+       };
+
+       /* find memory size from the bootloader environment */
+       for (i = 0; i < ARRAY_SIZE(var_names); i++) {
+               var = fw_getenv(var_names[i]);
+               if (!var)
+                       continue;
+
+               err = kstrtoul(var, 0, &phys_memsize);
+               if (!err)
+                       break;
+
+               pr_warn("Failed to read the '%s' env variable '%s'\n",
+                       var_names[i], var);
+       }
+
+       if (!phys_memsize) {
+               pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n");
+               phys_memsize = 32 << 20;
+       }
+
+       /* default to using all available RAM */
+       memsize = phys_memsize;
+
+       /* allow the user to override the usable memory */
+       for (i = 0; i < ARRAY_SIZE(var_names); i++) {
+               snprintf(param_name, sizeof(param_name), "%s=", var_names[i]);
+               var = strstr(arcs_cmdline, param_name);
+               if (!var)
+                       continue;
+
+               memsize = memparse(var + strlen(param_name), NULL);
+       }
+
+       /* if the user says there's more RAM than we thought, believe them */
+       phys_memsize = max_t(unsigned long, phys_memsize, memsize);
+
+       /* find or add a memory node */
+       mem_off = fdt_path_offset(fdt, "/memory");
+       if (mem_off == -FDT_ERR_NOTFOUND)
+               mem_off = fdt_add_subnode(fdt, 0, "memory");
+       if (mem_off < 0) {
+               pr_err("Unable to find or add memory DT node: %d\n", mem_off);
+               return mem_off;
+       }
+
+       err = fdt_setprop_string(fdt, mem_off, "device_type", "memory");
+       if (err) {
+               pr_err("Unable to set memory node device_type: %d\n", err);
+               return err;
+       }
+
+       mem_entries = gen_fdt_mem_array(regions, mem_array,
+                                       MAX_MEM_ARRAY_ENTRIES, phys_memsize);
+       err = fdt_setprop(fdt, mem_off, "reg",
+                         mem_array, mem_entries * 2 * sizeof(mem_array[0]));
+       if (err) {
+               pr_err("Unable to set memory regs property: %d\n", err);
+               return err;
+       }
+
+       mem_entries = gen_fdt_mem_array(regions, mem_array,
+                                       MAX_MEM_ARRAY_ENTRIES, memsize);
+       err = fdt_setprop(fdt, mem_off, "linux,usable-memory",
+                         mem_array, mem_entries * 2 * sizeof(mem_array[0]));
+       if (err) {
+               pr_err("Unable to set linux,usable-memory property: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+__init int yamon_dt_serial_config(void *fdt)
+{
+       const char *yamontty, *mode_var;
+       char mode_var_name[9], path[20], parity;
+       unsigned int uart, baud, stop_bits;
+       bool hw_flow;
+       int chosen_off, err;
+
+       yamontty = fw_getenv("yamontty");
+       if (!yamontty || !strcmp(yamontty, "tty0")) {
+               uart = 0;
+       } else if (!strcmp(yamontty, "tty1")) {
+               uart = 1;
+       } else {
+               pr_warn("yamontty environment variable '%s' invalid\n",
+                       yamontty);
+               uart = 0;
+       }
+
+       baud = stop_bits = 0;
+       parity = 0;
+       hw_flow = false;
+
+       snprintf(mode_var_name, sizeof(mode_var_name), "modetty%u", uart);
+       mode_var = fw_getenv(mode_var_name);
+       if (mode_var) {
+               while (mode_var[0] >= '0' && mode_var[0] <= '9') {
+                       baud *= 10;
+                       baud += mode_var[0] - '0';
+                       mode_var++;
+               }
+               if (mode_var[0] == ',')
+                       mode_var++;
+               if (mode_var[0])
+                       parity = mode_var[0];
+               if (mode_var[0] == ',')
+                       mode_var++;
+               if (mode_var[0])
+                       stop_bits = mode_var[0] - '0';
+               if (mode_var[0] == ',')
+                       mode_var++;
+               if (!strcmp(mode_var, "hw"))
+                       hw_flow = true;
+       }
+
+       if (!baud)
+               baud = 38400;
+
+       if (parity != 'e' && parity != 'n' && parity != 'o')
+               parity = 'n';
+
+       if (stop_bits != 7 && stop_bits != 8)
+               stop_bits = 8;
+
+       WARN_ON(snprintf(path, sizeof(path), "serial%u:%u%c%u%s",
+                        uart, baud, parity, stop_bits,
+                        hw_flow ? "r" : "") >= sizeof(path));
+
+       /* find or add chosen node */
+       chosen_off = fdt_path_offset(fdt, "/chosen");
+       if (chosen_off == -FDT_ERR_NOTFOUND)
+               chosen_off = fdt_path_offset(fdt, "/chosen@0");
+       if (chosen_off == -FDT_ERR_NOTFOUND)
+               chosen_off = fdt_add_subnode(fdt, 0, "chosen");
+       if (chosen_off < 0) {
+               pr_err("Unable to find or add DT chosen node: %d\n",
+                      chosen_off);
+               return chosen_off;
+       }
+
+       err = fdt_setprop_string(fdt, chosen_off, "stdout-path", path);
+       if (err) {
+               pr_err("Unable to set stdout-path property: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
index 2535c7b..7c8aab2 100644 (file)
@@ -12,6 +12,8 @@ generic-y += mm-arch-hooks.h
 generic-y += parport.h
 generic-y += percpu.h
 generic-y += preempt.h
+generic-y += qrwlock.h
+generic-y += qspinlock.h
 generic-y += sections.h
 generic-y += segment.h
 generic-y += serial.h
index de781cf..da80878 100644 (file)
@@ -74,10 +74,7 @@ static inline int compute_return_epc(struct pt_regs *regs)
                        return __microMIPS_compute_return_epc(regs);
                if (cpu_has_mips16)
                        return __MIPS16e_compute_return_epc(regs);
-               return regs->cp0_epc;
-       }
-
-       if (!delay_slot(regs)) {
+       } else if (!delay_slot(regs)) {
                regs->cp0_epc += 4;
                return 0;
        }
index b71ab4a..903f3bf 100644 (file)
 #include <asm/compiler.h>
 #include <asm/war.h>
 
-static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
-{
-       __u32 retval;
-
-       smp_mb__before_llsc();
-
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               unsigned long dummy;
-
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     ll      %0, %3                  # xchg_u32      \n"
-               "       .set    mips0                                   \n"
-               "       move    %2, %z4                                 \n"
-               "       .set    arch=r4000                              \n"
-               "       sc      %2, %1                                  \n"
-               "       beqzl   %2, 1b                                  \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (retval), "=" GCC_OFF_SMALL_ASM() (*m), "=&r" (dummy)
-               : GCC_OFF_SMALL_ASM() (*m), "Jr" (val)
-               : "memory");
-       } else if (kernel_uses_llsc) {
-               unsigned long dummy;
-
-               do {
-                       __asm__ __volatile__(
-                       "       .set    "MIPS_ISA_ARCH_LEVEL"           \n"
-                       "       ll      %0, %3          # xchg_u32      \n"
-                       "       .set    mips0                           \n"
-                       "       move    %2, %z4                         \n"
-                       "       .set    "MIPS_ISA_ARCH_LEVEL"           \n"
-                       "       sc      %2, %1                          \n"
-                       "       .set    mips0                           \n"
-                       : "=&r" (retval), "=" GCC_OFF_SMALL_ASM() (*m),
-                         "=&r" (dummy)
-                       : GCC_OFF_SMALL_ASM() (*m), "Jr" (val)
-                       : "memory");
-               } while (unlikely(!dummy));
-       } else {
-               unsigned long flags;
-
-               raw_local_irq_save(flags);
-               retval = *m;
-               *m = val;
-               raw_local_irq_restore(flags);   /* implies memory barrier  */
-       }
-
-       smp_llsc_mb();
-
-       return retval;
-}
+/*
+ * Using a branch-likely instruction to check the result of an sc instruction
+ * works around a bug present in R10000 CPUs prior to revision 3.0 that could
+ * cause ll-sc sequences to execute non-atomically.
+ */
+#if R10000_LLSC_WAR
+# define __scbeqz "beqzl"
+#else
+# define __scbeqz "beqz"
+#endif
 
-#ifdef CONFIG_64BIT
-static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
-{
-       __u64 retval;
-
-       smp_mb__before_llsc();
-
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               unsigned long dummy;
-
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     lld     %0, %3                  # xchg_u64      \n"
-               "       move    %2, %z4                                 \n"
-               "       scd     %2, %1                                  \n"
-               "       beqzl   %2, 1b                                  \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (retval), "=" GCC_OFF_SMALL_ASM() (*m), "=&r" (dummy)
-               : GCC_OFF_SMALL_ASM() (*m), "Jr" (val)
-               : "memory");
-       } else if (kernel_uses_llsc) {
-               unsigned long dummy;
-
-               do {
-                       __asm__ __volatile__(
-                       "       .set    "MIPS_ISA_ARCH_LEVEL"           \n"
-                       "       lld     %0, %3          # xchg_u64      \n"
-                       "       move    %2, %z4                         \n"
-                       "       scd     %2, %1                          \n"
-                       "       .set    mips0                           \n"
-                       : "=&r" (retval), "=" GCC_OFF_SMALL_ASM() (*m),
-                         "=&r" (dummy)
-                       : GCC_OFF_SMALL_ASM() (*m), "Jr" (val)
-                       : "memory");
-               } while (unlikely(!dummy));
-       } else {
-               unsigned long flags;
-
-               raw_local_irq_save(flags);
-               retval = *m;
-               *m = val;
-               raw_local_irq_restore(flags);   /* implies memory barrier  */
-       }
+/*
+ * These functions doesn't exist, so if they are called you'll either:
+ *
+ * - Get an error at compile-time due to __compiletime_error, if supported by
+ *   your compiler.
+ *
+ * or:
+ *
+ * - Get an error at link-time due to the call to the missing function.
+ */
+extern unsigned long __cmpxchg_called_with_bad_pointer(void)
+       __compiletime_error("Bad argument size for cmpxchg");
+extern unsigned long __xchg_called_with_bad_pointer(void)
+       __compiletime_error("Bad argument size for xchg");
 
-       smp_llsc_mb();
+#define __xchg_asm(ld, st, m, val)                                     \
+({                                                                     \
+       __typeof(*(m)) __ret;                                           \
+                                                                       \
+       if (kernel_uses_llsc) {                                         \
+               __asm__ __volatile__(                                   \
+               "       .set    push                            \n"     \
+               "       .set    noat                            \n"     \
+               "       .set    " MIPS_ISA_ARCH_LEVEL "         \n"     \
+               "1:     " ld "  %0, %2          # __xchg_asm    \n"     \
+               "       .set    mips0                           \n"     \
+               "       move    $1, %z3                         \n"     \
+               "       .set    " MIPS_ISA_ARCH_LEVEL "         \n"     \
+               "       " st "  $1, %1                          \n"     \
+               "\t" __scbeqz " $1, 1b                          \n"     \
+               "       .set    pop                             \n"     \
+               : "=&r" (__ret), "=" GCC_OFF_SMALL_ASM() (*m)           \
+               : GCC_OFF_SMALL_ASM() (*m), "Jr" (val)                  \
+               : "memory");                                            \
+       } else {                                                        \
+               unsigned long __flags;                                  \
+                                                                       \
+               raw_local_irq_save(__flags);                            \
+               __ret = *m;                                             \
+               *m = val;                                               \
+               raw_local_irq_restore(__flags);                         \
+       }                                                               \
+                                                                       \
+       __ret;                                                          \
+})
 
-       return retval;
-}
-#else
-extern __u64 __xchg_u64_unsupported_on_32bit_kernels(volatile __u64 * m, __u64 val);
-#define __xchg_u64 __xchg_u64_unsupported_on_32bit_kernels
-#endif
+extern unsigned long __xchg_small(volatile void *ptr, unsigned long val,
+                                 unsigned int size);
 
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+static inline unsigned long __xchg(volatile void *ptr, unsigned long x,
+                                  int size)
 {
        switch (size) {
+       case 1:
+       case 2:
+               return __xchg_small(ptr, x, size);
+
        case 4:
-               return __xchg_u32(ptr, x);
+               return __xchg_asm("ll", "sc", (volatile u32 *)ptr, x);
+
        case 8:
-               return __xchg_u64(ptr, x);
-       }
+               if (!IS_ENABLED(CONFIG_64BIT))
+                       return __xchg_called_with_bad_pointer();
+
+               return __xchg_asm("lld", "scd", (volatile u64 *)ptr, x);
 
-       return x;
+       default:
+               return __xchg_called_with_bad_pointer();
+       }
 }
 
 #define xchg(ptr, x)                                                   \
 ({                                                                     \
-       BUILD_BUG_ON(sizeof(*(ptr)) & ~0xc);                            \
+       __typeof__(*(ptr)) __res;                                       \
                                                                        \
-       ((__typeof__(*(ptr)))                                           \
-               __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))));     \
+       smp_mb__before_llsc();                                          \
+                                                                       \
+       __res = (__typeof__(*(ptr)))                                    \
+               __xchg((ptr), (unsigned long)(x), sizeof(*(ptr)));      \
+                                                                       \
+       smp_llsc_mb();                                                  \
+                                                                       \
+       __res;                                                          \
 })
 
 #define __cmpxchg_asm(ld, st, m, old, new)                             \
 ({                                                                     \
        __typeof(*(m)) __ret;                                           \
                                                                        \
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {                      \
-               __asm__ __volatile__(                                   \
-               "       .set    push                            \n"     \
-               "       .set    noat                            \n"     \
-               "       .set    arch=r4000                      \n"     \
-               "1:     " ld "  %0, %2          # __cmpxchg_asm \n"     \
-               "       bne     %0, %z3, 2f                     \n"     \
-               "       .set    mips0                           \n"     \
-               "       move    $1, %z4                         \n"     \
-               "       .set    arch=r4000                      \n"     \
-               "       " st "  $1, %1                          \n"     \
-               "       beqzl   $1, 1b                          \n"     \
-               "2:                                             \n"     \
-               "       .set    pop                             \n"     \
-               : "=&r" (__ret), "=" GCC_OFF_SMALL_ASM() (*m)           \
-               : GCC_OFF_SMALL_ASM() (*m), "Jr" (old), "Jr" (new)              \
-               : "memory");                                            \
-       } else if (kernel_uses_llsc) {                                  \
+       if (kernel_uses_llsc) {                                         \
                __asm__ __volatile__(                                   \
                "       .set    push                            \n"     \
                "       .set    noat                            \n"     \
@@ -170,7 +124,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
                "       move    $1, %z4                         \n"     \
                "       .set    "MIPS_ISA_ARCH_LEVEL"           \n"     \
                "       " st "  $1, %1                          \n"     \
-               "       beqz    $1, 1b                          \n"     \
+               "\t" __scbeqz " $1, 1b                          \n"     \
                "       .set    pop                             \n"     \
                "2:                                             \n"     \
                : "=&r" (__ret), "=" GCC_OFF_SMALL_ASM() (*m)           \
@@ -189,44 +143,50 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
        __ret;                                                          \
 })
 
-/*
- * This function doesn't exist, so you'll get a linker error
- * if something tries to do an invalid cmpxchg().
- */
-extern void __cmpxchg_called_with_bad_pointer(void);
+extern unsigned long __cmpxchg_small(volatile void *ptr, unsigned long old,
+                                    unsigned long new, unsigned int size);
+
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+                                     unsigned long new, unsigned int size)
+{
+       switch (size) {
+       case 1:
+       case 2:
+               return __cmpxchg_small(ptr, old, new, size);
+
+       case 4:
+               return __cmpxchg_asm("ll", "sc", (volatile u32 *)ptr, old, new);
+
+       case 8:
+               /* lld/scd are only available for MIPS64 */
+               if (!IS_ENABLED(CONFIG_64BIT))
+                       return __cmpxchg_called_with_bad_pointer();
+
+               return __cmpxchg_asm("lld", "scd", (volatile u64 *)ptr, old, new);
 
-#define __cmpxchg(ptr, old, new, pre_barrier, post_barrier)            \
+       default:
+               return __cmpxchg_called_with_bad_pointer();
+       }
+}
+
+#define cmpxchg_local(ptr, old, new)                                   \
+       ((__typeof__(*(ptr)))                                           \
+               __cmpxchg((ptr),                                        \
+                         (unsigned long)(__typeof__(*(ptr)))(old),     \
+                         (unsigned long)(__typeof__(*(ptr)))(new),     \
+                         sizeof(*(ptr))))
+
+#define cmpxchg(ptr, old, new)                                         \
 ({                                                                     \
-       __typeof__(ptr) __ptr = (ptr);                                  \
-       __typeof__(*(ptr)) __old = (old);                               \
-       __typeof__(*(ptr)) __new = (new);                               \
-       __typeof__(*(ptr)) __res = 0;                                   \
+       __typeof__(*(ptr)) __res;                                       \
                                                                        \
-       pre_barrier;                                                    \
-                                                                       \
-       switch (sizeof(*(__ptr))) {                                     \
-       case 4:                                                         \
-               __res = __cmpxchg_asm("ll", "sc", __ptr, __old, __new); \
-               break;                                                  \
-       case 8:                                                         \
-               if (sizeof(long) == 8) {                                \
-                       __res = __cmpxchg_asm("lld", "scd", __ptr,      \
-                                          __old, __new);               \
-                       break;                                          \
-               }                                                       \
-       default:                                                        \
-               __cmpxchg_called_with_bad_pointer();                    \
-               break;                                                  \
-       }                                                               \
-                                                                       \
-       post_barrier;                                                   \
+       smp_mb__before_llsc();                                          \
+       __res = cmpxchg_local((ptr), (old), (new));                     \
+       smp_llsc_mb();                                                  \
                                                                        \
        __res;                                                          \
 })
 
-#define cmpxchg(ptr, old, new)         __cmpxchg(ptr, old, new, smp_mb__before_llsc(), smp_llsc_mb())
-#define cmpxchg_local(ptr, old, new)   __cmpxchg(ptr, old, new, , )
-
 #ifdef CONFIG_64BIT
 #define cmpxchg64_local(ptr, o, n)                                     \
   ({                                                                   \
@@ -245,4 +205,6 @@ extern void __cmpxchg_called_with_bad_pointer(void);
 #define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n))
 #endif
 
+#undef __scbeqz
+
 #endif /* __ASM_CMPXCHG_H */
index 494d382..8baa903 100644 (file)
 #ifndef cpu_has_mips16
 #define cpu_has_mips16         (cpu_data[0].ases & MIPS_ASE_MIPS16)
 #endif
+#ifndef cpu_has_mips16e2
+#define cpu_has_mips16e2       (cpu_data[0].ases & MIPS_ASE_MIPS16E2)
+#endif
 #ifndef cpu_has_mdmx
 #define cpu_has_mdmx           (cpu_data[0].ases & MIPS_ASE_MDMX)
 #endif
 # define cpu_has_perf          (cpu_data[0].options & MIPS_CPU_PERF)
 #endif
 
+#if defined(CONFIG_SMP) && defined(__mips_isa_rev) && (__mips_isa_rev >= 6)
+/*
+ * Some systems share FTLB RAMs between threads within a core (siblings in
+ * kernel parlance). This means that FTLB entries may become invalid at almost
+ * any point when an entry is evicted due to a sibling thread writing an entry
+ * to the shared FTLB RAM.
+ *
+ * This is only relevant to SMP systems, and the only systems that exhibit this
+ * property implement MIPSr6 or higher so we constrain support for this to
+ * kernels that will run on such systems.
+ */
+# ifndef cpu_has_shared_ftlb_ram
+#  define cpu_has_shared_ftlb_ram \
+       (current_cpu_data.options & MIPS_CPU_SHARED_FTLB_RAM)
+# endif
+
+/*
+ * Some systems take this a step further & share FTLB entries between siblings.
+ * This is implemented as TLB writes happening as usual, but if an entry
+ * written by a sibling exists in the shared FTLB for a translation which would
+ * otherwise cause a TLB refill exception then the CPU will use the entry
+ * written by its sibling rather than triggering a refill & writing a matching
+ * TLB entry for itself.
+ *
+ * This is naturally only valid if a TLB entry is known to be suitable for use
+ * on all siblings in a CPU, and so it only takes effect when MMIDs are in use
+ * rather than ASIDs or when a TLB entry is marked global.
+ */
+# ifndef cpu_has_shared_ftlb_entries
+#  define cpu_has_shared_ftlb_entries \
+       (current_cpu_data.options & MIPS_CPU_SHARED_FTLB_ENTRIES)
+# endif
+#endif /* SMP && __mips_isa_rev >= 6 */
+
+#ifndef cpu_has_shared_ftlb_ram
+# define cpu_has_shared_ftlb_ram 0
+#endif
+#ifndef cpu_has_shared_ftlb_entries
+# define cpu_has_shared_ftlb_entries 0
+#endif
+
 /*
  * Guest capabilities
  */
index bdd6dc1..175fe56 100644 (file)
@@ -84,6 +84,7 @@ static inline int __pure __get_cpu_type(const int cpu_type)
 
 #ifdef CONFIG_SYS_HAS_CPU_MIPS64_R6
        case CPU_I6400:
+       case CPU_I6500:
        case CPU_P6600:
 #endif
 
index 98f5930..d0c152b 100644 (file)
 #define PRID_IMP_P5600         0xa800
 #define PRID_IMP_I6400         0xa900
 #define PRID_IMP_M6250         0xab00
+#define PRID_IMP_I6500         0xb000
 
 /*
  * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE
 #define PRID_REV_LOONGSON3B_R1 0x0006
 #define PRID_REV_LOONGSON3B_R2 0x0007
 #define PRID_REV_LOONGSON3A_R2 0x0008
+#define PRID_REV_LOONGSON3A_R3 0x0009
 
 /*
  * Older processors used to encode processor version and revision in two
@@ -322,7 +324,7 @@ enum cpu_type_enum {
         */
        CPU_5KC, CPU_5KE, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
        CPU_LOONGSON3, CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS,
-       CPU_CAVIUM_OCTEON2, CPU_CAVIUM_OCTEON3, CPU_XLR, CPU_XLP,
+       CPU_CAVIUM_OCTEON2, CPU_CAVIUM_OCTEON3, CPU_XLR, CPU_XLP, CPU_I6500,
 
        CPU_QEMU_GENERIC,
 
@@ -416,6 +418,10 @@ enum cpu_type_enum {
 #define MIPS_CPU_GUESTID       MBIT_ULL(51)    /* CPU uses VZ ASE GuestID feature */
 #define MIPS_CPU_DRG           MBIT_ULL(52)    /* CPU has VZ Direct Root to Guest (DRG) */
 #define MIPS_CPU_UFR           MBIT_ULL(53)    /* CPU supports User mode FR switching */
+#define MIPS_CPU_SHARED_FTLB_RAM \
+                               MBIT_ULL(54)    /* CPU shares FTLB RAM with another */
+#define MIPS_CPU_SHARED_FTLB_ENTRIES \
+                               MBIT_ULL(55)    /* CPU shares FTLB entries with another */
 
 /*
  * CPU ASE encodings
@@ -430,5 +436,6 @@ enum cpu_type_enum {
 #define MIPS_ASE_VZ            0x00000080 /* Virtualization ASE */
 #define MIPS_ASE_MSA           0x00000100 /* MIPS SIMD Architecture */
 #define MIPS_ASE_DSP3          0x00000200 /* Signal Processing ASE Rev 3*/
+#define MIPS_ASE_MIPS16E2      0x00000400 /* MIPS16e2 */
 
 #endif /* _ASM_CPU_H */
index ddd1c91..c5d3517 100644 (file)
@@ -18,7 +18,7 @@
 #include <irq.h>
 
 #define IRQ_STACK_SIZE                 THREAD_SIZE
-#define IRQ_STACK_START                        (IRQ_STACK_SIZE - sizeof(unsigned long))
+#define IRQ_STACK_START                        (IRQ_STACK_SIZE - 16)
 
 extern void *irq_stack[NR_CPUS];
 
index ade0356..e6a8108 100644 (file)
@@ -40,6 +40,7 @@
 #endif
 
 #define cpu_has_mips16                 0
+#define cpu_has_mips16e2               0
 #define cpu_has_mdmx                   0
 #define cpu_has_mips3d                 0
 #define cpu_has_smartmips              0
index c5b6eef..bace5b9 100644 (file)
@@ -31,6 +31,7 @@
 #define cpu_has_ejtag                  1
 #define cpu_has_llsc                   1
 #define cpu_has_mips16                 0
+#define cpu_has_mips16e2               0
 #define cpu_has_mdmx                   0
 #define cpu_has_mips3d                 0
 #define cpu_has_smartmips              0
index bc1167d..b56cf10 100644 (file)
@@ -19,6 +19,7 @@
 #define cpu_has_ejtag                  1
 #define cpu_has_llsc                   1
 #define cpu_has_mips16                 0
+#define cpu_has_mips16e2               0
 #define cpu_has_mdmx                   0
 #define cpu_has_mips3d                 0
 #define cpu_has_smartmips              0
index 30c5cd9..291fe90 100644 (file)
@@ -37,6 +37,7 @@
 #endif
 
 #define cpu_has_mips16         0
+#define cpu_has_mips16e2       0
 #define cpu_has_mdmx           0
 #define cpu_has_mips3d         0
 #define cpu_has_smartmips      0
index 21eae03..2ec1023 100644 (file)
@@ -27,6 +27,7 @@
 #define cpu_has_mcheck                 0
 #define cpu_has_ejtag                  0
 #define cpu_has_mips16                 0
+#define cpu_has_mips16e2               0
 #define cpu_has_mdmx                   0
 #define cpu_has_mips3d                 0
 #define cpu_has_smartmips              0
index 0b9a942..9c72e54 100644 (file)
@@ -27,7 +27,7 @@ static inline void CMOS_WRITE(unsigned char data, unsigned long addr)
        outb_p(data, RTC_PORT(1));
 }
 
-#define RTC_ALWAYS_BCD 1
+#define RTC_ALWAYS_BCD 0
 
 #ifndef mc146818_decode_year
 #define mc146818_decode_year(year) ((year) < 70 ? (year) + 2000 : (year) + 1900)
index 9b19b72..b80d5ea 100644 (file)
@@ -19,6 +19,7 @@
 #define cpu_has_32fpr          1
 #define cpu_has_counter                1
 #define cpu_has_mips16         0
+#define cpu_has_mips16e2       0
 #define cpu_has_divec          0
 #define cpu_has_cache_cdex_p   1
 #define cpu_has_prefetch       0
index 7449794..136d6d4 100644 (file)
@@ -43,6 +43,7 @@
 #define cpu_has_ejtag                  0
 #define cpu_has_llsc                   1
 #define cpu_has_mips16                 0
+#define cpu_has_mips16e2               0
 #define cpu_has_mdmx                   0
 #define cpu_has_mips3d                 0
 #define cpu_has_smartmips              0
index 4cec06d..ba8b4e3 100644 (file)
@@ -16,6 +16,7 @@
  */
 #define cpu_has_watch          1
 #define cpu_has_mips16         0
+#define cpu_has_mips16e2       0
 #define cpu_has_divec          0
 #define cpu_has_vce            0
 #define cpu_has_cache_cdex_p   0
index 241409b..63b4c88 100644 (file)
@@ -29,6 +29,7 @@
 #define cpu_has_32fpr          1
 #define cpu_has_counter                1
 #define cpu_has_mips16         0
+#define cpu_has_mips16e2       0
 #define cpu_has_vce            0
 #define cpu_has_cache_cdex_s   0
 #define cpu_has_mcheck         0
index 0933f94..7c5e576 100644 (file)
@@ -23,6 +23,7 @@
 #define cpu_has_ejtag 1
 #define cpu_has_llsc           1
 #define cpu_has_mips16 0
+#define cpu_has_mips16e2       0
 #define cpu_has_mdmx 0
 #define cpu_has_mips3d 0
 #define cpu_has_smartmips 0
index d3f3258..9f9bb9c 100644 (file)
@@ -27,12 +27,22 @@ struct efi_memory_map_loongson {
 } __packed;
 
 enum loongson_cpu_type {
-       Loongson_2E = 0,
-       Loongson_2F = 1,
-       Loongson_3A = 2,
-       Loongson_3B = 3,
-       Loongson_1A = 4,
-       Loongson_1B = 5
+       Legacy_2E = 0x0,
+       Legacy_2F = 0x1,
+       Legacy_3A = 0x2,
+       Legacy_3B = 0x3,
+       Legacy_1A = 0x4,
+       Legacy_1B = 0x5,
+       Legacy_2G = 0x6,
+       Legacy_2H = 0x7,
+       Loongson_1A = 0x100,
+       Loongson_1B = 0x101,
+       Loongson_2E = 0x200,
+       Loongson_2F = 0x201,
+       Loongson_2G = 0x202,
+       Loongson_2H = 0x203,
+       Loongson_3A = 0x300,
+       Loongson_3B = 0x301
 };
 
 /*
index 89328a3..581915c 100644 (file)
@@ -32,6 +32,7 @@
 #define cpu_has_mcheck         0
 #define cpu_has_mdmx           0
 #define cpu_has_mips16         0
+#define cpu_has_mips16e2       0
 #define cpu_has_mips3d         0
 #define cpu_has_mipsmt         0
 #define cpu_has_smartmips      0
index 091deb1..0c29ff8 100644 (file)
@@ -13,6 +13,7 @@
 #define cpu_has_4k_cache       1
 #define cpu_has_watch          1
 #define cpu_has_mips16         0
+#define cpu_has_mips16e2       0
 #define cpu_has_counter                1
 #define cpu_has_divec          1
 #define cpu_has_vce            0
index b153075..6a1087e 100644 (file)
@@ -48,6 +48,7 @@
 #define cpu_has_llsc                   1
 
 #define cpu_has_mips16                 0
+#define cpu_has_mips16e2               0
 #define cpu_has_mdmx                   0
 #define cpu_has_mips3d                 0
 #define cpu_has_smartmips              0
index d38be66..e1e1823 100644 (file)
@@ -17,6 +17,7 @@
 #define cpu_has_counter                1
 #define cpu_has_watch          0
 #define cpu_has_mips16         0
+#define cpu_has_mips16e2       0
 #define cpu_has_divec          0
 #define cpu_has_cache_cdex_p   1
 #define cpu_has_prefetch       0
index 92927b6..7022358 100644 (file)
@@ -13,6 +13,7 @@
  */
 #define cpu_has_watch          1
 #define cpu_has_mips16         0
+#define cpu_has_mips16e2       0
 #define cpu_has_divec          1
 #define cpu_has_vce            0
 #define cpu_has_cache_cdex_p   0
index 7f5144c..b9d39dc 100644 (file)
@@ -6,6 +6,7 @@
 #define cpu_has_inclusive_pcaches      0
 
 #define cpu_has_mips16         0
+#define cpu_has_mips16e2       0
 #define cpu_has_mdmx           0
 #define cpu_has_mips3d         0
 #define cpu_has_smartmips      0
index 6b444cd..ecb6c73 100644 (file)
@@ -60,4 +60,35 @@ mips_machine_is_compatible(const struct mips_machine *mach, const void *fdt)
        return NULL;
 }
 
+/**
+ * struct mips_fdt_fixup - Describe a fixup to apply to an FDT
+ * @apply: applies the fixup to @fdt, returns zero on success else -errno
+ * @description: a short description of the fixup
+ *
+ * Describes a fixup applied to an FDT blob by the @apply function. The
+ * @description field provides a short description of the fixup intended for
+ * use in error messages if the @apply function returns non-zero.
+ */
+struct mips_fdt_fixup {
+       int (*apply)(void *fdt);
+       const char *description;
+};
+
+/**
+ * apply_mips_fdt_fixups() - apply fixups to an FDT blob
+ * @fdt_out: buffer in which to place the fixed-up FDT
+ * @fdt_out_size: the size of the @fdt_out buffer
+ * @fdt_in: the FDT blob
+ * @fixups: pointer to an array of fixups to be applied
+ *
+ * Loop through the array of fixups pointed to by @fixups, calling the apply
+ * function on each until either one returns an error or we reach the end of
+ * the list as indicated by an entry with a NULL apply field.
+ *
+ * Return: zero on success, else -errno
+ */
+extern int __init apply_mips_fdt_fixups(void *fdt_out, size_t fdt_out_size,
+                                       const void *fdt_in,
+                                       const struct mips_fdt_fixup *fixups);
+
 #endif /* __MIPS_ASM_MACHINE_H__ */
index 6875b69..dbb0ece 100644 (file)
 #define MIPS_CONF5_SBRI                (_ULCAST_(1) << 6)
 #define MIPS_CONF5_FRE         (_ULCAST_(1) << 8)
 #define MIPS_CONF5_UFE         (_ULCAST_(1) << 9)
+#define MIPS_CONF5_CA2         (_ULCAST_(1) << 14)
 #define MIPS_CONF5_MSAEN       (_ULCAST_(1) << 27)
 #define MIPS_CONF5_EVA         (_ULCAST_(1) << 28)
 #define MIPS_CONF5_CV          (_ULCAST_(1) << 29)
index 702c273..e51add1 100644 (file)
@@ -47,8 +47,8 @@ typedef struct {
 #define Elf_Mips_Rel   Elf32_Rel
 #define Elf_Mips_Rela  Elf32_Rela
 
-#define ELF_MIPS_R_SYM(rel) ELF32_R_SYM(rel.r_info)
-#define ELF_MIPS_R_TYPE(rel) ELF32_R_TYPE(rel.r_info)
+#define ELF_MIPS_R_SYM(rel) ELF32_R_SYM((rel).r_info)
+#define ELF_MIPS_R_TYPE(rel) ELF32_R_TYPE((rel).r_info)
 
 #endif
 
@@ -65,8 +65,8 @@ typedef struct {
 #define Elf_Mips_Rel   Elf64_Mips_Rel
 #define Elf_Mips_Rela  Elf64_Mips_Rela
 
-#define ELF_MIPS_R_SYM(rel) (rel.r_sym)
-#define ELF_MIPS_R_TYPE(rel) (rel.r_type)
+#define ELF_MIPS_R_SYM(rel) ((rel).r_sym)
+#define ELF_MIPS_R_TYPE(rel) ((rel).r_type)
 
 #endif
 
index a1bdb1e..39b9f31 100644 (file)
@@ -116,7 +116,7 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
 {
        pud_t *pud;
 
-       pud = (pud_t *) __get_free_pages(GFP_KERNEL|__GFP_REPEAT, PUD_ORDER);
+       pud = (pud_t *) __get_free_pages(GFP_KERNEL, PUD_ORDER);
        if (pud)
                pud_init((unsigned long)pud, (unsigned long)invalid_pmd_table);
        return pud;
index 98a117a..bab3d41 100644 (file)
@@ -47,7 +47,7 @@ extern int __cpu_logical_map[NR_CPUS];
 /* Mask of CPUs which are currently definitely operating coherently */
 extern cpumask_t cpu_coherent_mask;
 
-extern void asmlinkage smp_bootstrap(void);
+extern asmlinkage void smp_bootstrap(void);
 
 extern void calculate_cpu_foreign_map(void);
 
index a8df44d..a7d21da 100644 (file)
@@ -9,431 +9,9 @@
 #ifndef _ASM_SPINLOCK_H
 #define _ASM_SPINLOCK_H
 
-#include <linux/compiler.h>
-
-#include <asm/barrier.h>
 #include <asm/processor.h>
-#include <asm/compiler.h>
-#include <asm/war.h>
-
-/*
- * Your basic SMP spinlocks, allowing only a single CPU anywhere
- *
- * Simple spin lock operations.         There are two variants, one clears IRQ's
- * on the local processor, one does not.
- *
- * These are fair FIFO ticket locks
- *
- * (the type definitions are in asm/spinlock_types.h)
- */
-
-
-/*
- * Ticket locks are conceptually two parts, one indicating the current head of
- * the queue, and the other indicating the current tail. The lock is acquired
- * by atomically noting the tail and incrementing it by one (thus adding
- * ourself to the queue and noting our position), then waiting until the head
- * becomes equal to the the initial value of the tail.
- */
-
-static inline int arch_spin_is_locked(arch_spinlock_t *lock)
-{
-       u32 counters = ACCESS_ONCE(lock->lock);
-
-       return ((counters >> 16) ^ counters) & 0xffff;
-}
-
-static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
-{
-       return lock.h.serving_now == lock.h.ticket;
-}
-
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-       u16 owner = READ_ONCE(lock->h.serving_now);
-       smp_rmb();
-       for (;;) {
-               arch_spinlock_t tmp = READ_ONCE(*lock);
-
-               if (tmp.h.serving_now == tmp.h.ticket ||
-                   tmp.h.serving_now != owner)
-                       break;
-
-               cpu_relax();
-       }
-       smp_acquire__after_ctrl_dep();
-}
-
-static inline int arch_spin_is_contended(arch_spinlock_t *lock)
-{
-       u32 counters = ACCESS_ONCE(lock->lock);
-
-       return (((counters >> 16) - counters) & 0xffff) > 1;
-}
-#define arch_spin_is_contended arch_spin_is_contended
-
-static inline void arch_spin_lock(arch_spinlock_t *lock)
-{
-       int my_ticket;
-       int tmp;
-       int inc = 0x10000;
-
-       if (R10000_LLSC_WAR) {
-               __asm__ __volatile__ (
-               "       .set push               # arch_spin_lock        \n"
-               "       .set noreorder                                  \n"
-               "                                                       \n"
-               "1:     ll      %[ticket], %[ticket_ptr]                \n"
-               "       addu    %[my_ticket], %[ticket], %[inc]         \n"
-               "       sc      %[my_ticket], %[ticket_ptr]             \n"
-               "       beqzl   %[my_ticket], 1b                        \n"
-               "        nop                                            \n"
-               "       srl     %[my_ticket], %[ticket], 16             \n"
-               "       andi    %[ticket], %[ticket], 0xffff            \n"
-               "       bne     %[ticket], %[my_ticket], 4f             \n"
-               "        subu   %[ticket], %[my_ticket], %[ticket]      \n"
-               "2:                                                     \n"
-               "       .subsection 2                                   \n"
-               "4:     andi    %[ticket], %[ticket], 0xffff            \n"
-               "       sll     %[ticket], 5                            \n"
-               "                                                       \n"
-               "6:     bnez    %[ticket], 6b                           \n"
-               "        subu   %[ticket], 1                            \n"
-               "                                                       \n"
-               "       lhu     %[ticket], %[serving_now_ptr]           \n"
-               "       beq     %[ticket], %[my_ticket], 2b             \n"
-               "        subu   %[ticket], %[my_ticket], %[ticket]      \n"
-               "       b       4b                                      \n"
-               "        subu   %[ticket], %[ticket], 1                 \n"
-               "       .previous                                       \n"
-               "       .set pop                                        \n"
-               : [ticket_ptr] "+" GCC_OFF_SMALL_ASM() (lock->lock),
-                 [serving_now_ptr] "+m" (lock->h.serving_now),
-                 [ticket] "=&r" (tmp),
-                 [my_ticket] "=&r" (my_ticket)
-               : [inc] "r" (inc));
-       } else {
-               __asm__ __volatile__ (
-               "       .set push               # arch_spin_lock        \n"
-               "       .set noreorder                                  \n"
-               "                                                       \n"
-               "1:     ll      %[ticket], %[ticket_ptr]                \n"
-               "       addu    %[my_ticket], %[ticket], %[inc]         \n"
-               "       sc      %[my_ticket], %[ticket_ptr]             \n"
-               "       beqz    %[my_ticket], 1b                        \n"
-               "        srl    %[my_ticket], %[ticket], 16             \n"
-               "       andi    %[ticket], %[ticket], 0xffff            \n"
-               "       bne     %[ticket], %[my_ticket], 4f             \n"
-               "        subu   %[ticket], %[my_ticket], %[ticket]      \n"
-               "2:     .insn                                           \n"
-               "       .subsection 2                                   \n"
-               "4:     andi    %[ticket], %[ticket], 0xffff            \n"
-               "       sll     %[ticket], 5                            \n"
-               "                                                       \n"
-               "6:     bnez    %[ticket], 6b                           \n"
-               "        subu   %[ticket], 1                            \n"
-               "                                                       \n"
-               "       lhu     %[ticket], %[serving_now_ptr]           \n"
-               "       beq     %[ticket], %[my_ticket], 2b             \n"
-               "        subu   %[ticket], %[my_ticket], %[ticket]      \n"
-               "       b       4b                                      \n"
-               "        subu   %[ticket], %[ticket], 1                 \n"
-               "       .previous                                       \n"
-               "       .set pop                                        \n"
-               : [ticket_ptr] "+" GCC_OFF_SMALL_ASM() (lock->lock),
-                 [serving_now_ptr] "+m" (lock->h.serving_now),
-                 [ticket] "=&r" (tmp),
-                 [my_ticket] "=&r" (my_ticket)
-               : [inc] "r" (inc));
-       }
-
-       smp_llsc_mb();
-}
-
-static inline void arch_spin_unlock(arch_spinlock_t *lock)
-{
-       unsigned int serving_now = lock->h.serving_now + 1;
-       wmb();
-       lock->h.serving_now = (u16)serving_now;
-       nudge_writes();
-}
-
-static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock)
-{
-       int tmp, tmp2, tmp3;
-       int inc = 0x10000;
-
-       if (R10000_LLSC_WAR) {
-               __asm__ __volatile__ (
-               "       .set push               # arch_spin_trylock     \n"
-               "       .set noreorder                                  \n"
-               "                                                       \n"
-               "1:     ll      %[ticket], %[ticket_ptr]                \n"
-               "       srl     %[my_ticket], %[ticket], 16             \n"
-               "       andi    %[now_serving], %[ticket], 0xffff       \n"
-               "       bne     %[my_ticket], %[now_serving], 3f        \n"
-               "        addu   %[ticket], %[ticket], %[inc]            \n"
-               "       sc      %[ticket], %[ticket_ptr]                \n"
-               "       beqzl   %[ticket], 1b                           \n"
-               "        li     %[ticket], 1                            \n"
-               "2:                                                     \n"
-               "       .subsection 2                                   \n"
-               "3:     b       2b                                      \n"
-               "        li     %[ticket], 0                            \n"
-               "       .previous                                       \n"
-               "       .set pop                                        \n"
-               : [ticket_ptr] "+" GCC_OFF_SMALL_ASM() (lock->lock),
-                 [ticket] "=&r" (tmp),
-                 [my_ticket] "=&r" (tmp2),
-                 [now_serving] "=&r" (tmp3)
-               : [inc] "r" (inc));
-       } else {
-               __asm__ __volatile__ (
-               "       .set push               # arch_spin_trylock     \n"
-               "       .set noreorder                                  \n"
-               "                                                       \n"
-               "1:     ll      %[ticket], %[ticket_ptr]                \n"
-               "       srl     %[my_ticket], %[ticket], 16             \n"
-               "       andi    %[now_serving], %[ticket], 0xffff       \n"
-               "       bne     %[my_ticket], %[now_serving], 3f        \n"
-               "        addu   %[ticket], %[ticket], %[inc]            \n"
-               "       sc      %[ticket], %[ticket_ptr]                \n"
-               "       beqz    %[ticket], 1b                           \n"
-               "        li     %[ticket], 1                            \n"
-               "2:     .insn                                           \n"
-               "       .subsection 2                                   \n"
-               "3:     b       2b                                      \n"
-               "        li     %[ticket], 0                            \n"
-               "       .previous                                       \n"
-               "       .set pop                                        \n"
-               : [ticket_ptr] "+" GCC_OFF_SMALL_ASM() (lock->lock),
-                 [ticket] "=&r" (tmp),
-                 [my_ticket] "=&r" (tmp2),
-                 [now_serving] "=&r" (tmp3)
-               : [inc] "r" (inc));
-       }
-
-       smp_llsc_mb();
-
-       return tmp;
-}
-
-/*
- * Read-write spinlocks, allowing multiple readers but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts but no interrupt
- * writers. For those circumstances we can "mix" irq-safe locks - any writer
- * needs to get a irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- */
-
-/*
- * read_can_lock - would read_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_read_can_lock(rw) ((rw)->lock >= 0)
-
-/*
- * write_can_lock - would write_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_write_can_lock(rw) (!(rw)->lock)
-
-static inline void arch_read_lock(arch_rwlock_t *rw)
-{
-       unsigned int tmp;
-
-       if (R10000_LLSC_WAR) {
-               __asm__ __volatile__(
-               "       .set    noreorder       # arch_read_lock        \n"
-               "1:     ll      %1, %2                                  \n"
-               "       bltz    %1, 1b                                  \n"
-               "        addu   %1, 1                                   \n"
-               "       sc      %1, %0                                  \n"
-               "       beqzl   %1, 1b                                  \n"
-               "        nop                                            \n"
-               "       .set    reorder                                 \n"
-               : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp)
-               : GCC_OFF_SMALL_ASM() (rw->lock)
-               : "memory");
-       } else {
-               do {
-                       __asm__ __volatile__(
-                       "1:     ll      %1, %2  # arch_read_lock        \n"
-                       "       bltz    %1, 1b                          \n"
-                       "        addu   %1, 1                           \n"
-                       "2:     sc      %1, %0                          \n"
-                       : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp)
-                       : GCC_OFF_SMALL_ASM() (rw->lock)
-                       : "memory");
-               } while (unlikely(!tmp));
-       }
-
-       smp_llsc_mb();
-}
-
-static inline void arch_read_unlock(arch_rwlock_t *rw)
-{
-       unsigned int tmp;
-
-       smp_mb__before_llsc();
-
-       if (R10000_LLSC_WAR) {
-               __asm__ __volatile__(
-               "1:     ll      %1, %2          # arch_read_unlock      \n"
-               "       addiu   %1, -1                                  \n"
-               "       sc      %1, %0                                  \n"
-               "       beqzl   %1, 1b                                  \n"
-               : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp)
-               : GCC_OFF_SMALL_ASM() (rw->lock)
-               : "memory");
-       } else {
-               do {
-                       __asm__ __volatile__(
-                       "1:     ll      %1, %2  # arch_read_unlock      \n"
-                       "       addiu   %1, -1                          \n"
-                       "       sc      %1, %0                          \n"
-                       : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp)
-                       : GCC_OFF_SMALL_ASM() (rw->lock)
-                       : "memory");
-               } while (unlikely(!tmp));
-       }
-}
-
-static inline void arch_write_lock(arch_rwlock_t *rw)
-{
-       unsigned int tmp;
-
-       if (R10000_LLSC_WAR) {
-               __asm__ __volatile__(
-               "       .set    noreorder       # arch_write_lock       \n"
-               "1:     ll      %1, %2                                  \n"
-               "       bnez    %1, 1b                                  \n"
-               "        lui    %1, 0x8000                              \n"
-               "       sc      %1, %0                                  \n"
-               "       beqzl   %1, 1b                                  \n"
-               "        nop                                            \n"
-               "       .set    reorder                                 \n"
-               : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp)
-               : GCC_OFF_SMALL_ASM() (rw->lock)
-               : "memory");
-       } else {
-               do {
-                       __asm__ __volatile__(
-                       "1:     ll      %1, %2  # arch_write_lock       \n"
-                       "       bnez    %1, 1b                          \n"
-                       "        lui    %1, 0x8000                      \n"
-                       "2:     sc      %1, %0                          \n"
-                       : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp)
-                       : GCC_OFF_SMALL_ASM() (rw->lock)
-                       : "memory");
-               } while (unlikely(!tmp));
-       }
-
-       smp_llsc_mb();
-}
-
-static inline void arch_write_unlock(arch_rwlock_t *rw)
-{
-       smp_mb__before_llsc();
-
-       __asm__ __volatile__(
-       "                               # arch_write_unlock     \n"
-       "       sw      $0, %0                                  \n"
-       : "=m" (rw->lock)
-       : "m" (rw->lock)
-       : "memory");
-}
-
-static inline int arch_read_trylock(arch_rwlock_t *rw)
-{
-       unsigned int tmp;
-       int ret;
-
-       if (R10000_LLSC_WAR) {
-               __asm__ __volatile__(
-               "       .set    noreorder       # arch_read_trylock     \n"
-               "       li      %2, 0                                   \n"
-               "1:     ll      %1, %3                                  \n"
-               "       bltz    %1, 2f                                  \n"
-               "        addu   %1, 1                                   \n"
-               "       sc      %1, %0                                  \n"
-               "       .set    reorder                                 \n"
-               "       beqzl   %1, 1b                                  \n"
-               "        nop                                            \n"
-               __WEAK_LLSC_MB
-               "       li      %2, 1                                   \n"
-               "2:                                                     \n"
-               : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret)
-               : GCC_OFF_SMALL_ASM() (rw->lock)
-               : "memory");
-       } else {
-               __asm__ __volatile__(
-               "       .set    noreorder       # arch_read_trylock     \n"
-               "       li      %2, 0                                   \n"
-               "1:     ll      %1, %3                                  \n"
-               "       bltz    %1, 2f                                  \n"
-               "        addu   %1, 1                                   \n"
-               "       sc      %1, %0                                  \n"
-               "       beqz    %1, 1b                                  \n"
-               "        nop                                            \n"
-               "       .set    reorder                                 \n"
-               __WEAK_LLSC_MB
-               "       li      %2, 1                                   \n"
-               "2:     .insn                                           \n"
-               : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret)
-               : GCC_OFF_SMALL_ASM() (rw->lock)
-               : "memory");
-       }
-
-       return ret;
-}
-
-static inline int arch_write_trylock(arch_rwlock_t *rw)
-{
-       unsigned int tmp;
-       int ret;
-
-       if (R10000_LLSC_WAR) {
-               __asm__ __volatile__(
-               "       .set    noreorder       # arch_write_trylock    \n"
-               "       li      %2, 0                                   \n"
-               "1:     ll      %1, %3                                  \n"
-               "       bnez    %1, 2f                                  \n"
-               "        lui    %1, 0x8000                              \n"
-               "       sc      %1, %0                                  \n"
-               "       beqzl   %1, 1b                                  \n"
-               "        nop                                            \n"
-               __WEAK_LLSC_MB
-               "       li      %2, 1                                   \n"
-               "       .set    reorder                                 \n"
-               "2:                                                     \n"
-               : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret)
-               : GCC_OFF_SMALL_ASM() (rw->lock)
-               : "memory");
-       } else {
-               do {
-                       __asm__ __volatile__(
-                       "       ll      %1, %3  # arch_write_trylock    \n"
-                       "       li      %2, 0                           \n"
-                       "       bnez    %1, 2f                          \n"
-                       "       lui     %1, 0x8000                      \n"
-                       "       sc      %1, %0                          \n"
-                       "       li      %2, 1                           \n"
-                       "2:     .insn                                   \n"
-                       : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp),
-                         "=&r" (ret)
-                       : GCC_OFF_SMALL_ASM() (rw->lock)
-                       : "memory");
-               } while (unlikely(!tmp));
-
-               smp_llsc_mb();
-       }
-
-       return ret;
-}
+#include <asm/qrwlock.h>
+#include <asm/qspinlock.h>
 
 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
 #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
index 9b2528e..177e722 100644 (file)
@@ -1,37 +1,7 @@
 #ifndef _ASM_SPINLOCK_TYPES_H
 #define _ASM_SPINLOCK_TYPES_H
 
-#ifndef __LINUX_SPINLOCK_TYPES_H
-# error "please don't include this file directly"
-#endif
-
-#include <linux/types.h>
-
-#include <asm/byteorder.h>
-
-typedef union {
-       /*
-        * bits  0..15 : serving_now
-        * bits 16..31 : ticket
-        */
-       u32 lock;
-       struct {
-#ifdef __BIG_ENDIAN
-               u16 ticket;
-               u16 serving_now;
-#else
-               u16 serving_now;
-               u16 ticket;
-#endif
-       } h;
-} arch_spinlock_t;
-
-#define __ARCH_SPIN_LOCK_UNLOCKED      { .lock = 0 }
-
-typedef struct {
-       volatile unsigned int lock;
-} arch_rwlock_t;
-
-#define __ARCH_RW_LOCK_UNLOCKED                { 0 }
+#include <asm-generic/qspinlock_types.h>
+#include <asm-generic/qrwlock_types.h>
 
 #endif
index d878825..7c71302 100644 (file)
@@ -85,7 +85,7 @@ static inline void syscall_set_return_value(struct task_struct *task,
 {
        if (error) {
                regs->regs[2] = -error;
-               regs->regs[7] = -1;
+               regs->regs[7] = 1;
        } else {
                regs->regs[2] = val;
                regs->regs[7] = 0;
index 9700251..b713069 100644 (file)
@@ -497,283 +497,6 @@ do {                                                                      \
 extern void __put_user_unknown(void);
 
 /*
- * ul{b,h,w} are macros and there are no equivalent macros for EVA.
- * EVA unaligned access is handled in the ADE exception handler.
- */
-#ifndef CONFIG_EVA
-/*
- * put_user_unaligned: - Write a simple value into user space.
- * @x:  Value to copy to user space.
- * @ptr: Destination address, in user space.
- *
- * Context: User context only. This function may sleep if pagefaults are
- *          enabled.
- *
- * This macro copies a single simple value from kernel space to user
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and @x must be assignable
- * to the result of dereferencing @ptr.
- *
- * Returns zero on success, or -EFAULT on error.
- */
-#define put_user_unaligned(x,ptr)      \
-       __put_user_unaligned_check((x),(ptr),sizeof(*(ptr)))
-
-/*
- * get_user_unaligned: - Get a simple variable from user space.
- * @x:  Variable to store result.
- * @ptr: Source address, in user space.
- *
- * Context: User context only. This function may sleep if pagefaults are
- *          enabled.
- *
- * This macro copies a single simple variable from user space to kernel
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and the result of
- * dereferencing @ptr must be assignable to @x without a cast.
- *
- * Returns zero on success, or -EFAULT on error.
- * On error, the variable @x is set to zero.
- */
-#define get_user_unaligned(x,ptr) \
-       __get_user_unaligned_check((x),(ptr),sizeof(*(ptr)))
-
-/*
- * __put_user_unaligned: - Write a simple value into user space, with less checking.
- * @x:  Value to copy to user space.
- * @ptr: Destination address, in user space.
- *
- * Context: User context only. This function may sleep if pagefaults are
- *          enabled.
- *
- * This macro copies a single simple value from kernel space to user
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and @x must be assignable
- * to the result of dereferencing @ptr.
- *
- * Caller must check the pointer with access_ok() before calling this
- * function.
- *
- * Returns zero on success, or -EFAULT on error.
- */
-#define __put_user_unaligned(x,ptr) \
-       __put_user_unaligned_nocheck((x),(ptr),sizeof(*(ptr)))
-
-/*
- * __get_user_unaligned: - Get a simple variable from user space, with less checking.
- * @x:  Variable to store result.
- * @ptr: Source address, in user space.
- *
- * Context: User context only. This function may sleep if pagefaults are
- *          enabled.
- *
- * This macro copies a single simple variable from user space to kernel
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and the result of
- * dereferencing @ptr must be assignable to @x without a cast.
- *
- * Caller must check the pointer with access_ok() before calling this
- * function.
- *
- * Returns zero on success, or -EFAULT on error.
- * On error, the variable @x is set to zero.
- */
-#define __get_user_unaligned(x,ptr) \
-       __get_user_unaligned_nocheck((x),(ptr),sizeof(*(ptr)))
-
-/*
- * Yuck.  We need two variants, one for 64bit operation and one
- * for 32 bit mode and old iron.
- */
-#ifdef CONFIG_32BIT
-#define __GET_USER_UNALIGNED_DW(val, ptr)                              \
-       __get_user_unaligned_asm_ll32(val, ptr)
-#endif
-#ifdef CONFIG_64BIT
-#define __GET_USER_UNALIGNED_DW(val, ptr)                              \
-       __get_user_unaligned_asm(val, "uld", ptr)
-#endif
-
-extern void __get_user_unaligned_unknown(void);
-
-#define __get_user_unaligned_common(val, size, ptr)                    \
-do {                                                                   \
-       switch (size) {                                                 \
-       case 1: __get_data_asm(val, "lb", ptr); break;                  \
-       case 2: __get_data_unaligned_asm(val, "ulh", ptr); break;       \
-       case 4: __get_data_unaligned_asm(val, "ulw", ptr); break;       \
-       case 8: __GET_USER_UNALIGNED_DW(val, ptr); break;               \
-       default: __get_user_unaligned_unknown(); break;                 \
-       }                                                               \
-} while (0)
-
-#define __get_user_unaligned_nocheck(x,ptr,size)                       \
-({                                                                     \
-       int __gu_err;                                                   \
-                                                                       \
-       __get_user_unaligned_common((x), size, ptr);                    \
-       __gu_err;                                                       \
-})
-
-#define __get_user_unaligned_check(x,ptr,size)                         \
-({                                                                     \
-       int __gu_err = -EFAULT;                                         \
-       const __typeof__(*(ptr)) __user * __gu_ptr = (ptr);             \
-                                                                       \
-       if (likely(access_ok(VERIFY_READ,  __gu_ptr, size)))            \
-               __get_user_unaligned_common((x), size, __gu_ptr);       \
-                                                                       \
-       __gu_err;                                                       \
-})
-
-#define __get_data_unaligned_asm(val, insn, addr)                      \
-{                                                                      \
-       long __gu_tmp;                                                  \
-                                                                       \
-       __asm__ __volatile__(                                           \
-       "1:     " insn "        %1, %3                          \n"     \
-       "2:                                                     \n"     \
-       "       .insn                                           \n"     \
-       "       .section .fixup,\"ax\"                          \n"     \
-       "3:     li      %0, %4                                  \n"     \
-       "       move    %1, $0                                  \n"     \
-       "       j       2b                                      \n"     \
-       "       .previous                                       \n"     \
-       "       .section __ex_table,\"a\"                       \n"     \
-       "       "__UA_ADDR "\t1b, 3b                            \n"     \
-       "       "__UA_ADDR "\t1b + 4, 3b                        \n"     \
-       "       .previous                                       \n"     \
-       : "=r" (__gu_err), "=r" (__gu_tmp)                              \
-       : "0" (0), "o" (__m(addr)), "i" (-EFAULT));                     \
-                                                                       \
-       (val) = (__typeof__(*(addr))) __gu_tmp;                         \
-}
-
-/*
- * Get a long long 64 using 32 bit registers.
- */
-#define __get_user_unaligned_asm_ll32(val, addr)                       \
-{                                                                      \
-       unsigned long long __gu_tmp;                                    \
-                                                                       \
-       __asm__ __volatile__(                                           \
-       "1:     ulw     %1, (%3)                                \n"     \
-       "2:     ulw     %D1, 4(%3)                              \n"     \
-       "       move    %0, $0                                  \n"     \
-       "3:                                                     \n"     \
-       "       .insn                                           \n"     \
-       "       .section        .fixup,\"ax\"                   \n"     \
-       "4:     li      %0, %4                                  \n"     \
-       "       move    %1, $0                                  \n"     \
-       "       move    %D1, $0                                 \n"     \
-       "       j       3b                                      \n"     \
-       "       .previous                                       \n"     \
-       "       .section        __ex_table,\"a\"                \n"     \
-       "       " __UA_ADDR "   1b, 4b                          \n"     \
-       "       " __UA_ADDR "   1b + 4, 4b                      \n"     \
-       "       " __UA_ADDR "   2b, 4b                          \n"     \
-       "       " __UA_ADDR "   2b + 4, 4b                      \n"     \
-       "       .previous                                       \n"     \
-       : "=r" (__gu_err), "=&r" (__gu_tmp)                             \
-       : "0" (0), "r" (addr), "i" (-EFAULT));                          \
-       (val) = (__typeof__(*(addr))) __gu_tmp;                         \
-}
-
-/*
- * Yuck.  We need two variants, one for 64bit operation and one
- * for 32 bit mode and old iron.
- */
-#ifdef CONFIG_32BIT
-#define __PUT_USER_UNALIGNED_DW(ptr) __put_user_unaligned_asm_ll32(ptr)
-#endif
-#ifdef CONFIG_64BIT
-#define __PUT_USER_UNALIGNED_DW(ptr) __put_user_unaligned_asm("usd", ptr)
-#endif
-
-#define __put_user_unaligned_common(ptr, size)                         \
-do {                                                                   \
-       switch (size) {                                                 \
-       case 1: __put_data_asm("sb", ptr); break;                       \
-       case 2: __put_user_unaligned_asm("ush", ptr); break;            \
-       case 4: __put_user_unaligned_asm("usw", ptr); break;            \
-       case 8: __PUT_USER_UNALIGNED_DW(ptr); break;                    \
-       default: __put_user_unaligned_unknown(); break;                 \
-} while (0)
-
-#define __put_user_unaligned_nocheck(x,ptr,size)                       \
-({                                                                     \
-       __typeof__(*(ptr)) __pu_val;                                    \
-       int __pu_err = 0;                                               \
-                                                                       \
-       __pu_val = (x);                                                 \
-       __put_user_unaligned_common(ptr, size);                         \
-       __pu_err;                                                       \
-})
-
-#define __put_user_unaligned_check(x,ptr,size)                         \
-({                                                                     \
-       __typeof__(*(ptr)) __user *__pu_addr = (ptr);                   \
-       __typeof__(*(ptr)) __pu_val = (x);                              \
-       int __pu_err = -EFAULT;                                         \
-                                                                       \
-       if (likely(access_ok(VERIFY_WRITE,  __pu_addr, size)))          \
-               __put_user_unaligned_common(__pu_addr, size);           \
-                                                                       \
-       __pu_err;                                                       \
-})
-
-#define __put_user_unaligned_asm(insn, ptr)                            \
-{                                                                      \
-       __asm__ __volatile__(                                           \
-       "1:     " insn "        %z2, %3         # __put_user_unaligned_asm\n" \
-       "2:                                                     \n"     \
-       "       .insn                                           \n"     \
-       "       .section        .fixup,\"ax\"                   \n"     \
-       "3:     li      %0, %4                                  \n"     \
-       "       j       2b                                      \n"     \
-       "       .previous                                       \n"     \
-       "       .section        __ex_table,\"a\"                \n"     \
-       "       " __UA_ADDR "   1b, 3b                          \n"     \
-       "       .previous                                       \n"     \
-       : "=r" (__pu_err)                                               \
-       : "0" (0), "Jr" (__pu_val), "o" (__m(ptr)),                     \
-         "i" (-EFAULT));                                               \
-}
-
-#define __put_user_unaligned_asm_ll32(ptr)                             \
-{                                                                      \
-       __asm__ __volatile__(                                           \
-       "1:     sw      %2, (%3)        # __put_user_unaligned_asm_ll32 \n" \
-       "2:     sw      %D2, 4(%3)                              \n"     \
-       "3:                                                     \n"     \
-       "       .insn                                           \n"     \
-       "       .section        .fixup,\"ax\"                   \n"     \
-       "4:     li      %0, %4                                  \n"     \
-       "       j       3b                                      \n"     \
-       "       .previous                                       \n"     \
-       "       .section        __ex_table,\"a\"                \n"     \
-       "       " __UA_ADDR "   1b, 4b                          \n"     \
-       "       " __UA_ADDR "   1b + 4, 4b                      \n"     \
-       "       " __UA_ADDR "   2b, 4b                          \n"     \
-       "       " __UA_ADDR "   2b + 4, 4b                      \n"     \
-       "       .previous"                                              \
-       : "=r" (__pu_err)                                               \
-       : "0" (0), "r" (__pu_val), "r" (ptr),                           \
-         "i" (-EFAULT));                                               \
-}
-
-extern void __put_user_unaligned_unknown(void);
-#endif
-
-/*
  * We're generating jump to subroutines which will be outside the range of
  * jump instructions
  */
index 3748f4d..59dae37 100644 (file)
@@ -72,9 +72,12 @@ Ip_u1u2s3(_beq);
 Ip_u1u2s3(_beql);
 Ip_u1s2(_bgez);
 Ip_u1s2(_bgezl);
+Ip_u1s2(_bgtz);
+Ip_u1s2(_blez);
 Ip_u1s2(_bltz);
 Ip_u1s2(_bltzl);
 Ip_u1u2s3(_bne);
+Ip_u1(_break);
 Ip_u2s3u1(_cache);
 Ip_u1u2(_cfc1);
 Ip_u2u1(_cfcmsa);
@@ -82,19 +85,28 @@ Ip_u1u2(_ctc1);
 Ip_u2u1(_ctcmsa);
 Ip_u2u1s3(_daddiu);
 Ip_u3u1u2(_daddu);
+Ip_u1u2(_ddivu);
 Ip_u1(_di);
 Ip_u2u1msbu3(_dins);
 Ip_u2u1msbu3(_dinsm);
+Ip_u2u1msbu3(_dinsu);
 Ip_u1u2(_divu);
 Ip_u1u2u3(_dmfc0);
 Ip_u1u2u3(_dmtc0);
+Ip_u1u2(_dmultu);
 Ip_u2u1u3(_drotr);
 Ip_u2u1u3(_drotr32);
+Ip_u2u1(_dsbh);
+Ip_u2u1(_dshd);
 Ip_u2u1u3(_dsll);
 Ip_u2u1u3(_dsll32);
+Ip_u3u2u1(_dsllv);
 Ip_u2u1u3(_dsra);
+Ip_u2u1u3(_dsra32);
+Ip_u3u2u1(_dsrav);
 Ip_u2u1u3(_dsrl);
 Ip_u2u1u3(_dsrl32);
+Ip_u3u2u1(_dsrlv);
 Ip_u3u1u2(_dsubu);
 Ip_0(_eret);
 Ip_u2u1msbu3(_ext);
@@ -104,6 +116,7 @@ Ip_u1(_jal);
 Ip_u2u1(_jalr);
 Ip_u1(_jr);
 Ip_u2s3u1(_lb);
+Ip_u2s3u1(_lbu);
 Ip_u2s3u1(_ld);
 Ip_u3u1u2(_ldx);
 Ip_u2s3u1(_lh);
@@ -112,27 +125,35 @@ Ip_u2s3u1(_ll);
 Ip_u2s3u1(_lld);
 Ip_u1s2(_lui);
 Ip_u2s3u1(_lw);
+Ip_u2s3u1(_lwu);
 Ip_u3u1u2(_lwx);
 Ip_u1u2u3(_mfc0);
 Ip_u1u2u3(_mfhc0);
 Ip_u1(_mfhi);
 Ip_u1(_mflo);
+Ip_u3u1u2(_movn);
+Ip_u3u1u2(_movz);
 Ip_u1u2u3(_mtc0);
 Ip_u1u2u3(_mthc0);
 Ip_u1(_mthi);
 Ip_u1(_mtlo);
 Ip_u3u1u2(_mul);
+Ip_u1u2(_multu);
+Ip_u3u1u2(_nor);
 Ip_u3u1u2(_or);
 Ip_u2u1u3(_ori);
 Ip_u2s3u1(_pref);
 Ip_0(_rfe);
 Ip_u2u1u3(_rotr);
+Ip_u2s3u1(_sb);
 Ip_u2s3u1(_sc);
 Ip_u2s3u1(_scd);
 Ip_u2s3u1(_sd);
+Ip_u2s3u1(_sh);
 Ip_u2u1u3(_sll);
 Ip_u3u2u1(_sllv);
 Ip_s3s1s2(_slt);
+Ip_u2u1s3(_slti);
 Ip_u2u1s3(_sltiu);
 Ip_u3u1u2(_sltu);
 Ip_u2u1u3(_sra);
@@ -248,6 +269,15 @@ static inline void uasm_i_dsrl_safe(u32 **p, unsigned int a1,
                uasm_i_dsrl32(p, a1, a2, a3 - 32);
 }
 
+static inline void uasm_i_dsra_safe(u32 **p, unsigned int a1,
+                                   unsigned int a2, unsigned int a3)
+{
+       if (a3 < 32)
+               uasm_i_dsra(p, a1, a2, a3);
+       else
+               uasm_i_dsra32(p, a1, a2, a3 - 32);
+}
+
 /* Handle relocations. */
 struct uasm_reloc {
        u32 *addr;
index 8f4ca5d..b7cd6cf 100644 (file)
@@ -79,8 +79,8 @@ union mips_vdso_data {
        struct {
                u64 xtime_sec;
                u64 xtime_nsec;
-               u32 wall_to_mono_sec;
-               u32 wall_to_mono_nsec;
+               u64 wall_to_mono_sec;
+               u64 wall_to_mono_nsec;
                u32 seq_count;
                u32 cs_shift;
                u8 clock_mode;
diff --git a/arch/mips/include/asm/yamon-dt.h b/arch/mips/include/asm/yamon-dt.h
new file mode 100644 (file)
index 0000000..485cfe3
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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 __MIPS_ASM_YAMON_DT_H__
+#define __MIPS_ASM_YAMON_DT_H__
+
+#include <linux/types.h>
+
+/**
+ * struct yamon_mem_region - Represents a contiguous range of physical RAM.
+ * @start:     Start physical address.
+ * @size:      Maximum size of region.
+ * @discard:   Length of additional memory to discard after the region.
+ */
+struct yamon_mem_region {
+       phys_addr_t     start;
+       phys_addr_t     size;
+       phys_addr_t     discard;
+};
+
+/**
+ * yamon_dt_append_cmdline() - Append YAMON-provided command line to /chosen
+ * @fdt: the FDT blob
+ *
+ * Write the YAMON-provided command line to the bootargs property of the
+ * /chosen node in @fdt.
+ *
+ * Return: 0 on success, else -errno
+ */
+extern __init int yamon_dt_append_cmdline(void *fdt);
+
+/**
+ * yamon_dt_append_memory() - Append YAMON-provided memory info to /memory
+ * @fdt:       the FDT blob
+ * @regions:   zero size terminated array of physical memory regions
+ *
+ * Generate a /memory node in @fdt based upon memory size information provided
+ * by YAMON in its environment and the @regions array.
+ *
+ * Return: 0 on success, else -errno
+ */
+extern __init int yamon_dt_append_memory(void *fdt,
+                                       const struct yamon_mem_region *regions);
+
+/**
+ * yamon_dt_serial_config() - Append YAMON-provided serial config to /chosen
+ * @fdt: the FDT blob
+ *
+ * Generate a stdout-path property in the /chosen node of @fdt, based upon
+ * information provided in the YAMON environment about the UART configuration
+ * of the system.
+ *
+ * Return: 0 on success, else -errno
+ */
+extern __init int yamon_dt_serial_config(void *fdt);
+
+#endif /* __MIPS_ASM_YAMON_DT_H__ */
index b5e46ae..d618975 100644 (file)
@@ -276,12 +276,19 @@ enum lx_func {
  */
 enum bshfl_func {
        wsbh_op = 0x2,
-       dshd_op = 0x5,
        seb_op  = 0x10,
        seh_op  = 0x18,
 };
 
 /*
+ * DBSHFL opcodes
+ */
+enum dbshfl_func {
+       dsbh_op = 0x2,
+       dshd_op = 0x5,
+};
+
+/*
  * MSA minor opcodes.
  */
 enum msa_func {
@@ -755,6 +762,16 @@ struct msa_mi10_format {           /* MSA MI10 */
        ;))))))
 };
 
+struct dsp_format {            /* SPEC3 DSP format instructions */
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int base : 5,
+       __BITFIELD_FIELD(unsigned int index : 5,
+       __BITFIELD_FIELD(unsigned int rd : 5,
+       __BITFIELD_FIELD(unsigned int op : 5,
+       __BITFIELD_FIELD(unsigned int func : 6,
+       ;))))))
+};
+
 struct spec3_format {   /* SPEC3 */
        __BITFIELD_FIELD(unsigned int opcode:6,
        __BITFIELD_FIELD(unsigned int rs:5,
@@ -1046,6 +1063,7 @@ union mips_instruction {
        struct b_format b_format;
        struct ps_format ps_format;
        struct v_format v_format;
+       struct dsp_format dsp_format;
        struct spec3_format spec3_format;
        struct fb_format fb_format;
        struct fp0_format fp0_format;
index 68e19b6..1609cb0 100644 (file)
@@ -91,7 +91,7 @@
 #define TIOCGPKT       _IOR('T', 0x38, int) /* Get packet mode state */
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
-#define TIOCGPTPEER    _IOR('T', 0x41, int) /* Safely open the slave */
+#define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
 
 /* I hope the range from 0x5480 on is free ... */
 #define TIOCSCTTY      0x5480          /* become controlling tty */
index 9a0e37b..46c0581 100644 (file)
@@ -4,7 +4,7 @@
 
 extra-y                := head.o vmlinux.lds
 
-obj-y          += cpu-probe.o branch.o elf.o entry.o genex.o idle.o irq.o \
+obj-y          += cmpxchg.o cpu-probe.o branch.o elf.o entry.o genex.o idle.o irq.o \
                   process.o prom.o ptrace.o reset.o setup.o signal.o \
                   syscall.o time.o topology.o traps.o unaligned.o watch.o \
                   vdso.o cacheinfo.o
@@ -31,7 +31,6 @@ obj-$(CONFIG_SYNC_R4K)                += sync-r4k.o
 obj-$(CONFIG_DEBUG_FS)         += segment.o
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-$(CONFIG_MODULES)          += module.o
-obj-$(CONFIG_MODULES_USE_ELF_RELA) += module-rela.o
 
 obj-$(CONFIG_FTRACE_SYSCALLS)  += ftrace.o
 obj-$(CONFIG_FUNCTION_TRACER)  += mcount.o ftrace.o
index f702a45..b79ed9a 100644 (file)
@@ -399,7 +399,7 @@ int __MIPS16e_compute_return_epc(struct pt_regs *regs)
  *
  * @regs:      Pointer to pt_regs
  * @insn:      branch instruction to decode
- * @returns:   -EFAULT on error and forces SIGBUS, and on success
+ * @returns:   -EFAULT on error and forces SIGILL, and on success
  *             returns 0 or BRANCH_LIKELY_TAKEN as appropriate after
  *             evaluating the branch.
  *
@@ -431,7 +431,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                        /* Fall through */
                case jr_op:
                        if (NO_R6EMU && insn.r_format.func == jr_op)
-                               goto sigill_r6;
+                               goto sigill_r2r6;
                        regs->cp0_epc = regs->regs[insn.r_format.rs];
                        break;
                }
@@ -446,7 +446,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                switch (insn.i_format.rt) {
                case bltzl_op:
                        if (NO_R6EMU)
-                               goto sigill_r6;
+                               goto sigill_r2r6;
                case bltz_op:
                        if ((long)regs->regs[insn.i_format.rs] < 0) {
                                epc = epc + 4 + (insn.i_format.simmediate << 2);
@@ -459,7 +459,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
 
                case bgezl_op:
                        if (NO_R6EMU)
-                               goto sigill_r6;
+                               goto sigill_r2r6;
                case bgez_op:
                        if ((long)regs->regs[insn.i_format.rs] >= 0) {
                                epc = epc + 4 + (insn.i_format.simmediate << 2);
@@ -473,10 +473,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                case bltzal_op:
                case bltzall_op:
                        if (NO_R6EMU && (insn.i_format.rs ||
-                           insn.i_format.rt == bltzall_op)) {
-                               ret = -SIGILL;
-                               break;
-                       }
+                           insn.i_format.rt == bltzall_op))
+                               goto sigill_r2r6;
                        regs->regs[31] = epc + 8;
                        /*
                         * OK we are here either because we hit a NAL
@@ -507,10 +505,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                case bgezal_op:
                case bgezall_op:
                        if (NO_R6EMU && (insn.i_format.rs ||
-                           insn.i_format.rt == bgezall_op)) {
-                               ret = -SIGILL;
-                               break;
-                       }
+                           insn.i_format.rt == bgezall_op))
+                               goto sigill_r2r6;
                        regs->regs[31] = epc + 8;
                        /*
                         * OK we are here either because we hit a BAL
@@ -556,6 +552,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
        /*
         * These are unconditional and in j_format.
         */
+       case jalx_op:
        case jal_op:
                regs->regs[31] = regs->cp0_epc + 8;
        case j_op:
@@ -573,7 +570,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
         */
        case beql_op:
                if (NO_R6EMU)
-                       goto sigill_r6;
+                       goto sigill_r2r6;
        case beq_op:
                if (regs->regs[insn.i_format.rs] ==
                    regs->regs[insn.i_format.rt]) {
@@ -587,7 +584,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
 
        case bnel_op:
                if (NO_R6EMU)
-                       goto sigill_r6;
+                       goto sigill_r2r6;
        case bne_op:
                if (regs->regs[insn.i_format.rs] !=
                    regs->regs[insn.i_format.rt]) {
@@ -601,7 +598,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
 
        case blezl_op: /* not really i_format */
                if (!insn.i_format.rt && NO_R6EMU)
-                       goto sigill_r6;
+                       goto sigill_r2r6;
        case blez_op:
                /*
                 * Compact branches for R6 for the
@@ -636,7 +633,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
 
        case bgtzl_op:
                if (!insn.i_format.rt && NO_R6EMU)
-                       goto sigill_r6;
+                       goto sigill_r2r6;
        case bgtz_op:
                /*
                 * Compact branches for R6 for the
@@ -774,35 +771,27 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
 #else
        case bc6_op:
                /* Only valid for MIPS R6 */
-               if (!cpu_has_mips_r6) {
-                       ret = -SIGILL;
-                       break;
-               }
+               if (!cpu_has_mips_r6)
+                       goto sigill_r6;
                regs->cp0_epc += 8;
                break;
        case balc6_op:
-               if (!cpu_has_mips_r6) {
-                       ret = -SIGILL;
-                       break;
-               }
+               if (!cpu_has_mips_r6)
+                       goto sigill_r6;
                /* Compact branch: BALC */
                regs->regs[31] = epc + 4;
                epc += 4 + (insn.i_format.simmediate << 2);
                regs->cp0_epc = epc;
                break;
        case pop66_op:
-               if (!cpu_has_mips_r6) {
-                       ret = -SIGILL;
-                       break;
-               }
+               if (!cpu_has_mips_r6)
+                       goto sigill_r6;
                /* Compact branch: BEQZC || JIC */
                regs->cp0_epc += 8;
                break;
        case pop76_op:
-               if (!cpu_has_mips_r6) {
-                       ret = -SIGILL;
-                       break;
-               }
+               if (!cpu_has_mips_r6)
+                       goto sigill_r6;
                /* Compact branch: BNEZC || JIALC */
                if (!insn.i_format.rs) {
                        /* JIALC: set $31/ra */
@@ -814,10 +803,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
        case pop10_op:
        case pop30_op:
                /* Only valid for MIPS R6 */
-               if (!cpu_has_mips_r6) {
-                       ret = -SIGILL;
-                       break;
-               }
+               if (!cpu_has_mips_r6)
+                       goto sigill_r6;
                /*
                 * Compact branches:
                 * bovc, beqc, beqzalc, bnvc, bnec, bnezlac
@@ -831,12 +818,18 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
        return ret;
 
 sigill_dsp:
-       printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
-       force_sig(SIGBUS, current);
+       pr_debug("%s: DSP branch but not DSP ASE - sending SIGILL.\n",
+                current->comm);
+       force_sig(SIGILL, current);
+       return -EFAULT;
+sigill_r2r6:
+       pr_debug("%s: R2 branch but r2-to-r6 emulator is not present - sending SIGILL.\n",
+                current->comm);
+       force_sig(SIGILL, current);
        return -EFAULT;
 sigill_r6:
-       pr_info("%s: R2 branch but r2-to-r6 emulator is not preset - sending SIGILL.\n",
-               current->comm);
+       pr_debug("%s: R6 branch but no MIPSr6 ISA support - sending SIGILL.\n",
+                current->comm);
        force_sig(SIGILL, current);
        return -EFAULT;
 }
diff --git a/arch/mips/kernel/cmpxchg.c b/arch/mips/kernel/cmpxchg.c
new file mode 100644 (file)
index 0000000..7730f1d
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2017 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <asm/cmpxchg.h>
+
+unsigned long __xchg_small(volatile void *ptr, unsigned long val, unsigned int size)
+{
+       u32 old32, new32, load32, mask;
+       volatile u32 *ptr32;
+       unsigned int shift;
+
+       /* Check that ptr is naturally aligned */
+       WARN_ON((unsigned long)ptr & (size - 1));
+
+       /* Mask value to the correct size. */
+       mask = GENMASK((size * BITS_PER_BYTE) - 1, 0);
+       val &= mask;
+
+       /*
+        * Calculate a shift & mask that correspond to the value we wish to
+        * exchange within the naturally aligned 4 byte integerthat includes
+        * it.
+        */
+       shift = (unsigned long)ptr & 0x3;
+       if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+               shift ^= sizeof(u32) - size;
+       shift *= BITS_PER_BYTE;
+       mask <<= shift;
+
+       /*
+        * Calculate a pointer to the naturally aligned 4 byte integer that
+        * includes our byte of interest, and load its value.
+        */
+       ptr32 = (volatile u32 *)((unsigned long)ptr & ~0x3);
+       load32 = *ptr32;
+
+       do {
+               old32 = load32;
+               new32 = (load32 & ~mask) | (val << shift);
+               load32 = cmpxchg(ptr32, old32, new32);
+       } while (load32 != old32);
+
+       return (load32 & mask) >> shift;
+}
+
+unsigned long __cmpxchg_small(volatile void *ptr, unsigned long old,
+                             unsigned long new, unsigned int size)
+{
+       u32 mask, old32, new32, load32;
+       volatile u32 *ptr32;
+       unsigned int shift;
+       u8 load;
+
+       /* Check that ptr is naturally aligned */
+       WARN_ON((unsigned long)ptr & (size - 1));
+
+       /* Mask inputs to the correct size. */
+       mask = GENMASK((size * BITS_PER_BYTE) - 1, 0);
+       old &= mask;
+       new &= mask;
+
+       /*
+        * Calculate a shift & mask that correspond to the value we wish to
+        * compare & exchange within the naturally aligned 4 byte integer
+        * that includes it.
+        */
+       shift = (unsigned long)ptr & 0x3;
+       if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+               shift ^= sizeof(u32) - size;
+       shift *= BITS_PER_BYTE;
+       mask <<= shift;
+
+       /*
+        * Calculate a pointer to the naturally aligned 4 byte integer that
+        * includes our byte of interest, and load its value.
+        */
+       ptr32 = (volatile u32 *)((unsigned long)ptr & ~0x3);
+       load32 = *ptr32;
+
+       while (true) {
+               /*
+                * Ensure the byte we want to exchange matches the expected
+                * old value, and if not then bail.
+                */
+               load = (load32 & mask) >> shift;
+               if (load != old)
+                       return load;
+
+               /*
+                * Calculate the old & new values of the naturally aligned
+                * 4 byte integer that include the byte we want to exchange.
+                * Attempt to exchange the old value for the new value, and
+                * return if we succeed.
+                */
+               old32 = (load32 & ~mask) | (old << shift);
+               new32 = (load32 & ~mask) | (new << shift);
+               load32 = cmpxchg(ptr32, old32, new32);
+               if (load32 == old32)
+                       return old;
+       }
+}
index a00e87b..b849fe6 100644 (file)
@@ -22,6 +22,7 @@
 #define GCR_CL_COHERENCE_OFS   0x2008
 #define GCR_CL_ID_OFS          0x2028
 
+#define CPC_CL_VC_STOP_OFS     0x2020
 #define CPC_CL_VC_RUN_OFS      0x2028
 
 .extern mips_cm_base
@@ -376,8 +377,12 @@ LEAF(mips_cps_boot_vpes)
        PTR_LI  t2, UNCAC_BASE
        PTR_ADD t1, t1, t2
 
-       /* Set VC_RUN to the VPE mask */
+       /* Start any other VPs that ought to be running */
        PTR_S   ta2, CPC_CL_VC_RUN_OFS(t1)
+
+       /* Ensure this VP stops running if it shouldn't be */
+       not     ta2
+       PTR_S   ta2, CPC_CL_VC_STOP_OFS(t1)
        ehb
 
 #elif defined(CONFIG_MIPS_MT)
index 1aba277..d08afc7 100644 (file)
@@ -564,6 +564,7 @@ static int set_ftlb_enable(struct cpuinfo_mips *c, enum ftlb_flags flags)
                back_to_back_c0_hazard();
                break;
        case CPU_I6400:
+       case CPU_I6500:
                /* There's no way to disable the FTLB */
                if (!(flags & FTLB_EN))
                        return 1;
@@ -844,6 +845,8 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c)
                c->options |= MIPS_CPU_MVH;
        if (cpu_has_mips_r6 && (config5 & MIPS_CONF5_VP))
                c->options |= MIPS_CPU_VP;
+       if (config5 & MIPS_CONF5_CA2)
+               c->ases |= MIPS_ASE_MIPS16E2;
 
        return config5 & MIPS_CONF_M;
 }
@@ -1635,6 +1638,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_I6400;
                __cpu_name[cpu] = "MIPS I6400";
                break;
+       case PRID_IMP_I6500:
+               c->cputype = CPU_I6500;
+               __cpu_name[cpu] = "MIPS I6500";
+               break;
        case PRID_IMP_M5150:
                c->cputype = CPU_M5150;
                __cpu_name[cpu] = "MIPS M5150";
@@ -1648,6 +1655,17 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
        decode_configs(c);
 
        spram_config();
+
+       switch (__get_cpu_type(c->cputype)) {
+       case CPU_I6500:
+               c->options |= MIPS_CPU_SHARED_FTLB_ENTRIES;
+               /* fall-through */
+       case CPU_I6400:
+               c->options |= MIPS_CPU_SHARED_FTLB_RAM;
+               /* fall-through */
+       default:
+               break;
+       }
 }
 
 static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
@@ -1831,6 +1849,12 @@ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu)
                        set_elf_platform(cpu, "loongson3a");
                        set_isa(c, MIPS_CPU_ISA_M64R2);
                        break;
+               case PRID_REV_LOONGSON3A_R3:
+                       c->cputype = CPU_LOONGSON3;
+                       __cpu_name[cpu] = "ICT Loongson-3";
+                       set_elf_platform(cpu, "loongson3a");
+                       set_isa(c, MIPS_CPU_ISA_M64R2);
+                       break;
                }
 
                decode_configs(c);
index 659e6d3..cb0c57f 100644 (file)
@@ -265,15 +265,34 @@ void mips_cm_lock_other(unsigned int core, unsigned int vp)
        u32 val;
 
        preempt_disable();
-       curr_core = current_cpu_data.core;
-       spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core),
-                         per_cpu(cm_core_lock_flags, curr_core));
 
        if (mips_cm_revision() >= CM_REV_CM3) {
                val = core << CM3_GCR_Cx_OTHER_CORE_SHF;
                val |= vp << CM3_GCR_Cx_OTHER_VP_SHF;
+
+               /*
+                * We need to disable interrupts in SMP systems in order to
+                * ensure that we don't interrupt the caller with code which
+                * may modify the redirect register. We do so here in a
+                * slightly obscure way by using a spin lock, since this has
+                * the neat property of also catching any nested uses of
+                * mips_cm_lock_other() leading to a deadlock or a nice warning
+                * with lockdep enabled.
+                */
+               spin_lock_irqsave(this_cpu_ptr(&cm_core_lock),
+                                 *this_cpu_ptr(&cm_core_lock_flags));
        } else {
-               BUG_ON(vp != 0);
+               WARN_ON(vp != 0);
+
+               /*
+                * We only have a GCR_CL_OTHER per core in systems with
+                * CM 2.5 & older, so have to ensure other VP(E)s don't
+                * race with us.
+                */
+               curr_core = current_cpu_data.core;
+               spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core),
+                                 per_cpu(cm_core_lock_flags, curr_core));
+
                val = core << CM_GCR_Cx_OTHER_CORENUM_SHF;
        }
 
@@ -288,10 +307,17 @@ void mips_cm_lock_other(unsigned int core, unsigned int vp)
 
 void mips_cm_unlock_other(void)
 {
-       unsigned curr_core = current_cpu_data.core;
+       unsigned int curr_core;
+
+       if (mips_cm_revision() < CM_REV_CM3) {
+               curr_core = current_cpu_data.core;
+               spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core),
+                                      per_cpu(cm_core_lock_flags, curr_core));
+       } else {
+               spin_unlock_irqrestore(this_cpu_ptr(&cm_core_lock),
+                                      *this_cpu_ptr(&cm_core_lock_flags));
+       }
 
-       spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core),
-                              per_cpu(cm_core_lock_flags, curr_core));
        preempt_enable();
 }
 
diff --git a/arch/mips/kernel/module-rela.c b/arch/mips/kernel/module-rela.c
deleted file mode 100644 (file)
index 7811688..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- *  Copyright (C) 2001 Rusty Russell.
- *  Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
- *  Copyright (C) 2005 Thiemo Seufer
- *  Copyright (C) 2015 Imagination Technologies Ltd.
- */
-
-#include <linux/elf.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/moduleloader.h>
-
-extern int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v);
-
-static int apply_r_mips_32_rela(struct module *me, u32 *location, Elf_Addr v)
-{
-       *location = v;
-
-       return 0;
-}
-
-static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v)
-{
-       if (v % 4) {
-               pr_err("module %s: dangerous R_MIPS_26 RELA relocation\n",
-                      me->name);
-               return -ENOEXEC;
-       }
-
-       if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
-               pr_err("module %s: relocation overflow\n", me->name);
-               return -ENOEXEC;
-       }
-
-       *location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff);
-
-       return 0;
-}
-
-static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v)
-{
-       *location = (*location & 0xffff0000) |
-                   ((((long long) v + 0x8000LL) >> 16) & 0xffff);
-
-       return 0;
-}
-
-static int apply_r_mips_lo16_rela(struct module *me, u32 *location, Elf_Addr v)
-{
-       *location = (*location & 0xffff0000) | (v & 0xffff);
-
-       return 0;
-}
-
-static int apply_r_mips_pc_rela(struct module *me, u32 *location, Elf_Addr v,
-                               unsigned bits)
-{
-       unsigned long mask = GENMASK(bits - 1, 0);
-       unsigned long se_bits;
-       long offset;
-
-       if (v % 4) {
-               pr_err("module %s: dangerous R_MIPS_PC%u RELA relocation\n",
-                      me->name, bits);
-               return -ENOEXEC;
-       }
-
-       offset = ((long)v - (long)location) >> 2;
-
-       /* check the sign bit onwards are identical - ie. we didn't overflow */
-       se_bits = (offset & BIT(bits - 1)) ? ~0ul : 0;
-       if ((offset & ~mask) != (se_bits & ~mask)) {
-               pr_err("module %s: relocation overflow\n", me->name);
-               return -ENOEXEC;
-       }
-
-       *location = (*location & ~mask) | (offset & mask);
-
-       return 0;
-}
-
-static int apply_r_mips_pc16_rela(struct module *me, u32 *location, Elf_Addr v)
-{
-       return apply_r_mips_pc_rela(me, location, v, 16);
-}
-
-static int apply_r_mips_pc21_rela(struct module *me, u32 *location, Elf_Addr v)
-{
-       return apply_r_mips_pc_rela(me, location, v, 21);
-}
-
-static int apply_r_mips_pc26_rela(struct module *me, u32 *location, Elf_Addr v)
-{
-       return apply_r_mips_pc_rela(me, location, v, 26);
-}
-
-static int apply_r_mips_64_rela(struct module *me, u32 *location, Elf_Addr v)
-{
-       *(Elf_Addr *)location = v;
-
-       return 0;
-}
-
-static int apply_r_mips_higher_rela(struct module *me, u32 *location,
-                                   Elf_Addr v)
-{
-       *location = (*location & 0xffff0000) |
-                   ((((long long) v + 0x80008000LL) >> 32) & 0xffff);
-
-       return 0;
-}
-
-static int apply_r_mips_highest_rela(struct module *me, u32 *location,
-                                    Elf_Addr v)
-{
-       *location = (*location & 0xffff0000) |
-                   ((((long long) v + 0x800080008000LL) >> 48) & 0xffff);
-
-       return 0;
-}
-
-static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
-                               Elf_Addr v) = {
-       [R_MIPS_NONE]           = apply_r_mips_none,
-       [R_MIPS_32]             = apply_r_mips_32_rela,
-       [R_MIPS_26]             = apply_r_mips_26_rela,
-       [R_MIPS_HI16]           = apply_r_mips_hi16_rela,
-       [R_MIPS_LO16]           = apply_r_mips_lo16_rela,
-       [R_MIPS_PC16]           = apply_r_mips_pc16_rela,
-       [R_MIPS_64]             = apply_r_mips_64_rela,
-       [R_MIPS_HIGHER]         = apply_r_mips_higher_rela,
-       [R_MIPS_HIGHEST]        = apply_r_mips_highest_rela,
-       [R_MIPS_PC21_S2]        = apply_r_mips_pc21_rela,
-       [R_MIPS_PC26_S2]        = apply_r_mips_pc26_rela,
-};
-
-int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
-                      unsigned int symindex, unsigned int relsec,
-                      struct module *me)
-{
-       Elf_Mips_Rela *rel = (void *) sechdrs[relsec].sh_addr;
-       int (*handler)(struct module *me, u32 *location, Elf_Addr v);
-       Elf_Sym *sym;
-       u32 *location;
-       unsigned int i, type;
-       Elf_Addr v;
-       int res;
-
-       pr_debug("Applying relocate section %u to %u\n", relsec,
-              sechdrs[relsec].sh_info);
-
-       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-               /* This is where to make the change */
-               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-                       + rel[i].r_offset;
-               /* This is the symbol it is referring to */
-               sym = (Elf_Sym *)sechdrs[symindex].sh_addr
-                       + ELF_MIPS_R_SYM(rel[i]);
-               if (sym->st_value >= -MAX_ERRNO) {
-                       /* Ignore unresolved weak symbol */
-                       if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
-                               continue;
-                       pr_warn("%s: Unknown symbol %s\n",
-                              me->name, strtab + sym->st_name);
-                       return -ENOENT;
-               }
-
-               type = ELF_MIPS_R_TYPE(rel[i]);
-
-               if (type < ARRAY_SIZE(reloc_handlers_rela))
-                       handler = reloc_handlers_rela[type];
-               else
-                       handler = NULL;
-
-               if (!handler) {
-                       pr_err("%s: Unknown relocation type %u\n",
-                              me->name, type);
-                       return -EINVAL;
-               }
-
-               v = sym->st_value + rel[i].r_addend;
-               res = handler(me, location, v);
-               if (res)
-                       return res;
-       }
-
-       return 0;
-}
index 50c020c..4916051 100644 (file)
@@ -53,22 +53,25 @@ void *module_alloc(unsigned long size)
 }
 #endif
 
-int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
+static int apply_r_mips_none(struct module *me, u32 *location,
+                            u32 base, Elf_Addr v, bool rela)
 {
        return 0;
 }
 
-static int apply_r_mips_32_rel(struct module *me, u32 *location, Elf_Addr v)
+static int apply_r_mips_32(struct module *me, u32 *location,
+                          u32 base, Elf_Addr v, bool rela)
 {
-       *location += v;
+       *location = base + v;
 
        return 0;
 }
 
-static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
+static int apply_r_mips_26(struct module *me, u32 *location,
+                          u32 base, Elf_Addr v, bool rela)
 {
        if (v % 4) {
-               pr_err("module %s: dangerous R_MIPS_26 REL relocation\n",
+               pr_err("module %s: dangerous R_MIPS_26 relocation\n",
                       me->name);
                return -ENOEXEC;
        }
@@ -80,15 +83,22 @@ static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
        }
 
        *location = (*location & ~0x03ffffff) |
-                   ((*location + (v >> 2)) & 0x03ffffff);
+                   ((base + (v >> 2)) & 0x03ffffff);
 
        return 0;
 }
 
-static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v)
+static int apply_r_mips_hi16(struct module *me, u32 *location,
+                            u32 base, Elf_Addr v, bool rela)
 {
        struct mips_hi16 *n;
 
+       if (rela) {
+               *location = (*location & 0xffff0000) |
+                           ((((long long) v + 0x8000LL) >> 16) & 0xffff);
+               return 0;
+       }
+
        /*
         * We cannot relocate this one now because we don't know the value of
         * the carry we need to add.  Save the information, and let LO16 do the
@@ -117,12 +127,18 @@ static void free_relocation_chain(struct mips_hi16 *l)
        }
 }
 
-static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
+static int apply_r_mips_lo16(struct module *me, u32 *location,
+                            u32 base, Elf_Addr v, bool rela)
 {
-       unsigned long insnlo = *location;
+       unsigned long insnlo = base;
        struct mips_hi16 *l;
        Elf_Addr val, vallo;
 
+       if (rela) {
+               *location = (*location & 0xffff0000) | (v & 0xffff);
+               return 0;
+       }
+
        /* Sign extend the addend we extract from the lo insn.  */
        vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
 
@@ -178,26 +194,26 @@ out_danger:
        free_relocation_chain(l);
        me->arch.r_mips_hi16_list = NULL;
 
-       pr_err("module %s: dangerous R_MIPS_LO16 REL relocation\n", me->name);
+       pr_err("module %s: dangerous R_MIPS_LO16 relocation\n", me->name);
 
        return -ENOEXEC;
 }
 
-static int apply_r_mips_pc_rel(struct module *me, u32 *location, Elf_Addr v,
-                              unsigned bits)
+static int apply_r_mips_pc(struct module *me, u32 *location, u32 base,
+                          Elf_Addr v, unsigned int bits)
 {
        unsigned long mask = GENMASK(bits - 1, 0);
        unsigned long se_bits;
        long offset;
 
        if (v % 4) {
-               pr_err("module %s: dangerous R_MIPS_PC%u REL relocation\n",
+               pr_err("module %s: dangerous R_MIPS_PC%u relocation\n",
                       me->name, bits);
                return -ENOEXEC;
        }
 
-       /* retrieve & sign extend implicit addend */
-       offset = *location & mask;
+       /* retrieve & sign extend implicit addend if any */
+       offset = base & mask;
        offset |= (offset & BIT(bits - 1)) ? ~mask : 0;
 
        offset += ((long)v - (long)location) >> 2;
@@ -214,99 +230,192 @@ static int apply_r_mips_pc_rel(struct module *me, u32 *location, Elf_Addr v,
        return 0;
 }
 
-static int apply_r_mips_pc16_rel(struct module *me, u32 *location, Elf_Addr v)
+static int apply_r_mips_pc16(struct module *me, u32 *location,
+                            u32 base, Elf_Addr v, bool rela)
+{
+       return apply_r_mips_pc(me, location, base, v, 16);
+}
+
+static int apply_r_mips_pc21(struct module *me, u32 *location,
+                            u32 base, Elf_Addr v, bool rela)
+{
+       return apply_r_mips_pc(me, location, base, v, 21);
+}
+
+static int apply_r_mips_pc26(struct module *me, u32 *location,
+                            u32 base, Elf_Addr v, bool rela)
+{
+       return apply_r_mips_pc(me, location, base, v, 26);
+}
+
+static int apply_r_mips_64(struct module *me, u32 *location,
+                          u32 base, Elf_Addr v, bool rela)
 {
-       return apply_r_mips_pc_rel(me, location, v, 16);
+       if (WARN_ON(!rela))
+               return -EINVAL;
+
+       *(Elf_Addr *)location = v;
+
+       return 0;
 }
 
-static int apply_r_mips_pc21_rel(struct module *me, u32 *location, Elf_Addr v)
+static int apply_r_mips_higher(struct module *me, u32 *location,
+                              u32 base, Elf_Addr v, bool rela)
 {
-       return apply_r_mips_pc_rel(me, location, v, 21);
+       if (WARN_ON(!rela))
+               return -EINVAL;
+
+       *location = (*location & 0xffff0000) |
+                   ((((long long)v + 0x80008000LL) >> 32) & 0xffff);
+
+       return 0;
 }
 
-static int apply_r_mips_pc26_rel(struct module *me, u32 *location, Elf_Addr v)
+static int apply_r_mips_highest(struct module *me, u32 *location,
+                               u32 base, Elf_Addr v, bool rela)
 {
-       return apply_r_mips_pc_rel(me, location, v, 26);
+       if (WARN_ON(!rela))
+               return -EINVAL;
+
+       *location = (*location & 0xffff0000) |
+                   ((((long long)v + 0x800080008000LL) >> 48) & 0xffff);
+
+       return 0;
 }
 
-static int (*reloc_handlers_rel[]) (struct module *me, u32 *location,
-                               Elf_Addr v) = {
+/**
+ * reloc_handler() - Apply a particular relocation to a module
+ * @me: the module to apply the reloc to
+ * @location: the address at which the reloc is to be applied
+ * @base: the existing value at location for REL-style; 0 for RELA-style
+ * @v: the value of the reloc, with addend for RELA-style
+ *
+ * Each implemented reloc_handler function applies a particular type of
+ * relocation to the module @me. Relocs that may be found in either REL or RELA
+ * variants can be handled by making use of the @base & @v parameters which are
+ * set to values which abstract the difference away from the particular reloc
+ * implementations.
+ *
+ * Return: 0 upon success, else -ERRNO
+ */
+typedef int (*reloc_handler)(struct module *me, u32 *location,
+                            u32 base, Elf_Addr v, bool rela);
+
+/* The handlers for known reloc types */
+static reloc_handler reloc_handlers[] = {
        [R_MIPS_NONE]           = apply_r_mips_none,
-       [R_MIPS_32]             = apply_r_mips_32_rel,
-       [R_MIPS_26]             = apply_r_mips_26_rel,
-       [R_MIPS_HI16]           = apply_r_mips_hi16_rel,
-       [R_MIPS_LO16]           = apply_r_mips_lo16_rel,
-       [R_MIPS_PC16]           = apply_r_mips_pc16_rel,
-       [R_MIPS_PC21_S2]        = apply_r_mips_pc21_rel,
-       [R_MIPS_PC26_S2]        = apply_r_mips_pc26_rel,
+       [R_MIPS_32]             = apply_r_mips_32,
+       [R_MIPS_26]             = apply_r_mips_26,
+       [R_MIPS_HI16]           = apply_r_mips_hi16,
+       [R_MIPS_LO16]           = apply_r_mips_lo16,
+       [R_MIPS_PC16]           = apply_r_mips_pc16,
+       [R_MIPS_64]             = apply_r_mips_64,
+       [R_MIPS_HIGHER]         = apply_r_mips_higher,
+       [R_MIPS_HIGHEST]        = apply_r_mips_highest,
+       [R_MIPS_PC21_S2]        = apply_r_mips_pc21,
+       [R_MIPS_PC26_S2]        = apply_r_mips_pc26,
 };
 
-int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
-                  unsigned int symindex, unsigned int relsec,
-                  struct module *me)
+static int __apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
+                           unsigned int symindex, unsigned int relsec,
+                           struct module *me, bool rela)
 {
-       Elf_Mips_Rel *rel = (void *) sechdrs[relsec].sh_addr;
-       int (*handler)(struct module *me, u32 *location, Elf_Addr v);
+       union {
+               Elf_Mips_Rel *rel;
+               Elf_Mips_Rela *rela;
+       } r;
+       reloc_handler handler;
        Elf_Sym *sym;
-       u32 *location;
+       u32 *location, base;
        unsigned int i, type;
        Elf_Addr v;
-       int res;
+       int err = 0;
+       size_t reloc_sz;
 
        pr_debug("Applying relocate section %u to %u\n", relsec,
               sechdrs[relsec].sh_info);
 
+       r.rel = (void *)sechdrs[relsec].sh_addr;
+       reloc_sz = rela ? sizeof(*r.rela) : sizeof(*r.rel);
        me->arch.r_mips_hi16_list = NULL;
-       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+       for (i = 0; i < sechdrs[relsec].sh_size / reloc_sz; i++) {
                /* This is where to make the change */
                location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-                       + rel[i].r_offset;
+                       + r.rel->r_offset;
                /* This is the symbol it is referring to */
                sym = (Elf_Sym *)sechdrs[symindex].sh_addr
-                       + ELF_MIPS_R_SYM(rel[i]);
+                       + ELF_MIPS_R_SYM(*r.rel);
                if (sym->st_value >= -MAX_ERRNO) {
                        /* Ignore unresolved weak symbol */
                        if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
                                continue;
                        pr_warn("%s: Unknown symbol %s\n",
                                me->name, strtab + sym->st_name);
-                       return -ENOENT;
+                       err = -ENOENT;
+                       goto out;
                }
 
-               type = ELF_MIPS_R_TYPE(rel[i]);
-
-               if (type < ARRAY_SIZE(reloc_handlers_rel))
-                       handler = reloc_handlers_rel[type];
+               type = ELF_MIPS_R_TYPE(*r.rel);
+               if (type < ARRAY_SIZE(reloc_handlers))
+                       handler = reloc_handlers[type];
                else
                        handler = NULL;
 
                if (!handler) {
                        pr_err("%s: Unknown relocation type %u\n",
                               me->name, type);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto out;
                }
 
-               v = sym->st_value;
-               res = handler(me, location, v);
-               if (res)
-                       return res;
+               if (rela) {
+                       v = sym->st_value + r.rela->r_addend;
+                       base = 0;
+                       r.rela = &r.rela[1];
+               } else {
+                       v = sym->st_value;
+                       base = *location;
+                       r.rel = &r.rel[1];
+               }
+
+               err = handler(me, location, base, v, rela);
+               if (err)
+                       goto out;
        }
 
+out:
        /*
-        * Normally the hi16 list should be deallocated at this point.  A
+        * Normally the hi16 list should be deallocated at this point. A
         * malformed binary however could contain a series of R_MIPS_HI16
-        * relocations not followed by a R_MIPS_LO16 relocation.  In that
-        * case, free up the list and return an error.
+        * relocations not followed by a R_MIPS_LO16 relocation, or if we hit
+        * an error processing a reloc we might have gotten here before
+        * reaching the R_MIPS_LO16. In either case, free up the list and
+        * return an error.
         */
        if (me->arch.r_mips_hi16_list) {
                free_relocation_chain(me->arch.r_mips_hi16_list);
                me->arch.r_mips_hi16_list = NULL;
-
-               return -ENOEXEC;
+               err = err ?: -ENOEXEC;
        }
 
-       return 0;
+       return err;
+}
+
+int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
+                  unsigned int symindex, unsigned int relsec,
+                  struct module *me)
+{
+       return __apply_relocate(sechdrs, strtab, symindex, relsec, me, false);
+}
+
+#ifdef CONFIG_MODULES_USE_ELF_RELA
+int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
+                      unsigned int symindex, unsigned int relsec,
+                      struct module *me)
+{
+       return __apply_relocate(sechdrs, strtab, symindex, relsec, me, true);
 }
+#endif /* CONFIG_MODULES_USE_ELF_RELA */
 
 /* Given an address, look for it in the module exception tables. */
 const struct exception_table_entry *search_module_dbetables(unsigned long addr)
index f3e301f..9e6c74b 100644 (file)
@@ -814,7 +814,7 @@ static const struct mips_perf_event mipsxxcore_event_map2
        [PERF_COUNT_HW_BRANCH_MISSES] = { 0x27, CNTR_ODD, T },
 };
 
-static const struct mips_perf_event i6400_event_map[PERF_COUNT_HW_MAX] = {
+static const struct mips_perf_event i6x00_event_map[PERF_COUNT_HW_MAX] = {
        [PERF_COUNT_HW_CPU_CYCLES]          = { 0x00, CNTR_EVEN | CNTR_ODD },
        [PERF_COUNT_HW_INSTRUCTIONS]        = { 0x01, CNTR_EVEN | CNTR_ODD },
        /* These only count dcache, not icache */
@@ -1014,7 +1014,7 @@ static const struct mips_perf_event mipsxxcore_cache_map2
 },
 };
 
-static const struct mips_perf_event i6400_cache_map
+static const struct mips_perf_event i6x00_cache_map
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
                                [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
@@ -1610,6 +1610,7 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
 #endif
                break;
        case CPU_I6400:
+       case CPU_I6500:
                /* 8-bit event numbers */
                base_id = config & 0xff;
                raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
@@ -1770,8 +1771,13 @@ init_hw_perf_events(void)
                break;
        case CPU_I6400:
                mipspmu.name = "mips/I6400";
-               mipspmu.general_event_map = &i6400_event_map;
-               mipspmu.cache_event_map = &i6400_cache_map;
+               mipspmu.general_event_map = &i6x00_event_map;
+               mipspmu.cache_event_map = &i6x00_cache_map;
+               break;
+       case CPU_I6500:
+               mipspmu.name = "mips/I6500";
+               mipspmu.general_event_map = &i6x00_event_map;
+               mipspmu.cache_event_map = &i6x00_cache_map;
                break;
        case CPU_1004K:
                mipspmu.name = "mips/1004K";
index 4eff2ae..70604c7 100644 (file)
@@ -83,7 +83,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        }
 
        seq_printf(m, "isa\t\t\t:"); 
-       if (cpu_has_mips_r1)
+       if (cpu_has_mips_1)
                seq_printf(m, " mips1");
        if (cpu_has_mips_2)
                seq_printf(m, "%s", " mips2");
@@ -109,6 +109,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
 
        seq_printf(m, "ASEs implemented\t:");
        if (cpu_has_mips16)     seq_printf(m, "%s", " mips16");
+       if (cpu_has_mips16e2)   seq_printf(m, "%s", " mips16e2");
        if (cpu_has_mdmx)       seq_printf(m, "%s", " mdmx");
        if (cpu_has_mips3d)     seq_printf(m, "%s", " mips3d");
        if (cpu_has_smartmips)  seq_printf(m, "%s", " smartmips");
index 6931fe7..6dd1364 100644 (file)
@@ -868,14 +868,39 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
            tracehook_report_syscall_entry(regs))
                return -1;
 
-       if (secure_computing(NULL) == -1)
-               return -1;
+#ifdef CONFIG_SECCOMP
+       if (unlikely(test_thread_flag(TIF_SECCOMP))) {
+               int ret, i;
+               struct seccomp_data sd;
+
+               sd.nr = syscall;
+               sd.arch = syscall_get_arch();
+               for (i = 0; i < 6; i++) {
+                       unsigned long v, r;
+
+                       r = mips_get_syscall_arg(&v, current, regs, i);
+                       sd.args[i] = r ? 0 : v;
+               }
+               sd.instruction_pointer = KSTK_EIP(current);
+
+               ret = __secure_computing(&sd);
+               if (ret == -1)
+                       return ret;
+       }
+#endif
 
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_enter(regs, regs->regs[2]);
 
        audit_syscall_entry(syscall, regs->regs[4], regs->regs[5],
                            regs->regs[6], regs->regs[7]);
+
+       /*
+        * Negative syscall numbers are mistaken for rejected syscalls, but
+        * won't have had the return value set appropriately, so we do so now.
+        */
+       if (syscall < 0)
+               syscall_set_return_value(current, regs, -ENOSYS, 0);
        return syscall;
 }
 
@@ -895,7 +920,7 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs)
        audit_syscall_exit(regs);
 
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
-               trace_sys_exit(regs, regs->regs[2]);
+               trace_sys_exit(regs, regs_return_value(regs));
 
        if (test_thread_flag(TIF_SYSCALL_TRACE))
                tracehook_report_syscall_exit(regs, 0);
index 80ed68b..27c2f90 100644 (file)
@@ -371,7 +371,7 @@ EXPORT(sys_call_table)
        PTR     sys_writev
        PTR     sys_cacheflush
        PTR     sys_cachectl
-       PTR     sys_sysmips
+       PTR     __sys_sysmips
        PTR     sys_ni_syscall                  /* 4150 */
        PTR     sys_getsid
        PTR     sys_fdatasync
index 49765b4..65d5aee 100644 (file)
@@ -311,7 +311,7 @@ EXPORT(sys_call_table)
        PTR     sys_sched_getaffinity
        PTR     sys_cacheflush
        PTR     sys_cachectl
-       PTR     sys_sysmips
+       PTR     __sys_sysmips
        PTR     sys_io_setup                    /* 5200 */
        PTR     sys_io_destroy
        PTR     sys_io_getevents
index 90bad2d..cbf190e 100644 (file)
@@ -302,7 +302,7 @@ EXPORT(sysn32_call_table)
        PTR     compat_sys_sched_getaffinity
        PTR     sys_cacheflush
        PTR     sys_cachectl
-       PTR     sys_sysmips
+       PTR     __sys_sysmips
        PTR     compat_sys_io_setup                     /* 6200 */
        PTR     sys_io_destroy
        PTR     compat_sys_io_getevents
index 2dd70bd..c30bc52 100644 (file)
@@ -371,7 +371,7 @@ EXPORT(sys32_call_table)
        PTR     compat_sys_writev
        PTR     sys_cacheflush
        PTR     sys_cachectl
-       PTR     sys_sysmips
+       PTR     __sys_sysmips
        PTR     sys_ni_syscall                  /* 4150 */
        PTR     sys_getsid
        PTR     sys_fdatasync
index 01d1dbd..fe39397 100644 (file)
@@ -670,6 +670,46 @@ static int __init early_parse_mem(char *p)
 }
 early_param("mem", early_parse_mem);
 
+static int __init early_parse_memmap(char *p)
+{
+       char *oldp;
+       u64 start_at, mem_size;
+
+       if (!p)
+               return -EINVAL;
+
+       if (!strncmp(p, "exactmap", 8)) {
+               pr_err("\"memmap=exactmap\" invalid on MIPS\n");
+               return 0;
+       }
+
+       oldp = p;
+       mem_size = memparse(p, &p);
+       if (p == oldp)
+               return -EINVAL;
+
+       if (*p == '@') {
+               start_at = memparse(p+1, &p);
+               add_memory_region(start_at, mem_size, BOOT_MEM_RAM);
+       } else if (*p == '#') {
+               pr_err("\"memmap=nn#ss\" (force ACPI data) invalid on MIPS\n");
+               return -EINVAL;
+       } else if (*p == '$') {
+               start_at = memparse(p+1, &p);
+               add_memory_region(start_at, mem_size, BOOT_MEM_RESERVED);
+       } else {
+               pr_err("\"memmap\" invalid format!\n");
+               return -EINVAL;
+       }
+
+       if (*p == '\0') {
+               usermem = 1;
+               return 0;
+       } else
+               return -EINVAL;
+}
+early_param("memmap", early_parse_memmap);
+
 #ifdef CONFIG_PROC_VMCORE
 unsigned long setup_elfcorehdr, setup_elfcorehdr_size;
 static int __init early_parse_elfcorehdr(char *p)
index 36954dd..f832e99 100644 (file)
@@ -142,9 +142,11 @@ static void __init cps_prepare_cpus(unsigned int max_cpus)
 
        /* Warn the user if the CCA prevents multi-core */
        ncores = mips_cm_numcores();
-       if (cca_unsuitable && ncores > 1) {
-               pr_warn("Using only one core due to unsuitable CCA 0x%x\n",
-                       cca);
+       if ((cca_unsuitable || cpu_has_dc_aliases) && ncores > 1) {
+               pr_warn("Using only one core due to %s%s%s\n",
+                       cca_unsuitable ? "unsuitable CCA" : "",
+                       (cca_unsuitable && cpu_has_dc_aliases) ? " & " : "",
+                       cpu_has_dc_aliases ? "dcache aliasing" : "");
 
                for_each_present_cpu(c) {
                        if (cpu_data[c].core)
@@ -488,6 +490,7 @@ static void cps_cpu_die(unsigned int cpu)
 {
        unsigned core = cpu_data[cpu].core;
        unsigned int vpe_id = cpu_vpe_id(&cpu_data[cpu]);
+       ktime_t fail_time;
        unsigned stat;
        int err;
 
@@ -514,6 +517,7 @@ static void cps_cpu_die(unsigned int cpu)
                 * state, the latter happening when a JTAG probe is connected
                 * in which case the CPC will refuse to power down the core.
                 */
+               fail_time = ktime_add_ms(ktime_get(), 2000);
                do {
                        mips_cm_lock_other(core, 0);
                        mips_cpc_lock_other(core);
@@ -521,9 +525,28 @@ static void cps_cpu_die(unsigned int cpu)
                        stat &= CPC_Cx_STAT_CONF_SEQSTATE_MSK;
                        mips_cpc_unlock_other();
                        mips_cm_unlock_other();
-               } while (stat != CPC_Cx_STAT_CONF_SEQSTATE_D0 &&
-                        stat != CPC_Cx_STAT_CONF_SEQSTATE_D2 &&
-                        stat != CPC_Cx_STAT_CONF_SEQSTATE_U2);
+
+                       if (stat == CPC_Cx_STAT_CONF_SEQSTATE_D0 ||
+                           stat == CPC_Cx_STAT_CONF_SEQSTATE_D2 ||
+                           stat == CPC_Cx_STAT_CONF_SEQSTATE_U2)
+                               break;
+
+                       /*
+                        * The core ought to have powered down, but didn't &
+                        * now we don't really know what state it's in. It's
+                        * likely that its _pwr_up pin has been wired to logic
+                        * 1 & it powered back up as soon as we powered it
+                        * down...
+                        *
+                        * The best we can do is warn the user & continue in
+                        * the hope that the core is doing nothing harmful &
+                        * might behave properly if we online it later.
+                        */
+                       if (WARN(ktime_after(ktime_get(), fail_time),
+                                "CPU%u hasn't powered down, seq. state %u\n",
+                                cpu, stat >> CPC_Cx_STAT_CONF_SEQSTATE_SHF))
+                               break;
+               } while (1);
 
                /* Indicate the core is powered off */
                bitmap_clear(core_power, core, 1);
index aba1afb..770d4d1 100644 (file)
@@ -335,6 +335,9 @@ int mips_smp_ipi_free(const struct cpumask *mask)
 
 static int __init mips_smp_ipi_init(void)
 {
+       if (num_possible_cpus() == 1)
+               return 0;
+
        mips_smp_ipi_allocate(cpu_possible_mask);
 
        call_desc = irq_to_desc(call_virq);
index 1dfa7f5..58c6f63 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/sched/task_stack.h>
 
 #include <asm/asm.h>
+#include <asm/asm-eva.h>
 #include <asm/branch.h>
 #include <asm/cachectl.h>
 #include <asm/cacheflush.h>
@@ -131,16 +132,14 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
                __asm__ __volatile__ (
                "       .set    "MIPS_ISA_ARCH_LEVEL"                   \n"
                "       li      %[err], 0                               \n"
-               "1:     ll      %[old], (%[addr])                       \n"
+               "1:                                                     \n"
+               user_ll("%[old]", "(%[addr])")
                "       move    %[tmp], %[new]                          \n"
-               "2:     sc      %[tmp], (%[addr])                       \n"
-               "       bnez    %[tmp], 4f                              \n"
+               "2:                                                     \n"
+               user_sc("%[tmp]", "(%[addr])")
+               "       beqz    %[tmp], 1b                              \n"
                "3:                                                     \n"
                "       .insn                                           \n"
-               "       .subsection 2                                   \n"
-               "4:     b       1b                                      \n"
-               "       .previous                                       \n"
-               "                                                       \n"
                "       .section .fixup,\"ax\"                          \n"
                "5:     li      %[err], %[efault]                       \n"
                "       j       3b                                      \n"
@@ -192,6 +191,12 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
        unreachable();
 }
 
+/*
+ * mips_atomic_set() normally returns directly via syscall_exit potentially
+ * clobbering static registers, so be sure to preserve them.
+ */
+save_static_function(sys_sysmips);
+
 SYSCALL_DEFINE3(sysmips, long, cmd, long, arg1, long, arg2)
 {
        switch (cmd) {
index f806ee5..5eaf257 100644 (file)
@@ -939,88 +939,114 @@ static void emulate_load_store_insn(struct pt_regs *regs,
                 * The remaining opcodes are the ones that are really of
                 * interest.
                 */
-#ifdef CONFIG_EVA
        case spec3_op:
-               /*
-                * we can land here only from kernel accessing user memory,
-                * so we need to "switch" the address limit to user space, so
-                * address check can work properly.
-                */
-               seg = get_fs();
-               set_fs(USER_DS);
-               switch (insn.spec3_format.func) {
-               case lhe_op:
-                       if (!access_ok(VERIFY_READ, addr, 2)) {
-                               set_fs(seg);
-                               goto sigbus;
-                       }
-                       LoadHWE(addr, value, res);
-                       if (res) {
-                               set_fs(seg);
-                               goto fault;
-                       }
-                       compute_return_epc(regs);
-                       regs->regs[insn.spec3_format.rt] = value;
-                       break;
-               case lwe_op:
-                       if (!access_ok(VERIFY_READ, addr, 4)) {
-                               set_fs(seg);
-                               goto sigbus;
+               if (insn.dsp_format.func == lx_op) {
+                       switch (insn.dsp_format.op) {
+                       case lwx_op:
+                               if (!access_ok(VERIFY_READ, addr, 4))
+                                       goto sigbus;
+                               LoadW(addr, value, res);
+                               if (res)
+                                       goto fault;
+                               compute_return_epc(regs);
+                               regs->regs[insn.dsp_format.rd] = value;
+                               break;
+                       case lhx_op:
+                               if (!access_ok(VERIFY_READ, addr, 2))
+                                       goto sigbus;
+                               LoadHW(addr, value, res);
+                               if (res)
+                                       goto fault;
+                               compute_return_epc(regs);
+                               regs->regs[insn.dsp_format.rd] = value;
+                               break;
+                       default:
+                               goto sigill;
                        }
+               }
+#ifdef CONFIG_EVA
+               else {
+                       /*
+                        * we can land here only from kernel accessing user
+                        * memory, so we need to "switch" the address limit to
+                        * user space, so that address check can work properly.
+                        */
+                       seg = get_fs();
+                       set_fs(USER_DS);
+                       switch (insn.spec3_format.func) {
+                       case lhe_op:
+                               if (!access_ok(VERIFY_READ, addr, 2)) {
+                                       set_fs(seg);
+                                       goto sigbus;
+                               }
+                               LoadHWE(addr, value, res);
+                               if (res) {
+                                       set_fs(seg);
+                                       goto fault;
+                               }
+                               compute_return_epc(regs);
+                               regs->regs[insn.spec3_format.rt] = value;
+                               break;
+                       case lwe_op:
+                               if (!access_ok(VERIFY_READ, addr, 4)) {
+                                       set_fs(seg);
+                                       goto sigbus;
+                               }
                                LoadWE(addr, value, res);
-                       if (res) {
-                               set_fs(seg);
-                               goto fault;
-                       }
-                       compute_return_epc(regs);
-                       regs->regs[insn.spec3_format.rt] = value;
-                       break;
-               case lhue_op:
-                       if (!access_ok(VERIFY_READ, addr, 2)) {
-                               set_fs(seg);
-                               goto sigbus;
-                       }
-                       LoadHWUE(addr, value, res);
-                       if (res) {
-                               set_fs(seg);
-                               goto fault;
-                       }
-                       compute_return_epc(regs);
-                       regs->regs[insn.spec3_format.rt] = value;
-                       break;
-               case she_op:
-                       if (!access_ok(VERIFY_WRITE, addr, 2)) {
-                               set_fs(seg);
-                               goto sigbus;
-                       }
-                       compute_return_epc(regs);
-                       value = regs->regs[insn.spec3_format.rt];
-                       StoreHWE(addr, value, res);
-                       if (res) {
-                               set_fs(seg);
-                               goto fault;
-                       }
-                       break;
-               case swe_op:
-                       if (!access_ok(VERIFY_WRITE, addr, 4)) {
-                               set_fs(seg);
-                               goto sigbus;
-                       }
-                       compute_return_epc(regs);
-                       value = regs->regs[insn.spec3_format.rt];
-                       StoreWE(addr, value, res);
-                       if (res) {
+                               if (res) {
+                                       set_fs(seg);
+                                       goto fault;
+                               }
+                               compute_return_epc(regs);
+                               regs->regs[insn.spec3_format.rt] = value;
+                               break;
+                       case lhue_op:
+                               if (!access_ok(VERIFY_READ, addr, 2)) {
+                                       set_fs(seg);
+                                       goto sigbus;
+                               }
+                               LoadHWUE(addr, value, res);
+                               if (res) {
+                                       set_fs(seg);
+                                       goto fault;
+                               }
+                               compute_return_epc(regs);
+                               regs->regs[insn.spec3_format.rt] = value;
+                               break;
+                       case she_op:
+                               if (!access_ok(VERIFY_WRITE, addr, 2)) {
+                                       set_fs(seg);
+                                       goto sigbus;
+                               }
+                               compute_return_epc(regs);
+                               value = regs->regs[insn.spec3_format.rt];
+                               StoreHWE(addr, value, res);
+                               if (res) {
+                                       set_fs(seg);
+                                       goto fault;
+                               }
+                               break;
+                       case swe_op:
+                               if (!access_ok(VERIFY_WRITE, addr, 4)) {
+                                       set_fs(seg);
+                                       goto sigbus;
+                               }
+                               compute_return_epc(regs);
+                               value = regs->regs[insn.spec3_format.rt];
+                               StoreWE(addr, value, res);
+                               if (res) {
+                                       set_fs(seg);
+                                       goto fault;
+                               }
+                               break;
+                       default:
                                set_fs(seg);
-                               goto fault;
+                               goto sigill;
                        }
-                       break;
-               default:
                        set_fs(seg);
-                       goto sigill;
                }
-               set_fs(seg);
-               break;
 #endif
+               break;
        case lh_op:
                if (!access_ok(VERIFY_READ, addr, 2))
                        goto sigbus;
@@ -1984,6 +2010,8 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
        u16 __user *pc16;
        unsigned long origpc;
        union mips16e_instruction mips16inst, oldinst;
+       unsigned int opcode;
+       int extended = 0;
 
        origpc = regs->cp0_epc;
        orig31 = regs->regs[31];
@@ -1996,6 +2024,7 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
 
        /* skip EXTEND instruction */
        if (mips16inst.ri.opcode == MIPS16e_extend_op) {
+               extended = 1;
                pc16++;
                __get_user(mips16inst.full, pc16);
        } else if (delay_slot(regs)) {
@@ -2008,7 +2037,8 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
                        goto sigbus;
        }
 
-       switch (mips16inst.ri.opcode) {
+       opcode = mips16inst.ri.opcode;
+       switch (opcode) {
        case MIPS16e_i64_op:    /* I64 or RI64 instruction */
                switch (mips16inst.i64.func) {  /* I64/RI64 func field check */
                case MIPS16e_ldpc_func:
@@ -2028,9 +2058,40 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
                goto sigbus;
 
        case MIPS16e_swsp_op:
+               reg = reg16to32[mips16inst.ri.rx];
+               if (extended && cpu_has_mips16e2)
+                       switch (mips16inst.ri.imm >> 5) {
+                       case 0:         /* SWSP */
+                       case 1:         /* SWGP */
+                               break;
+                       case 2:         /* SHGP */
+                               opcode = MIPS16e_sh_op;
+                               break;
+                       default:
+                               goto sigbus;
+                       }
+               break;
+
        case MIPS16e_lwpc_op:
+               reg = reg16to32[mips16inst.ri.rx];
+               break;
+
        case MIPS16e_lwsp_op:
                reg = reg16to32[mips16inst.ri.rx];
+               if (extended && cpu_has_mips16e2)
+                       switch (mips16inst.ri.imm >> 5) {
+                       case 0:         /* LWSP */
+                       case 1:         /* LWGP */
+                               break;
+                       case 2:         /* LHGP */
+                               opcode = MIPS16e_lh_op;
+                               break;
+                       case 4:         /* LHUGP */
+                               opcode = MIPS16e_lhu_op;
+                               break;
+                       default:
+                               goto sigbus;
+                       }
                break;
 
        case MIPS16e_i8_op:
@@ -2044,7 +2105,7 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
                break;
        }
 
-       switch (mips16inst.ri.opcode) {
+       switch (opcode) {
 
        case MIPS16e_lb_op:
        case MIPS16e_lbu_op:
index 3114a2e..03e3304 100644 (file)
@@ -28,6 +28,9 @@
 #ifdef CONFIG_MIPS_MALTA
 #undef CONFIG_CPU_HAS_PREFETCH
 #endif
+#ifdef CONFIG_CPU_MIPSR6
+#undef CONFIG_CPU_HAS_PREFETCH
+#endif
 
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
index 6afa218..1e8a955 100644 (file)
@@ -90,7 +90,9 @@ void __init prom_init_env(void)
 
        cpu_clock_freq = ecpu->cpu_clock_freq;
        loongson_sysconf.cputype = ecpu->cputype;
-       if (ecpu->cputype == Loongson_3A) {
+       switch (ecpu->cputype) {
+       case Legacy_3A:
+       case Loongson_3A:
                loongson_sysconf.cores_per_node = 4;
                loongson_sysconf.cores_per_package = 4;
                smp_group[0] = 0x900000003ff01000;
@@ -111,7 +113,9 @@ void __init prom_init_env(void)
                loongson_freqctrl[3] = 0x900030001fe001d0;
                loongson_sysconf.ht_control_base = 0x90000EFDFB000000;
                loongson_sysconf.workarounds = WORKAROUND_CPUFREQ;
-       } else if (ecpu->cputype == Loongson_3B) {
+               break;
+       case Legacy_3B:
+       case Loongson_3B:
                loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */
                loongson_sysconf.cores_per_package = 8;
                smp_group[0] = 0x900000003ff01000;
@@ -132,7 +136,8 @@ void __init prom_init_env(void)
                loongson_freqctrl[3] = 0x900060001fe001d0;
                loongson_sysconf.ht_control_base = 0x90001EFDFB000000;
                loongson_sysconf.workarounds = WORKAROUND_CPUHOTPLUG;
-       } else {
+               break;
+       default:
                loongson_sysconf.cores_per_node = 1;
                loongson_sysconf.cores_per_package = 1;
                loongson_chipcfg[0] = 0x900000001fe00180;
@@ -193,6 +198,7 @@ void __init prom_init_env(void)
                        break;
                case PRID_REV_LOONGSON3A_R1:
                case PRID_REV_LOONGSON3A_R2:
+               case PRID_REV_LOONGSON3A_R3:
                        cpu_clock_freq = 900000000;
                        break;
                case PRID_REV_LOONGSON3B_R1:
index 9b987fe..6ef1712 100644 (file)
 
 #include <linux/bootmem.h>
 #include <asm/bootinfo.h>
+#include <asm/traps.h>
 #include <asm/smp-ops.h>
+#include <asm/cacheflush.h>
 
 #include <loongson.h>
 
 /* Loongson CPU address windows config space base address */
 unsigned long __maybe_unused _loongson_addrwincfg_base;
 
+static void __init mips_nmi_setup(void)
+{
+       void *base;
+       extern char except_vec_nmi;
+
+       base = (void *)(CAC_BASE + 0x380);
+       memcpy(base, &except_vec_nmi, 0x80);
+       flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
+}
+
 void __init prom_init(void)
 {
 #ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
@@ -40,6 +52,7 @@ void __init prom_init(void)
        /*init the uart base address */
        prom_init_uart_base();
        register_smp_ops(&loongson3_smp_ops);
+       board_nmi_handler_setup = mips_nmi_setup;
 }
 
 void __init prom_free_prom_memory(void)
index 548f759..7202e52 100644 (file)
@@ -9,18 +9,69 @@
 
 #include "smp.h"
 
+extern void loongson3_send_irq_by_ipi(int cpu, int irqs);
+
+unsigned int irq_cpu[16] = {[0 ... 15] = -1};
 unsigned int ht_irq[] = {0, 1, 3, 4, 5, 6, 7, 8, 12, 14, 15};
+unsigned int local_irq = 1<<0 | 1<<1 | 1<<2 | 1<<7 | 1<<8 | 1<<12;
+
+int plat_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity,
+                         bool force)
+{
+       unsigned int cpu;
+       struct cpumask new_affinity;
+
+       /* I/O devices are connected on package-0 */
+       cpumask_copy(&new_affinity, affinity);
+       for_each_cpu(cpu, affinity)
+               if (cpu_data[cpu].package > 0)
+                       cpumask_clear_cpu(cpu, &new_affinity);
+
+       if (cpumask_empty(&new_affinity))
+               return -EINVAL;
+
+       cpumask_copy(d->common->affinity, &new_affinity);
+
+       return IRQ_SET_MASK_OK_NOCOPY;
+}
 
 static void ht_irqdispatch(void)
 {
        unsigned int i, irq;
+       struct irq_data *irqd;
+       struct cpumask affinity;
 
        irq = LOONGSON_HT1_INT_VECTOR(0);
        LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */
 
        for (i = 0; i < ARRAY_SIZE(ht_irq); i++) {
-               if (irq & (0x1 << ht_irq[i]))
+               if (!(irq & (0x1 << ht_irq[i])))
+                       continue;
+
+               /* handled by local core */
+               if (local_irq & (0x1 << ht_irq[i])) {
                        do_IRQ(ht_irq[i]);
+                       continue;
+               }
+
+               irqd = irq_get_irq_data(ht_irq[i]);
+               cpumask_and(&affinity, irqd->common->affinity, cpu_active_mask);
+               if (cpumask_empty(&affinity)) {
+                       do_IRQ(ht_irq[i]);
+                       continue;
+               }
+
+               irq_cpu[ht_irq[i]] = cpumask_next(irq_cpu[ht_irq[i]], &affinity);
+               if (irq_cpu[ht_irq[i]] >= nr_cpu_ids)
+                       irq_cpu[ht_irq[i]] = cpumask_first(&affinity);
+
+               if (irq_cpu[ht_irq[i]] == 0) {
+                       do_IRQ(ht_irq[i]);
+                       continue;
+               }
+
+               /* balanced by other cores */
+               loongson3_send_irq_by_ipi(irq_cpu[ht_irq[i]], (0x1 << ht_irq[i]));
        }
 }
 
@@ -120,11 +171,16 @@ void irq_router_init(void)
 
 void __init mach_init_irq(void)
 {
+       struct irq_chip *chip;
+
        clear_c0_status(ST0_IM | ST0_BEV);
 
        irq_router_init();
        mips_cpu_irq_init();
        init_i8259_irqs();
+       chip = irq_get_chip(I8259A_IRQ_BASE);
+       chip->irq_set_affinity = plat_set_irq_affinity;
+
        irq_set_chip_and_handler(LOONGSON_UART_IRQ,
                        &loongson_irq_chip, handle_level_irq);
 
index 64659fc..b7a355c 100644 (file)
@@ -254,13 +254,21 @@ loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
                loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu_logical_map(i)]);
 }
 
+#define IPI_IRQ_OFFSET 6
+
+void loongson3_send_irq_by_ipi(int cpu, int irqs)
+{
+       loongson3_ipi_write32(irqs << IPI_IRQ_OFFSET, ipi_set0_regs[cpu_logical_map(cpu)]);
+}
+
 void loongson3_ipi_interrupt(struct pt_regs *regs)
 {
        int i, cpu = smp_processor_id();
-       unsigned int action, c0count;
+       unsigned int action, c0count, irqs;
 
        /* Load the ipi register to figure out what we're supposed to do */
        action = loongson3_ipi_read32(ipi_status0_regs[cpu_logical_map(cpu)]);
+       irqs = action >> IPI_IRQ_OFFSET;
 
        /* Clear the ipi register to clear the interrupt */
        loongson3_ipi_write32((u32)action, ipi_clear0_regs[cpu_logical_map(cpu)]);
@@ -282,6 +290,14 @@ void loongson3_ipi_interrupt(struct pt_regs *regs)
                        core0_c0count[i] = c0count;
                __wbflush(); /* Let others see the result ASAP */
        }
+
+       if (irqs) {
+               int irq;
+               while ((irq = ffs(irqs))) {
+                       do_IRQ(irq-1);
+                       irqs &= ~(1<<(irq-1));
+               }
+       }
 }
 
 #define MAX_LOOPS 800
@@ -503,7 +519,7 @@ static void loongson3a_r1_play_dead(int *state_addr)
                : "a1");
 }
 
-static void loongson3a_r2_play_dead(int *state_addr)
+static void loongson3a_r2r3_play_dead(int *state_addr)
 {
        register int val;
        register long cpuid, core, node, count;
@@ -664,8 +680,9 @@ void play_dead(void)
                        (void *)CKSEG1ADDR((unsigned long)loongson3a_r1_play_dead);
                break;
        case PRID_REV_LOONGSON3A_R2:
+       case PRID_REV_LOONGSON3A_R3:
                play_dead_at_ckseg1 =
-                       (void *)CKSEG1ADDR((unsigned long)loongson3a_r2_play_dead);
+                       (void *)CKSEG1ADDR((unsigned long)loongson3a_r2r3_play_dead);
                break;
        case PRID_REV_LOONGSON3B_R1:
        case PRID_REV_LOONGSON3B_R2:
index f12fde1..f08a7b4 100644 (file)
@@ -1142,7 +1142,7 @@ emul:
 
                case mfhc_op:
                        if (!cpu_has_mips_r2_r6)
-                               goto sigill;
+                               return SIGILL;
 
                        /* copregister rd -> gpr[rt] */
                        if (MIPSInst_RT(ir) != 0) {
@@ -1153,7 +1153,7 @@ emul:
 
                case mthc_op:
                        if (!cpu_has_mips_r2_r6)
-                               goto sigill;
+                               return SIGILL;
 
                        /* copregister rd <- gpr[rt] */
                        SITOHREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
@@ -1376,7 +1376,6 @@ branch_common:
                                xcp->regs[MIPSInst_RS(ir)];
                break;
        default:
-sigill:
                return SIGILL;
        }
 
@@ -2524,6 +2523,35 @@ dcopuop:
        return 0;
 }
 
+/*
+ * Emulate FPU instructions.
+ *
+ * If we use FPU hardware, then we have been typically called to handle
+ * an unimplemented operation, such as where an operand is a NaN or
+ * denormalized.  In that case exit the emulation loop after a single
+ * iteration so as to let hardware execute any subsequent instructions.
+ *
+ * If we have no FPU hardware or it has been disabled, then continue
+ * emulating floating-point instructions until one of these conditions
+ * has occurred:
+ *
+ * - a non-FPU instruction has been encountered,
+ *
+ * - an attempt to emulate has ended with a signal,
+ *
+ * - the ISA mode has been switched.
+ *
+ * We need to terminate the emulation loop if we got switched to the
+ * MIPS16 mode, whether supported or not, so that we do not attempt
+ * to emulate a MIPS16 instruction as a regular MIPS FPU instruction.
+ * Similarly if we got switched to the microMIPS mode and only the
+ * regular MIPS mode is supported, so that we do not attempt to emulate
+ * a microMIPS instruction as a regular MIPS FPU instruction.  Or if
+ * we got switched to the regular MIPS mode and only the microMIPS mode
+ * is supported, so that we do not attempt to emulate a regular MIPS
+ * instruction that should cause an Address Error exception instead.
+ * For simplicity we always terminate upon an ISA mode switch.
+ */
 int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
        int has_fpu, void *__user *fault_addr)
 {
@@ -2609,6 +2637,15 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        break;
                if (sig)
                        break;
+               /*
+                * We have to check for the ISA bit explicitly here,
+                * because `get_isa16_mode' may return 0 if support
+                * for code compression has been globally disabled,
+                * or otherwise we may produce the wrong signal or
+                * even proceed successfully where we must not.
+                */
+               if ((xcp->cp0_epc ^ prevepc) & 0x1)
+                       break;
 
                cond_resched();
        } while (xcp->cp0_epc > prevepc);
index 3fe99cb..81d6a15 100644 (file)
@@ -1453,6 +1453,7 @@ static void probe_pcache(void)
        case CPU_20KC:
        case CPU_25KF:
        case CPU_I6400:
+       case CPU_I6500:
        case CPU_SB1:
        case CPU_SB1A:
        case CPU_XLR:
@@ -1512,6 +1513,7 @@ static void probe_pcache(void)
 
        case CPU_ALCHEMY:
        case CPU_I6400:
+       case CPU_I6500:
                c->icache.flags |= MIPS_CACHE_IC_F_DC;
                break;
 
index e08598c..8e78251 100644 (file)
@@ -232,7 +232,7 @@ static int mips_dma_mmap(struct device *dev, struct vm_area_struct *vma,
        else
                vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-       if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+       if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;
 
        if (off < count && user_count <= (count - off)) {
index ed1c529..5aadc69 100644 (file)
@@ -153,8 +153,7 @@ static int scratchpad_offset(int i)
  */
 static int m4kc_tlbp_war(void)
 {
-       return (current_cpu_data.processor_id & 0xffff00) ==
-              (PRID_COMP_MIPS | PRID_IMP_4KC);
+       return current_cpu_type() == CPU_4KC;
 }
 
 /* Handle labels (which must be positive integers). */
@@ -2015,6 +2014,26 @@ static void build_r3000_tlb_modify_handler(void)
 }
 #endif /* CONFIG_MIPS_PGD_C0_CONTEXT */
 
+static bool cpu_has_tlbex_tlbp_race(void)
+{
+       /*
+        * When a Hardware Table Walker is running it can replace TLB entries
+        * at any time, leading to a race between it & the CPU.
+        */
+       if (cpu_has_htw)
+               return true;
+
+       /*
+        * If the CPU shares FTLB RAM with its siblings then our entry may be
+        * replaced at any time by a sibling performing a write to the FTLB.
+        */
+       if (cpu_has_shared_ftlb_ram)
+               return true;
+
+       /* In all other cases there ought to be no race condition to handle */
+       return false;
+}
+
 /*
  * R4000 style TLB load/store/modify handlers.
  */
@@ -2051,7 +2070,7 @@ build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
        iPTE_LW(p, wr.r1, wr.r2); /* get even pte */
        if (!m4kc_tlbp_war()) {
                build_tlb_probe_entry(p);
-               if (cpu_has_htw) {
+               if (cpu_has_tlbex_tlbp_race()) {
                        /* race condition happens, leaving */
                        uasm_i_ehb(p);
                        uasm_i_mfc0(p, wr.r3, C0_INDEX);
@@ -2125,6 +2144,14 @@ static void build_r4000_tlb_load_handler(void)
                }
                uasm_i_nop(&p);
 
+               /*
+                * Warn if something may race with us & replace the TLB entry
+                * before we read it here. Everything with such races should
+                * also have dedicated RiXi exception handlers, so this
+                * shouldn't be hit.
+                */
+               WARN(cpu_has_tlbex_tlbp_race(), "Unhandled race in RiXi path");
+
                uasm_i_tlbr(&p);
 
                switch (current_cpu_type()) {
@@ -2192,6 +2219,14 @@ static void build_r4000_tlb_load_handler(void)
                }
                uasm_i_nop(&p);
 
+               /*
+                * Warn if something may race with us & replace the TLB entry
+                * before we read it here. Everything with such races should
+                * also have dedicated RiXi exception handlers, so this
+                * shouldn't be hit.
+                */
+               WARN(cpu_has_tlbex_tlbp_race(), "Unhandled race in RiXi path");
+
                uasm_i_tlbr(&p);
 
                switch (current_cpu_type()) {
index 277cf52..c28ff53 100644 (file)
 
 #include "uasm.c"
 
-static struct insn insn_table_MM[] = {
-       { insn_addu, M(mm_pool32a_op, 0, 0, 0, 0, mm_addu32_op), RT | RS | RD },
-       { insn_addiu, M(mm_addiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
-       { insn_and, M(mm_pool32a_op, 0, 0, 0, 0, mm_and_op), RT | RS | RD },
-       { insn_andi, M(mm_andi32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
-       { insn_beq, M(mm_beq32_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-       { insn_beql, 0, 0 },
-       { insn_bgez, M(mm_pool32i_op, mm_bgez_op, 0, 0, 0, 0), RS | BIMM },
-       { insn_bgezl, 0, 0 },
-       { insn_bltz, M(mm_pool32i_op, mm_bltz_op, 0, 0, 0, 0), RS | BIMM },
-       { insn_bltzl, 0, 0 },
-       { insn_bne, M(mm_bne32_op, 0, 0, 0, 0, 0), RT | RS | BIMM },
-       { insn_cache, M(mm_pool32b_op, 0, 0, mm_cache_func, 0, 0), RT | RS | SIMM },
-       { insn_cfc1, M(mm_pool32f_op, 0, 0, 0, mm_cfc1_op, mm_32f_73_op), RT | RS },
-       { insn_cfcmsa, M(mm_pool32s_op, 0, msa_cfc_op, 0, 0, mm_32s_elm_op), RD | RE },
-       { insn_ctc1, M(mm_pool32f_op, 0, 0, 0, mm_ctc1_op, mm_32f_73_op), RT | RS },
-       { insn_ctcmsa, M(mm_pool32s_op, 0, msa_ctc_op, 0, 0, mm_32s_elm_op), RD | RE },
-       { insn_daddu, 0, 0 },
-       { insn_daddiu, 0, 0 },
-       { insn_di, M(mm_pool32a_op, 0, 0, 0, mm_di_op, mm_pool32axf_op), RS },
-       { insn_divu, M(mm_pool32a_op, 0, 0, 0, mm_divu_op, mm_pool32axf_op), RT | RS },
-       { insn_dmfc0, 0, 0 },
-       { insn_dmtc0, 0, 0 },
-       { insn_dsll, 0, 0 },
-       { insn_dsll32, 0, 0 },
-       { insn_dsra, 0, 0 },
-       { insn_dsrl, 0, 0 },
-       { insn_dsrl32, 0, 0 },
-       { insn_drotr, 0, 0 },
-       { insn_drotr32, 0, 0 },
-       { insn_dsubu, 0, 0 },
-       { insn_eret, M(mm_pool32a_op, 0, 0, 0, mm_eret_op, mm_pool32axf_op), 0 },
-       { insn_ins, M(mm_pool32a_op, 0, 0, 0, 0, mm_ins_op), RT | RS | RD | RE },
-       { insn_ext, M(mm_pool32a_op, 0, 0, 0, 0, mm_ext_op), RT | RS | RD | RE },
-       { insn_j, M(mm_j32_op, 0, 0, 0, 0, 0), JIMM },
-       { insn_jal, M(mm_jal32_op, 0, 0, 0, 0, 0), JIMM },
-       { insn_jalr, M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RT | RS },
-       { insn_jr, M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RS },
-       { insn_lb, M(mm_lb32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
-       { insn_ld, 0, 0 },
-       { insn_lh, M(mm_lh32_op, 0, 0, 0, 0, 0), RS | RS | SIMM },
-       { insn_ll, M(mm_pool32c_op, 0, 0, (mm_ll_func << 1), 0, 0), RS | RT | SIMM },
-       { insn_lld, 0, 0 },
-       { insn_lui, M(mm_pool32i_op, mm_lui_op, 0, 0, 0, 0), RS | SIMM },
-       { insn_lw, M(mm_lw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
-       { insn_mfc0, M(mm_pool32a_op, 0, 0, 0, mm_mfc0_op, mm_pool32axf_op), RT | RS | RD },
-       { insn_mfhi, M(mm_pool32a_op, 0, 0, 0, mm_mfhi32_op, mm_pool32axf_op), RS },
-       { insn_mflo, M(mm_pool32a_op, 0, 0, 0, mm_mflo32_op, mm_pool32axf_op), RS },
-       { insn_mtc0, M(mm_pool32a_op, 0, 0, 0, mm_mtc0_op, mm_pool32axf_op), RT | RS | RD },
-       { insn_mthi, M(mm_pool32a_op, 0, 0, 0, mm_mthi32_op, mm_pool32axf_op), RS },
-       { insn_mtlo, M(mm_pool32a_op, 0, 0, 0, mm_mtlo32_op, mm_pool32axf_op), RS },
-       { insn_mul, M(mm_pool32a_op, 0, 0, 0, 0, mm_mul_op), RT | RS | RD },
-       { insn_or, M(mm_pool32a_op, 0, 0, 0, 0, mm_or32_op), RT | RS | RD },
-       { insn_ori, M(mm_ori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
-       { insn_pref, M(mm_pool32c_op, 0, 0, (mm_pref_func << 1), 0, 0), RT | RS | SIMM },
-       { insn_rfe, 0, 0 },
-       { insn_sc, M(mm_pool32c_op, 0, 0, (mm_sc_func << 1), 0, 0), RT | RS | SIMM },
-       { insn_scd, 0, 0 },
-       { insn_sd, 0, 0 },
-       { insn_sll, M(mm_pool32a_op, 0, 0, 0, 0, mm_sll32_op), RT | RS | RD },
-       { insn_sllv, M(mm_pool32a_op, 0, 0, 0, 0, mm_sllv32_op), RT | RS | RD },
-       { insn_slt, M(mm_pool32a_op, 0, 0, 0, 0, mm_slt_op), RT | RS | RD },
-       { insn_sltiu, M(mm_sltiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
-       { insn_sltu, M(mm_pool32a_op, 0, 0, 0, 0, mm_sltu_op), RT | RS | RD },
-       { insn_sra, M(mm_pool32a_op, 0, 0, 0, 0, mm_sra_op), RT | RS | RD },
-       { insn_srl, M(mm_pool32a_op, 0, 0, 0, 0, mm_srl32_op), RT | RS | RD },
-       { insn_srlv, M(mm_pool32a_op, 0, 0, 0, 0, mm_srlv32_op), RT | RS | RD },
-       { insn_rotr, M(mm_pool32a_op, 0, 0, 0, 0, mm_rotr_op), RT | RS | RD },
-       { insn_subu, M(mm_pool32a_op, 0, 0, 0, 0, mm_subu32_op), RT | RS | RD },
-       { insn_sw, M(mm_sw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
-       { insn_sync, M(mm_pool32a_op, 0, 0, 0, mm_sync_op, mm_pool32axf_op), RS },
-       { insn_tlbp, M(mm_pool32a_op, 0, 0, 0, mm_tlbp_op, mm_pool32axf_op), 0 },
-       { insn_tlbr, M(mm_pool32a_op, 0, 0, 0, mm_tlbr_op, mm_pool32axf_op), 0 },
-       { insn_tlbwi, M(mm_pool32a_op, 0, 0, 0, mm_tlbwi_op, mm_pool32axf_op), 0 },
-       { insn_tlbwr, M(mm_pool32a_op, 0, 0, 0, mm_tlbwr_op, mm_pool32axf_op), 0 },
-       { insn_wait, M(mm_pool32a_op, 0, 0, 0, mm_wait_op, mm_pool32axf_op), SCIMM },
-       { insn_wsbh, M(mm_pool32a_op, 0, 0, 0, mm_wsbh_op, mm_pool32axf_op), RT | RS },
-       { insn_xor, M(mm_pool32a_op, 0, 0, 0, 0, mm_xor32_op), RT | RS | RD },
-       { insn_xori, M(mm_xori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
-       { insn_dins, 0, 0 },
-       { insn_dinsm, 0, 0 },
-       { insn_syscall, M(mm_pool32a_op, 0, 0, 0, mm_syscall_op, mm_pool32axf_op), SCIMM},
-       { insn_bbit0, 0, 0 },
-       { insn_bbit1, 0, 0 },
-       { insn_lwx, 0, 0 },
-       { insn_ldx, 0, 0 },
-       { insn_invalid, 0, 0 }
+static const struct insn const insn_table_MM[insn_invalid] = {
+       [insn_addu]     = {M(mm_pool32a_op, 0, 0, 0, 0, mm_addu32_op), RT | RS | RD},
+       [insn_addiu]    = {M(mm_addiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM},
+       [insn_and]      = {M(mm_pool32a_op, 0, 0, 0, 0, mm_and_op), RT | RS | RD},
+       [insn_andi]     = {M(mm_andi32_op, 0, 0, 0, 0, 0), RT | RS | UIMM},
+       [insn_beq]      = {M(mm_beq32_op, 0, 0, 0, 0, 0), RS | RT | BIMM},
+       [insn_beql]     = {0, 0},
+       [insn_bgez]     = {M(mm_pool32i_op, mm_bgez_op, 0, 0, 0, 0), RS | BIMM},
+       [insn_bgezl]    = {0, 0},
+       [insn_bltz]     = {M(mm_pool32i_op, mm_bltz_op, 0, 0, 0, 0), RS | BIMM},
+       [insn_bltzl]    = {0, 0},
+       [insn_bne]      = {M(mm_bne32_op, 0, 0, 0, 0, 0), RT | RS | BIMM},
+       [insn_cache]    = {M(mm_pool32b_op, 0, 0, mm_cache_func, 0, 0), RT | RS | SIMM},
+       [insn_cfc1]     = {M(mm_pool32f_op, 0, 0, 0, mm_cfc1_op, mm_32f_73_op), RT | RS},
+       [insn_cfcmsa]   = {M(mm_pool32s_op, 0, msa_cfc_op, 0, 0, mm_32s_elm_op), RD | RE},
+       [insn_ctc1]     = {M(mm_pool32f_op, 0, 0, 0, mm_ctc1_op, mm_32f_73_op), RT | RS},
+       [insn_ctcmsa]   = {M(mm_pool32s_op, 0, msa_ctc_op, 0, 0, mm_32s_elm_op), RD | RE},
+       [insn_daddu]    = {0, 0},
+       [insn_daddiu]   = {0, 0},
+       [insn_di]       = {M(mm_pool32a_op, 0, 0, 0, mm_di_op, mm_pool32axf_op), RS},
+       [insn_divu]     = {M(mm_pool32a_op, 0, 0, 0, mm_divu_op, mm_pool32axf_op), RT | RS},
+       [insn_dmfc0]    = {0, 0},
+       [insn_dmtc0]    = {0, 0},
+       [insn_dsll]     = {0, 0},
+       [insn_dsll32]   = {0, 0},
+       [insn_dsra]     = {0, 0},
+       [insn_dsrl]     = {0, 0},
+       [insn_dsrl32]   = {0, 0},
+       [insn_drotr]    = {0, 0},
+       [insn_drotr32]  = {0, 0},
+       [insn_dsubu]    = {0, 0},
+       [insn_eret]     = {M(mm_pool32a_op, 0, 0, 0, mm_eret_op, mm_pool32axf_op), 0},
+       [insn_ins]      = {M(mm_pool32a_op, 0, 0, 0, 0, mm_ins_op), RT | RS | RD | RE},
+       [insn_ext]      = {M(mm_pool32a_op, 0, 0, 0, 0, mm_ext_op), RT | RS | RD | RE},
+       [insn_j]        = {M(mm_j32_op, 0, 0, 0, 0, 0), JIMM},
+       [insn_jal]      = {M(mm_jal32_op, 0, 0, 0, 0, 0), JIMM},
+       [insn_jalr]     = {M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RT | RS},
+       [insn_jr]       = {M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RS},
+       [insn_lb]       = {M(mm_lb32_op, 0, 0, 0, 0, 0), RT | RS | SIMM},
+       [insn_ld]       = {0, 0},
+       [insn_lh]       = {M(mm_lh32_op, 0, 0, 0, 0, 0), RS | RS | SIMM},
+       [insn_ll]       = {M(mm_pool32c_op, 0, 0, (mm_ll_func << 1), 0, 0), RS | RT | SIMM},
+       [insn_lld]      = {0, 0},
+       [insn_lui]      = {M(mm_pool32i_op, mm_lui_op, 0, 0, 0, 0), RS | SIMM},
+       [insn_lw]       = {M(mm_lw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM},
+       [insn_mfc0]     = {M(mm_pool32a_op, 0, 0, 0, mm_mfc0_op, mm_pool32axf_op), RT | RS | RD},
+       [insn_mfhi]     = {M(mm_pool32a_op, 0, 0, 0, mm_mfhi32_op, mm_pool32axf_op), RS},
+       [insn_mflo]     = {M(mm_pool32a_op, 0, 0, 0, mm_mflo32_op, mm_pool32axf_op), RS},
+       [insn_mtc0]     = {M(mm_pool32a_op, 0, 0, 0, mm_mtc0_op, mm_pool32axf_op), RT | RS | RD},
+       [insn_mthi]     = {M(mm_pool32a_op, 0, 0, 0, mm_mthi32_op, mm_pool32axf_op), RS},
+       [insn_mtlo]     = {M(mm_pool32a_op, 0, 0, 0, mm_mtlo32_op, mm_pool32axf_op), RS},
+       [insn_mul]      = {M(mm_pool32a_op, 0, 0, 0, 0, mm_mul_op), RT | RS | RD},
+       [insn_or]       = {M(mm_pool32a_op, 0, 0, 0, 0, mm_or32_op), RT | RS | RD},
+       [insn_ori]      = {M(mm_ori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM},
+       [insn_pref]     = {M(mm_pool32c_op, 0, 0, (mm_pref_func << 1), 0, 0), RT | RS | SIMM},
+       [insn_rfe]      = {0, 0},
+       [insn_sc]       = {M(mm_pool32c_op, 0, 0, (mm_sc_func << 1), 0, 0), RT | RS | SIMM},
+       [insn_scd]      = {0, 0},
+       [insn_sd]       = {0, 0},
+       [insn_sll]      = {M(mm_pool32a_op, 0, 0, 0, 0, mm_sll32_op), RT | RS | RD},
+       [insn_sllv]     = {M(mm_pool32a_op, 0, 0, 0, 0, mm_sllv32_op), RT | RS | RD},
+       [insn_slt]      = {M(mm_pool32a_op, 0, 0, 0, 0, mm_slt_op), RT | RS | RD},
+       [insn_sltiu]    = {M(mm_sltiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM},
+       [insn_sltu]     = {M(mm_pool32a_op, 0, 0, 0, 0, mm_sltu_op), RT | RS | RD},
+       [insn_sra]      = {M(mm_pool32a_op, 0, 0, 0, 0, mm_sra_op), RT | RS | RD},
+       [insn_srl]      = {M(mm_pool32a_op, 0, 0, 0, 0, mm_srl32_op), RT | RS | RD},
+       [insn_srlv]     = {M(mm_pool32a_op, 0, 0, 0, 0, mm_srlv32_op), RT | RS | RD},
+       [insn_rotr]     = {M(mm_pool32a_op, 0, 0, 0, 0, mm_rotr_op), RT | RS | RD},
+       [insn_subu]     = {M(mm_pool32a_op, 0, 0, 0, 0, mm_subu32_op), RT | RS | RD},
+       [insn_sw]       = {M(mm_sw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM},
+       [insn_sync]     = {M(mm_pool32a_op, 0, 0, 0, mm_sync_op, mm_pool32axf_op), RS},
+       [insn_tlbp]     = {M(mm_pool32a_op, 0, 0, 0, mm_tlbp_op, mm_pool32axf_op), 0},
+       [insn_tlbr]     = {M(mm_pool32a_op, 0, 0, 0, mm_tlbr_op, mm_pool32axf_op), 0},
+       [insn_tlbwi]    = {M(mm_pool32a_op, 0, 0, 0, mm_tlbwi_op, mm_pool32axf_op), 0},
+       [insn_tlbwr]    = {M(mm_pool32a_op, 0, 0, 0, mm_tlbwr_op, mm_pool32axf_op), 0},
+       [insn_wait]     = {M(mm_pool32a_op, 0, 0, 0, mm_wait_op, mm_pool32axf_op), SCIMM},
+       [insn_wsbh]     = {M(mm_pool32a_op, 0, 0, 0, mm_wsbh_op, mm_pool32axf_op), RT | RS},
+       [insn_xor]      = {M(mm_pool32a_op, 0, 0, 0, 0, mm_xor32_op), RT | RS | RD},
+       [insn_xori]     = {M(mm_xori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM},
+       [insn_dins]     = {0, 0},
+       [insn_dinsm]    = {0, 0},
+       [insn_syscall]  = {M(mm_pool32a_op, 0, 0, 0, mm_syscall_op, mm_pool32axf_op), SCIMM},
+       [insn_bbit0]    = {0, 0},
+       [insn_bbit1]    = {0, 0},
+       [insn_lwx]      = {0, 0},
+       [insn_ldx]      = {0, 0},
 };
 
 #undef M
@@ -156,20 +155,17 @@ static inline u32 build_jimm(u32 arg)
  */
 static void build_insn(u32 **buf, enum opcode opc, ...)
 {
-       struct insn *ip = NULL;
-       unsigned int i;
+       const struct insn *ip;
        va_list ap;
        u32 op;
 
-       for (i = 0; insn_table_MM[i].opcode != insn_invalid; i++)
-               if (insn_table_MM[i].opcode == opc) {
-                       ip = &insn_table_MM[i];
-                       break;
-               }
-
-       if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
+       if (opc < 0 || opc >= insn_invalid ||
+           (opc == insn_daddiu && r4k_daddiu_bug()) ||
+           (insn_table_MM[opc].match == 0 && insn_table_MM[opc].fields == 0))
                panic("Unsupported Micro-assembler instruction %d", opc);
 
+       ip = &insn_table_MM[opc];
+
        op = ip->match;
        va_start(ap, opc);
        if (ip->fields & RS) {
index 2277499..3f74f6c 100644 (file)
 
 #include "uasm.c"
 
-static struct insn insn_table[] = {
-       { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
-       { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
-       { insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
-       { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
-       { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-       { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-       { insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-       { insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-       { insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
-       { insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
-       { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
-       { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
-       { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+static const struct insn const insn_table[insn_invalid] = {
+       [insn_addiu]    = {M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
+       [insn_addu]     = {M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD},
+       [insn_and]      = {M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD},
+       [insn_andi]     = {M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM},
+       [insn_bbit0]    = {M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM},
+       [insn_bbit1]    = {M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM},
+       [insn_beq]      = {M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM},
+       [insn_beql]     = {M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM},
+       [insn_bgez]     = {M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM},
+       [insn_bgezl]    = {M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM},
+       [insn_bgtz]     = {M(bgtz_op, 0, 0, 0, 0, 0), RS | BIMM},
+       [insn_blez]     = {M(blez_op, 0, 0, 0, 0, 0), RS | BIMM},
+       [insn_bltz]     = {M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM},
+       [insn_bltzl]    = {M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM},
+       [insn_bne]      = {M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM},
+       [insn_break]    = {M(spec_op, 0, 0, 0, 0, break_op), SCIMM},
 #ifndef CONFIG_CPU_MIPSR6
-       { insn_cache,  M(cache_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       [insn_cache]    = {M(cache_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
 #else
-       { insn_cache,  M6(spec3_op, 0, 0, 0, cache6_op),  RS | RT | SIMM9 },
+       [insn_cache]    = {M6(spec3_op, 0, 0, 0, cache6_op),  RS | RT | SIMM9},
 #endif
-       { insn_cfc1, M(cop1_op, cfc_op, 0, 0, 0, 0), RT | RD },
-       { insn_cfcmsa, M(msa_op, 0, msa_cfc_op, 0, 0, msa_elm_op), RD | RE },
-       { insn_ctc1, M(cop1_op, ctc_op, 0, 0, 0, 0), RT | RD },
-       { insn_ctcmsa, M(msa_op, 0, msa_ctc_op, 0, 0, msa_elm_op), RD | RE },
-       { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
-       { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
-       { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
-       { insn_di, M(cop0_op, mfmc0_op, 0, 12, 0, 0), RT },
-       { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
-       { insn_divu, M(spec_op, 0, 0, 0, 0, divu_op), RS | RT },
-       { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
-       { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
-       { insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE },
-       { insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE },
-       { insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
-       { insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
-       { insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
-       { insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
-       { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
-       { insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
-       { insn_eret,  M(cop0_op, cop_op, 0, 0, 0, eret_op),  0 },
-       { insn_ext, M(spec3_op, 0, 0, 0, 0, ext_op), RS | RT | RD | RE },
-       { insn_ins, M(spec3_op, 0, 0, 0, 0, ins_op), RS | RT | RD | RE },
-       { insn_j,  M(j_op, 0, 0, 0, 0, 0),  JIMM },
-       { insn_jal,  M(jal_op, 0, 0, 0, 0, 0),  JIMM },
-       { insn_jalr,  M(spec_op, 0, 0, 0, 0, jalr_op), RS | RD },
-       { insn_j,  M(j_op, 0, 0, 0, 0, 0),  JIMM },
+       [insn_cfc1]     = {M(cop1_op, cfc_op, 0, 0, 0, 0), RT | RD},
+       [insn_cfcmsa]   = {M(msa_op, 0, msa_cfc_op, 0, 0, msa_elm_op), RD | RE},
+       [insn_ctc1]     = {M(cop1_op, ctc_op, 0, 0, 0, 0), RT | RD},
+       [insn_ctcmsa]   = {M(msa_op, 0, msa_ctc_op, 0, 0, msa_elm_op), RD | RE},
+       [insn_daddiu]   = {M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
+       [insn_daddu]    = {M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD},
+       [insn_ddivu]    = {M(spec_op, 0, 0, 0, 0, ddivu_op), RS | RT},
+       [insn_di]       = {M(cop0_op, mfmc0_op, 0, 12, 0, 0), RT},
+       [insn_dins]     = {M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE},
+       [insn_dinsm]    = {M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE},
+       [insn_dinsu]    = {M(spec3_op, 0, 0, 0, 0, dinsu_op), RS | RT | RD | RE},
+       [insn_divu]     = {M(spec_op, 0, 0, 0, 0, divu_op), RS | RT},
+       [insn_dmfc0]    = {M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
+       [insn_dmtc0]    = {M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
+       [insn_dmultu]   = {M(spec_op, 0, 0, 0, 0, dmultu_op), RS | RT},
+       [insn_drotr]    = {M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE},
+       [insn_drotr32]  = {M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE},
+       [insn_dsbh]     = {M(spec3_op, 0, 0, 0, dsbh_op, dbshfl_op), RT | RD},
+       [insn_dshd]     = {M(spec3_op, 0, 0, 0, dshd_op, dbshfl_op), RT | RD},
+       [insn_dsll]     = {M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE},
+       [insn_dsll32]   = {M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE},
+       [insn_dsllv]    = {M(spec_op, 0, 0, 0, 0, dsllv_op),  RS | RT | RD},
+       [insn_dsra]     = {M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE},
+       [insn_dsra32]   = {M(spec_op, 0, 0, 0, 0, dsra32_op), RT | RD | RE},
+       [insn_dsrav]    = {M(spec_op, 0, 0, 0, 0, dsrav_op),  RS | RT | RD},
+       [insn_dsrl]     = {M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE},
+       [insn_dsrl32]   = {M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE},
+       [insn_dsrlv]    = {M(spec_op, 0, 0, 0, 0, dsrlv_op),  RS | RT | RD},
+       [insn_dsubu]    = {M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD},
+       [insn_eret]     = {M(cop0_op, cop_op, 0, 0, 0, eret_op),  0},
+       [insn_ext]      = {M(spec3_op, 0, 0, 0, 0, ext_op), RS | RT | RD | RE},
+       [insn_ins]      = {M(spec3_op, 0, 0, 0, 0, ins_op), RS | RT | RD | RE},
+       [insn_j]        = {M(j_op, 0, 0, 0, 0, 0),  JIMM},
+       [insn_jal]      = {M(jal_op, 0, 0, 0, 0, 0),    JIMM},
+       [insn_jalr]     = {M(spec_op, 0, 0, 0, 0, jalr_op), RS | RD},
 #ifndef CONFIG_CPU_MIPSR6
-       { insn_jr,  M(spec_op, 0, 0, 0, 0, jr_op),  RS },
+       [insn_jr]       = {M(spec_op, 0, 0, 0, 0, jr_op),  RS},
 #else
-       { insn_jr,  M(spec_op, 0, 0, 0, 0, jalr_op),  RS },
+       [insn_jr]       = {M(spec_op, 0, 0, 0, 0, jalr_op),  RS},
 #endif
-       { insn_lb, M(lb_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
-       { insn_ld,  M(ld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD },
-       { insn_lh,  M(lh_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_lhu,  M(lhu_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       [insn_lb]       = {M(lb_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
+       [insn_lbu]      = {M(lbu_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
+       [insn_ld]       = {M(ld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
+       [insn_lddir]    = {M(lwc2_op, 0, 0, 0, lddir_op, mult_op), RS | RT | RD},
+       [insn_ldpte]    = {M(lwc2_op, 0, 0, 0, ldpte_op, mult_op), RS | RD},
+       [insn_ldx]      = {M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD},
+       [insn_lh]       = {M(lh_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
+       [insn_lhu]      = {M(lhu_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
 #ifndef CONFIG_CPU_MIPSR6
-       { insn_lld,  M(lld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_ll,  M(ll_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       [insn_ll]       = {M(ll_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
+       [insn_lld]      = {M(lld_op, 0, 0, 0, 0, 0),    RS | RT | SIMM},
 #else
-       { insn_lld,  M6(spec3_op, 0, 0, 0, lld6_op),  RS | RT | SIMM9 },
-       { insn_ll,  M6(spec3_op, 0, 0, 0, ll6_op),  RS | RT | SIMM9 },
+       [insn_ll]       = {M6(spec3_op, 0, 0, 0, ll6_op),  RS | RT | SIMM9},
+       [insn_lld]      = {M6(spec3_op, 0, 0, 0, lld6_op),  RS | RT | SIMM9},
 #endif
-       { insn_lui,  M(lui_op, 0, 0, 0, 0, 0),  RT | SIMM },
-       { insn_lw,  M(lw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD },
-       { insn_mfc0,  M(cop0_op, mfc_op, 0, 0, 0, 0),  RT | RD | SET},
-       { insn_mfhc0,  M(cop0_op, mfhc0_op, 0, 0, 0, 0),  RT | RD | SET},
-       { insn_mfhi,  M(spec_op, 0, 0, 0, 0, mfhi_op), RD },
-       { insn_mflo,  M(spec_op, 0, 0, 0, 0, mflo_op), RD },
-       { insn_mtc0,  M(cop0_op, mtc_op, 0, 0, 0, 0),  RT | RD | SET},
-       { insn_mthc0,  M(cop0_op, mthc0_op, 0, 0, 0, 0),  RT | RD | SET},
-       { insn_mthi,  M(spec_op, 0, 0, 0, 0, mthi_op), RS },
-       { insn_mtlo,  M(spec_op, 0, 0, 0, 0, mtlo_op), RS },
+       [insn_lui]      = {M(lui_op, 0, 0, 0, 0, 0),    RT | SIMM},
+       [insn_lw]       = {M(lw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
+       [insn_lwu]      = {M(lwu_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
+       [insn_lwx]      = {M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD},
+       [insn_mfc0]     = {M(cop0_op, mfc_op, 0, 0, 0, 0),  RT | RD | SET},
+       [insn_mfhc0]    = {M(cop0_op, mfhc0_op, 0, 0, 0, 0),  RT | RD | SET},
+       [insn_mfhi]     = {M(spec_op, 0, 0, 0, 0, mfhi_op), RD},
+       [insn_mflo]     = {M(spec_op, 0, 0, 0, 0, mflo_op), RD},
+       [insn_movn]     = {M(spec_op, 0, 0, 0, 0, movn_op), RS | RT | RD},
+       [insn_movz]     = {M(spec_op, 0, 0, 0, 0, movz_op), RS | RT | RD},
+       [insn_mtc0]     = {M(cop0_op, mtc_op, 0, 0, 0, 0),  RT | RD | SET},
+       [insn_mthc0]    = {M(cop0_op, mthc0_op, 0, 0, 0, 0),  RT | RD | SET},
+       [insn_mthi]     = {M(spec_op, 0, 0, 0, 0, mthi_op), RS},
+       [insn_mtlo]     = {M(spec_op, 0, 0, 0, 0, mtlo_op), RS},
 #ifndef CONFIG_CPU_MIPSR6
-       { insn_mul, M(spec2_op, 0, 0, 0, 0, mul_op), RS | RT | RD},
+       [insn_mul]      = {M(spec2_op, 0, 0, 0, 0, mul_op), RS | RT | RD},
 #else
-       { insn_mul, M(spec_op, 0, 0, 0, mult_mul_op, mult_op), RS | RT | RD},
+       [insn_mul]      = {M(spec_op, 0, 0, 0, mult_mul_op, mult_op), RS | RT | RD},
 #endif
-       { insn_ori,  M(ori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
-       { insn_or,  M(spec_op, 0, 0, 0, 0, or_op),  RS | RT | RD },
+       [insn_multu]    = {M(spec_op, 0, 0, 0, 0, multu_op), RS | RT},
+       [insn_nor]      = {M(spec_op, 0, 0, 0, 0, nor_op),  RS | RT | RD},
+       [insn_or]       = {M(spec_op, 0, 0, 0, 0, or_op),  RS | RT | RD},
+       [insn_ori]      = {M(ori_op, 0, 0, 0, 0, 0),    RS | RT | UIMM},
 #ifndef CONFIG_CPU_MIPSR6
-       { insn_pref,  M(pref_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       [insn_pref]     = {M(pref_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
 #else
-       { insn_pref,  M6(spec3_op, 0, 0, 0, pref6_op),  RS | RT | SIMM9 },
+       [insn_pref]     = {M6(spec3_op, 0, 0, 0, pref6_op),  RS | RT | SIMM9},
 #endif
-       { insn_rfe,  M(cop0_op, cop_op, 0, 0, 0, rfe_op),  0 },
-       { insn_rotr,  M(spec_op, 1, 0, 0, 0, srl_op),  RT | RD | RE },
+       [insn_rfe]      = {M(cop0_op, cop_op, 0, 0, 0, rfe_op),  0},
+       [insn_rotr]     = {M(spec_op, 1, 0, 0, 0, srl_op),  RT | RD | RE},
+       [insn_sb]       = {M(sb_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
 #ifndef CONFIG_CPU_MIPSR6
-       { insn_scd,  M(scd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_sc,  M(sc_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       [insn_sc]       = {M(sc_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
+       [insn_scd]      = {M(scd_op, 0, 0, 0, 0, 0),    RS | RT | SIMM},
 #else
-       { insn_scd,  M6(spec3_op, 0, 0, 0, scd6_op),  RS | RT | SIMM9 },
-       { insn_sc,  M6(spec3_op, 0, 0, 0, sc6_op),  RS | RT | SIMM9 },
+       [insn_sc]       = {M6(spec3_op, 0, 0, 0, sc6_op),  RS | RT | SIMM9},
+       [insn_scd]      = {M6(spec3_op, 0, 0, 0, scd6_op),  RS | RT | SIMM9},
 #endif
-       { insn_sd,  M(sd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_sll,  M(spec_op, 0, 0, 0, 0, sll_op),  RT | RD | RE },
-       { insn_sllv,  M(spec_op, 0, 0, 0, 0, sllv_op),  RS | RT | RD },
-       { insn_slt,  M(spec_op, 0, 0, 0, 0, slt_op),  RS | RT | RD },
-       { insn_sltiu, M(sltiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
-       { insn_sltu, M(spec_op, 0, 0, 0, 0, sltu_op), RS | RT | RD },
-       { insn_sra,  M(spec_op, 0, 0, 0, 0, sra_op),  RT | RD | RE },
-       { insn_srl,  M(spec_op, 0, 0, 0, 0, srl_op),  RT | RD | RE },
-       { insn_srlv,  M(spec_op, 0, 0, 0, 0, srlv_op),  RS | RT | RD },
-       { insn_subu,  M(spec_op, 0, 0, 0, 0, subu_op),  RS | RT | RD },
-       { insn_sw,  M(sw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_sync, M(spec_op, 0, 0, 0, 0, sync_op), RE },
-       { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
-       { insn_tlbp,  M(cop0_op, cop_op, 0, 0, 0, tlbp_op),  0 },
-       { insn_tlbr,  M(cop0_op, cop_op, 0, 0, 0, tlbr_op),  0 },
-       { insn_tlbwi,  M(cop0_op, cop_op, 0, 0, 0, tlbwi_op),  0 },
-       { insn_tlbwr,  M(cop0_op, cop_op, 0, 0, 0, tlbwr_op),  0 },
-       { insn_wait, M(cop0_op, cop_op, 0, 0, 0, wait_op), SCIMM },
-       { insn_wsbh, M(spec3_op, 0, 0, 0, wsbh_op, bshfl_op), RT | RD },
-       { insn_xori,  M(xori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
-       { insn_xor,  M(spec_op, 0, 0, 0, 0, xor_op),  RS | RT | RD },
-       { insn_yield, M(spec3_op, 0, 0, 0, 0, yield_op), RS | RD },
-       { insn_ldpte, M(lwc2_op, 0, 0, 0, ldpte_op, mult_op), RS | RD },
-       { insn_lddir, M(lwc2_op, 0, 0, 0, lddir_op, mult_op), RS | RT | RD },
-       { insn_invalid, 0, 0 }
+       [insn_sd]       = {M(sd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
+       [insn_sh]       = {M(sh_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
+       [insn_sll]      = {M(spec_op, 0, 0, 0, 0, sll_op),  RT | RD | RE},
+       [insn_sllv]     = {M(spec_op, 0, 0, 0, 0, sllv_op),  RS | RT | RD},
+       [insn_slt]      = {M(spec_op, 0, 0, 0, 0, slt_op),  RS | RT | RD},
+       [insn_slti]     = {M(slti_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
+       [insn_sltiu]    = {M(sltiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
+       [insn_sltu]     = {M(spec_op, 0, 0, 0, 0, sltu_op), RS | RT | RD},
+       [insn_sra]      = {M(spec_op, 0, 0, 0, 0, sra_op),  RT | RD | RE},
+       [insn_srl]      = {M(spec_op, 0, 0, 0, 0, srl_op),  RT | RD | RE},
+       [insn_srlv]     = {M(spec_op, 0, 0, 0, 0, srlv_op),  RS | RT | RD},
+       [insn_subu]     = {M(spec_op, 0, 0, 0, 0, subu_op),     RS | RT | RD},
+       [insn_sw]       = {M(sw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM},
+       [insn_sync]     = {M(spec_op, 0, 0, 0, 0, sync_op), RE},
+       [insn_syscall]  = {M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
+       [insn_tlbp]     = {M(cop0_op, cop_op, 0, 0, 0, tlbp_op),  0},
+       [insn_tlbr]     = {M(cop0_op, cop_op, 0, 0, 0, tlbr_op),  0},
+       [insn_tlbwi]    = {M(cop0_op, cop_op, 0, 0, 0, tlbwi_op),  0},
+       [insn_tlbwr]    = {M(cop0_op, cop_op, 0, 0, 0, tlbwr_op),  0},
+       [insn_wait]     = {M(cop0_op, cop_op, 0, 0, 0, wait_op), SCIMM},
+       [insn_wsbh]     = {M(spec3_op, 0, 0, 0, wsbh_op, bshfl_op), RT | RD},
+       [insn_xor]      = {M(spec_op, 0, 0, 0, 0, xor_op),  RS | RT | RD},
+       [insn_xori]     = {M(xori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM},
+       [insn_yield]    = {M(spec3_op, 0, 0, 0, 0, yield_op), RS | RD},
 };
 
 #undef M
@@ -196,20 +215,17 @@ static inline u32 build_jimm(u32 arg)
  */
 static void build_insn(u32 **buf, enum opcode opc, ...)
 {
-       struct insn *ip = NULL;
-       unsigned int i;
+       const struct insn *ip;
        va_list ap;
        u32 op;
 
-       for (i = 0; insn_table[i].opcode != insn_invalid; i++)
-               if (insn_table[i].opcode == opc) {
-                       ip = &insn_table[i];
-                       break;
-               }
-
-       if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
+       if (opc < 0 || opc >= insn_invalid ||
+           (opc == insn_daddiu && r4k_daddiu_bug()) ||
+           (insn_table[opc].match == 0 && insn_table[opc].fields == 0))
                panic("Unsupported Micro-assembler instruction %d", opc);
 
+       ip = &insn_table[opc];
+
        op = ip->match;
        va_start(ap, opc);
        if (ip->fields & RS)
index 730363b..57570c0 100644 (file)
@@ -46,26 +46,29 @@ enum fields {
 #define SIMM9_MASK     0x1ff
 
 enum opcode {
-       insn_invalid,
        insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1,
-       insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
-       insn_bne, insn_cache, insn_cfc1, insn_cfcmsa, insn_ctc1, insn_ctcmsa,
-       insn_daddiu, insn_daddu, insn_di, insn_dins, insn_dinsm, insn_divu,
-       insn_dmfc0, insn_dmtc0, insn_drotr, insn_drotr32, insn_dsll,
-       insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, insn_dsubu, insn_eret,
-       insn_ext, insn_ins, insn_j, insn_jal, insn_jalr, insn_jr, insn_lb,
-       insn_ld, insn_ldx, insn_lh, insn_ll, insn_lld, insn_lui, insn_lw,
-       insn_lwx, insn_mfc0, insn_mfhc0, insn_mfhi, insn_mflo, insn_mtc0,
-       insn_mthc0, insn_mthi, insn_mtlo, insn_mul, insn_or, insn_ori,
-       insn_pref, insn_rfe, insn_rotr, insn_sc, insn_scd, insn_sd, insn_sll,
-       insn_sllv, insn_slt, insn_sltiu, insn_sltu, insn_sra, insn_srl,
+       insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bgtz, insn_blez,
+       insn_bltz, insn_bltzl, insn_bne, insn_break, insn_cache, insn_cfc1,
+       insn_cfcmsa, insn_ctc1, insn_ctcmsa, insn_daddiu, insn_daddu, insn_ddivu,
+       insn_di, insn_dins, insn_dinsm, insn_dinsu, insn_divu, insn_dmfc0,
+       insn_dmtc0, insn_dmultu, insn_drotr, insn_drotr32, insn_dsbh, insn_dshd,
+       insn_dsll, insn_dsll32, insn_dsllv, insn_dsra, insn_dsra32, insn_dsrav,
+       insn_dsrl, insn_dsrl32, insn_dsrlv, insn_dsubu, insn_eret, insn_ext,
+       insn_ins, insn_j, insn_jal, insn_jalr, insn_jr, insn_lb, insn_lbu,
+       insn_ld, insn_lddir, insn_ldpte, insn_ldx, insn_lh, insn_lhu,
+       insn_ll, insn_lld, insn_lui, insn_lw, insn_lwu, insn_lwx, insn_mfc0,
+       insn_mfhc0, insn_mfhi, insn_mflo, insn_movn, insn_movz, insn_mtc0,
+       insn_mthc0, insn_mthi, insn_mtlo, insn_mul, insn_multu, insn_nor,
+       insn_or, insn_ori, insn_pref, insn_rfe, insn_rotr, insn_sb,
+       insn_sc, insn_scd, insn_sd, insn_sh, insn_sll, insn_sllv,
+       insn_slt, insn_slti, insn_sltiu, insn_sltu, insn_sra, insn_srl,
        insn_srlv, insn_subu, insn_sw, insn_sync, insn_syscall, insn_tlbp,
        insn_tlbr, insn_tlbwi, insn_tlbwr, insn_wait, insn_wsbh, insn_xor,
-       insn_xori, insn_yield, insn_lddir, insn_ldpte, insn_lhu,
+       insn_xori, insn_yield,
+       insn_invalid /* insn_invalid must be last */
 };
 
 struct insn {
-       enum opcode opcode;
        u32 match;
        enum fields fields;
 };
@@ -215,6 +218,13 @@ Ip_u2u1msbu3(op)                                   \
 }                                                      \
 UASM_EXPORT_SYMBOL(uasm_i##op);
 
+#define I_u2u1msb32msb3(op)                            \
+Ip_u2u1msbu3(op)                                       \
+{                                                      \
+       build_insn(buf, insn##op, b, a, c+d-33, c-32);  \
+}                                                      \
+UASM_EXPORT_SYMBOL(uasm_i##op);
+
 #define I_u2u1msbdu3(op)                               \
 Ip_u2u1msbu3(op)                                       \
 {                                                      \
@@ -265,25 +275,36 @@ I_u1u2s3(_beq)
 I_u1u2s3(_beql)
 I_u1s2(_bgez)
 I_u1s2(_bgezl)
+I_u1s2(_bgtz)
+I_u1s2(_blez)
 I_u1s2(_bltz)
 I_u1s2(_bltzl)
 I_u1u2s3(_bne)
+I_u1(_break)
 I_u2s3u1(_cache)
 I_u1u2(_cfc1)
 I_u2u1(_cfcmsa)
 I_u1u2(_ctc1)
 I_u2u1(_ctcmsa)
+I_u1u2(_ddivu)
 I_u1u2u3(_dmfc0)
 I_u1u2u3(_dmtc0)
+I_u1u2(_dmultu)
 I_u2u1s3(_daddiu)
 I_u3u1u2(_daddu)
 I_u1(_di);
 I_u1u2(_divu)
+I_u2u1(_dsbh);
+I_u2u1(_dshd);
 I_u2u1u3(_dsll)
 I_u2u1u3(_dsll32)
+I_u3u2u1(_dsllv)
 I_u2u1u3(_dsra)
+I_u2u1u3(_dsra32)
+I_u3u2u1(_dsrav)
 I_u2u1u3(_dsrl)
 I_u2u1u3(_dsrl32)
+I_u3u2u1(_dsrlv)
 I_u2u1u3(_drotr)
 I_u2u1u3(_drotr32)
 I_u3u1u2(_dsubu)
@@ -295,6 +316,7 @@ I_u1(_jal)
 I_u2u1(_jalr)
 I_u1(_jr)
 I_u2s3u1(_lb)
+I_u2s3u1(_lbu)
 I_u2s3u1(_ld)
 I_u2s3u1(_lh)
 I_u2s3u1(_lhu)
@@ -302,8 +324,11 @@ I_u2s3u1(_ll)
 I_u2s3u1(_lld)
 I_u1s2(_lui)
 I_u2s3u1(_lw)
+I_u2s3u1(_lwu)
 I_u1u2u3(_mfc0)
 I_u1u2u3(_mfhc0)
+I_u3u1u2(_movn)
+I_u3u1u2(_movz)
 I_u1(_mfhi)
 I_u1(_mflo)
 I_u1u2u3(_mtc0)
@@ -311,15 +336,20 @@ I_u1u2u3(_mthc0)
 I_u1(_mthi)
 I_u1(_mtlo)
 I_u3u1u2(_mul)
-I_u2u1u3(_ori)
+I_u1u2(_multu)
+I_u3u1u2(_nor)
 I_u3u1u2(_or)
+I_u2u1u3(_ori)
 I_0(_rfe)
+I_u2s3u1(_sb)
 I_u2s3u1(_sc)
 I_u2s3u1(_scd)
 I_u2s3u1(_sd)
+I_u2s3u1(_sh)
 I_u2u1u3(_sll)
 I_u3u2u1(_sllv)
 I_s3s1s2(_slt)
+I_u2u1s3(_slti)
 I_u2u1s3(_sltiu)
 I_u3u1u2(_sltu)
 I_u2u1u3(_sra)
@@ -340,6 +370,7 @@ I_u2u1u3(_xori)
 I_u2u1(_yield)
 I_u2u1msbu3(_dins);
 I_u2u1msb32u3(_dinsm);
+I_u2u1msb32msb3(_dinsu);
 I_u1(_syscall);
 I_u1u2s3(_bbit0);
 I_u1u2s3(_bbit1);
index 8c27714..47d6784 100644 (file)
@@ -1,3 +1,4 @@
 # MIPS networking code
 
-obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_asm.o
+obj-$(CONFIG_MIPS_CBPF_JIT) += bpf_jit.o bpf_jit_asm.o
+obj-$(CONFIG_MIPS_EBPF_JIT) += ebpf_jit.o
index ce89c9e..974276e 100644 (file)
 #include <asm/unistd.h>
 #include <asm/vdso.h>
 
+#ifdef CONFIG_MIPS_CLOCK_VSYSCALL
+
+static __always_inline long gettimeofday_fallback(struct timeval *_tv,
+                                         struct timezone *_tz)
+{
+       register struct timezone *tz asm("a1") = _tz;
+       register struct timeval *tv asm("a0") = _tv;
+       register long ret asm("v0");
+       register long nr asm("v0") = __NR_gettimeofday;
+       register long error asm("a3");
+
+       asm volatile(
+       "       syscall\n"
+       : "=r" (ret), "=r" (error)
+       : "r" (tv), "r" (tz), "r" (nr)
+       : "memory");
+
+       return error ? -ret : ret;
+}
+
+#endif
+
+static __always_inline long clock_gettime_fallback(clockid_t _clkid,
+                                          struct timespec *_ts)
+{
+       register struct timespec *ts asm("a1") = _ts;
+       register clockid_t clkid asm("a0") = _clkid;
+       register long ret asm("v0");
+       register long nr asm("v0") = __NR_clock_gettime;
+       register long error asm("a3");
+
+       asm volatile(
+       "       syscall\n"
+       : "=r" (ret), "=r" (error)
+       : "r" (clkid), "r" (ts), "r" (nr)
+       : "memory");
+
+       return error ? -ret : ret;
+}
+
 static __always_inline int do_realtime_coarse(struct timespec *ts,
                                              const union mips_vdso_data *data)
 {
@@ -39,8 +79,8 @@ static __always_inline int do_monotonic_coarse(struct timespec *ts,
                                               const union mips_vdso_data *data)
 {
        u32 start_seq;
-       u32 to_mono_sec;
-       u32 to_mono_nsec;
+       u64 to_mono_sec;
+       u64 to_mono_nsec;
 
        do {
                start_seq = vdso_data_read_begin(data);
@@ -148,8 +188,8 @@ static __always_inline int do_monotonic(struct timespec *ts,
 {
        u32 start_seq;
        u64 ns;
-       u32 to_mono_sec;
-       u32 to_mono_nsec;
+       u64 to_mono_sec;
+       u64 to_mono_nsec;
 
        do {
                start_seq = vdso_data_read_begin(data);
@@ -187,7 +227,7 @@ int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
 
        ret = do_realtime(&ts, data);
        if (ret)
-               return ret;
+               return gettimeofday_fallback(tv, tz);
 
        if (tv) {
                tv->tv_sec = ts.tv_sec;
@@ -202,12 +242,12 @@ int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
        return 0;
 }
 
-#endif /* CONFIG_CLKSRC_MIPS_GIC */
+#endif /* CONFIG_MIPS_CLOCK_VSYSCALL */
 
 int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
 {
        const union mips_vdso_data *data = get_vdso_data();
-       int ret;
+       int ret = -1;
 
        switch (clkid) {
        case CLOCK_REALTIME_COARSE:
@@ -223,10 +263,11 @@ int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
                ret = do_monotonic(ts, data);
                break;
        default:
-               ret = -ENOSYS;
                break;
        }
 
-       /* If we return -ENOSYS libc should fall back to a syscall. */
+       if (ret)
+               ret = clock_gettime_fallback(clkid, ts);
+
        return ret;
 }
index aa6a388..811414f 100644 (file)
@@ -21,7 +21,7 @@ do {                                                          \
        asm volatile(                                           \
                "       syscall 15                      \n"     \
                "0:                                     \n"     \
-               "       .section __bug_table,\"a\"      \n"     \
+               "       .section __bug_table,\"aw\"     \n"     \
                "       .long 0b,%0,%1                  \n"     \
                "       .previous                       \n"     \
                :                                               \
index f3671cb..b056275 100644 (file)
@@ -11,4 +11,6 @@
 #ifndef _ASM_NMI_H
 #define _ASM_NMI_H
 
+extern void arch_touch_nmi_watchdog(void);
+
 #endif /* _ASM_NMI_H */
index f2f5c9c..34f8773 100644 (file)
@@ -50,9 +50,9 @@ watchdog_handler:
 #   we can't inline it)
 #
 ###############################################################################
-       .globl  touch_nmi_watchdog
-       .type   touch_nmi_watchdog,@function
-touch_nmi_watchdog:
+       .globl  arch_touch_nmi_watchdog
+       .type   arch_touch_nmi_watchdog,@function
+arch_touch_nmi_watchdog:
        clr     d0
        clr     d1
        mov     watchdog_alert_counter, a0
@@ -63,4 +63,4 @@ touch_nmi_watchdog:
        lne
        ret     [],0
 
-       .size   touch_nmi_watchdog,.-touch_nmi_watchdog
+       .size   arch_touch_nmi_watchdog,.-arch_touch_nmi_watchdog
index a2d8e69..0d5641b 100644 (file)
@@ -31,7 +31,7 @@ static unsigned int watchdog;
 static unsigned int watchdog_hz = 1;
 unsigned int watchdog_alert_counter[NR_CPUS];
 
-EXPORT_SYMBOL(touch_nmi_watchdog);
+EXPORT_SYMBOL(arch_touch_nmi_watchdog);
 
 /*
  * the best way to detect whether a CPU has a 'hard lockup' problem
index e1a843d..896c26a 100644 (file)
@@ -1,8 +1,6 @@
 generic-y += atomic.h
-generic-y += auxvec.h
 generic-y += barrier.h
 generic-y += bitops.h
-generic-y += bitsperlong.h
 generic-y += bug.h
 generic-y += bugs.h
 generic-y += clkdev.h
@@ -12,55 +10,33 @@ generic-y += device.h
 generic-y += div64.h
 generic-y += dma.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += exec.h
 generic-y += extable.h
 generic-y += fb.h
-generic-y += fcntl.h
 generic-y += ftrace.h
 generic-y += futex.h
 generic-y += hardirq.h
 generic-y += hw_irq.h
-generic-y += ioctl.h
-generic-y += ioctls.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
-generic-y += kvm_para.h
+generic-y += kprobes.h
 generic-y += local.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
 generic-y += module.h
-generic-y += msgbuf.h
-generic-y += param.h
 generic-y += pci.h
 generic-y += percpu.h
-generic-y += poll.h
-generic-y += posix_types.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += sections.h
 generic-y += segment.h
-generic-y += sembuf.h
 generic-y += serial.h
-generic-y += shmbuf.h
-generic-y += signal.h
-generic-y += socket.h
-generic-y += sockios.h
 generic-y += spinlock.h
-generic-y += stat.h
-generic-y += statfs.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += topology.h
 generic-y += trace_clock.h
-generic-y += types.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += kprobes.h
diff --git a/arch/nios2/include/asm/signal.h b/arch/nios2/include/asm/signal.h
deleted file mode 100644 (file)
index bbcf11e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright Altera Corporation (C) 2013. All rights reserved
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-#ifndef _NIOS2_SIGNAL_H
-#define _NIOS2_SIGNAL_H
-
-#include <uapi/asm/signal.h>
-
-#endif /* _NIOS2_SIGNAL_H */
index 51eff5b..ffca24d 100644 (file)
@@ -1,6 +1,29 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += auxvec.h
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += kvm_para.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += resource.h
+generic-y += sembuf.h
 generic-y += setup.h
+generic-y += shmbuf.h
 generic-y += siginfo.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
 generic-y += ucontext.h
index 091585a..5bea416 100644 (file)
@@ -1,6 +1,4 @@
-generic-y += auxvec.h
 generic-y += barrier.h
-generic-y += bitsperlong.h
 generic-y += bug.h
 generic-y += bugs.h
 generic-y += cacheflush.h
@@ -11,57 +9,32 @@ generic-y += device.h
 generic-y += div64.h
 generic-y += dma.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += exec.h
 generic-y += extable.h
 generic-y += fb.h
-generic-y += fcntl.h
 generic-y += ftrace.h
 generic-y += hardirq.h
 generic-y += hw_irq.h
-generic-y += ioctl.h
-generic-y += ioctls.h
-generic-y += ipcbuf.h
 generic-y += irq.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
-generic-y += kvm_para.h
+generic-y += kprobes.h
 generic-y += local.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
 generic-y += module.h
-generic-y += msgbuf.h
 generic-y += pci.h
 generic-y += percpu.h
-generic-y += poll.h
-generic-y += posix_types.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += sections.h
 generic-y += segment.h
-generic-y += sembuf.h
-generic-y += setup.h
-generic-y += shmbuf.h
-generic-y += shmparam.h
-generic-y += signal.h
-generic-y += socket.h
-generic-y += sockios.h
-generic-y += stat.h
-generic-y += statfs.h
 generic-y += string.h
-generic-y += swab.h
 generic-y += switch_to.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += topology.h
 generic-y += trace_clock.h
-generic-y += types.h
-generic-y += ucontext.h
 generic-y += user.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += kprobes.h
index b55fc2a..62286db 100644 (file)
@@ -1,4 +1,31 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += auxvec.h
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += kvm_para.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += setup.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
 generic-y += siginfo.h
+generic-y += signal.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += swab.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
+generic-y += ucontext.h
index 143d026..ccc1097 100644 (file)
@@ -1,11 +1,9 @@
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_SLAB=y
@@ -14,7 +12,6 @@ CONFIG_OPROFILE=m
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_PA7100LC=y
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_GSC_LASI=y
@@ -32,11 +29,9 @@ CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
-# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=m
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
-CONFIG_IP_NF_QUEUE=m
 CONFIG_LLC2=m
 CONFIG_NET_PKTGEN=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
@@ -65,21 +60,20 @@ CONFIG_MD_LINEAR=m
 CONFIG_MD_RAID0=m
 CONFIG_MD_RAID1=m
 CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
 CONFIG_BONDING=m
+CONFIG_DUMMY=m
 CONFIG_TUN=m
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=m
 CONFIG_LASI_82596=y
 CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_MPPE=m
 CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
 # CONFIG_KEYBOARD_HIL_OLD is not set
 CONFIG_MOUSE_SERIAL=m
+CONFIG_LEGACY_PTY_COUNT=64
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=17
@@ -88,22 +82,17 @@ CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 # CONFIG_SERIAL_MUX is not set
 CONFIG_PDC_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=64
 CONFIG_PRINTER=m
 CONFIG_PPDEV=m
 # CONFIG_HW_RANDOM is not set
 CONFIG_RAW_DRIVER=y
 # CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=128
 CONFIG_DUMMY_CONSOLE_ROWS=48
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
@@ -111,13 +100,9 @@ CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_SEQUENCER=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_SEQUENCER_OSS=y
 CONFIG_SND_HARMONY=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
 CONFIG_JFS_FS=m
 CONFIG_XFS_FS=m
 CONFIG_AUTOFS4_FS=y
@@ -130,14 +115,10 @@ CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_UFS_FS=m
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=m
 CONFIG_NFSD_V4=y
-CONFIG_RPCSEC_GSS_SPKM3=m
-CONFIG_SMB_FS=m
-CONFIG_SMB_NLS_DEFAULT=y
 CONFIG_CIFS=m
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_CODEPAGE_737=m
@@ -177,21 +158,16 @@ CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_KOI8_R=m
 CONFIG_NLS_KOI8_U=m
 CONFIG_NLS_UTF8=m
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_MUTEXES=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_ANUBIS=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAST6=m
@@ -200,6 +176,7 @@ CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_DEFLATE=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
-CONFIG_LIBCRC32C=m
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
index 1a4f776..5acb93d 100644 (file)
@@ -1,13 +1,10 @@
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_SLAB=y
@@ -16,7 +13,6 @@ CONFIG_OPROFILE=m
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_PA8X00=y
 CONFIG_64BIT=y
 CONFIG_SMP=y
@@ -43,21 +39,17 @@ CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
-# CONFIG_INET_LRO is not set
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
 CONFIG_IPV6_TUNNEL=m
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_XT_MATCH_DCCP is not set
-CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_RAW=m
@@ -70,7 +62,6 @@ CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_RT=m
-CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
@@ -94,7 +85,6 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 CONFIG_SCSI_SYM53C8XX_2=y
 CONFIG_SCSI_QLOGIC_1280=m
@@ -106,43 +96,38 @@ CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
 CONFIG_FUSION=y
 CONFIG_FUSION_SPI=m
-CONFIG_FUSION_FC=m
 CONFIG_FUSION_CTL=m
 CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
 CONFIG_BONDING=m
+CONFIG_DUMMY=m
 CONFIG_TUN=m
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_VENDOR_3COM=y
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_3C589=m
 CONFIG_VORTEX=m
 CONFIG_TYPHOON=m
+CONFIG_ACENIC=m
+CONFIG_ACENIC_OMIT_TIGON_I=y
+CONFIG_PCNET32=m
+CONFIG_TIGON3=m
 CONFIG_NET_TULIP=y
 CONFIG_DE2104X=m
 CONFIG_TULIP=y
 CONFIG_TULIP_MMIO=y
 CONFIG_PCMCIA_XIRCOM=m
 CONFIG_HP100=m
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=m
 CONFIG_E100=m
-CONFIG_ACENIC=m
-CONFIG_ACENIC_OMIT_TIGON_I=y
 CONFIG_E1000=m
-CONFIG_TIGON3=m
-CONFIG_NET_PCMCIA=y
-CONFIG_PCMCIA_3C589=m
-CONFIG_PCMCIA_3C574=m
 CONFIG_PCMCIA_SMC91C92=m
 CONFIG_PCMCIA_XIRC2PS=m
 CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_ASYNC=m
 CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-# CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_CS=m
@@ -151,7 +136,6 @@ CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_PDC_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_RAW_DRIVER=y
 # CONFIG_HWMON is not set
@@ -160,7 +144,6 @@ CONFIG_AGP_PARISC=y
 # CONFIG_STI_CONSOLE is not set
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
 CONFIG_JFS_FS=m
 CONFIG_XFS_FS=m
 CONFIG_AUTOFS4_FS=y
@@ -173,13 +156,9 @@ CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_UFS_FS=m
 CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
+CONFIG_NFS_V4=m
 CONFIG_NFSD=m
 CONFIG_NFSD_V4=y
-CONFIG_RPCSEC_GSS_SPKM3=m
-CONFIG_SMB_FS=m
-CONFIG_SMB_NLS_DEFAULT=y
 CONFIG_CIFS=m
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_CODEPAGE_850=m
@@ -187,17 +166,12 @@ CONFIG_NLS_ASCII=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 CONFIG_HEADERS_CHECK=y
-CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_HMAC=y
 CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_BLOWFISH=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
-CONFIG_LIBCRC32C=m
index f1a0c25..83ffd16 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
@@ -25,8 +24,6 @@ CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_LRO is not set
-CONFIG_IPV6=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
@@ -53,10 +50,9 @@ CONFIG_MD_LINEAR=y
 CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_LASI_82596=y
 CONFIG_NET_TULIP=y
 CONFIG_TULIP=y
+CONFIG_LASI_82596=y
 CONFIG_PPP=y
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_HIL_OLD is not set
@@ -71,40 +67,31 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_PRINTER=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_SEQUENCER=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_SEQUENCER_OSS=y
 CONFIG_SND_HARMONY=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
 CONFIG_AUTOFS4_FS=y
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
-CONFIG_SMB_FS=y
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_CODEPAGE_850=m
 CONFIG_NLS_ASCII=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_HEADERS_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_SECURITY=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
index 8e8f0e3..0764d39 100644 (file)
@@ -1,12 +1,9 @@
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_SLAB=y
@@ -15,7 +12,6 @@ CONFIG_OPROFILE=m
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_PA8X00=y
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_GSC is not set
@@ -31,13 +27,11 @@ CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 CONFIG_INET6_IPCOMP=m
 CONFIG_IPV6_TUNNEL=m
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_DEBUG=y
-CONFIG_IP_NF_QUEUE=m
 CONFIG_NET_PKTGEN=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
@@ -50,13 +44,11 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_NS87415=y
-CONFIG_PATA_SIL680=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 CONFIG_SCSI_SYM53C8XX_2=y
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
@@ -76,28 +68,23 @@ CONFIG_FUSION=y
 CONFIG_FUSION_SPI=m
 CONFIG_FUSION_CTL=m
 CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
 CONFIG_BONDING=m
+CONFIG_DUMMY=m
 CONFIG_TUN=m
-CONFIG_NET_ETHERNET=y
+CONFIG_ACENIC=m
+CONFIG_TIGON3=m
 CONFIG_NET_TULIP=y
 CONFIG_DE2104X=m
 CONFIG_TULIP=y
 CONFIG_TULIP_MMIO=y
-CONFIG_NET_PCI=y
 CONFIG_E100=m
-CONFIG_ACENIC=m
 CONFIG_E1000=m
-CONFIG_TIGON3=m
 CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
 CONFIG_PPPOE=m
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1600
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=1200
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
 # CONFIG_KEYBOARD_ATKBD is not set
 # CONFIG_MOUSE_PS2 is not set
 CONFIG_SERIO=m
@@ -111,7 +98,6 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_RAW_DRIVER=y
 # CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
@@ -121,9 +107,6 @@ CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_SEQUENCER=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_SEQUENCER_OSS=y
 CONFIG_SND_AD1889=y
 CONFIG_USB_HIDDEV=y
 CONFIG_USB=y
@@ -139,7 +122,6 @@ CONFIG_USB_MICROTEK=m
 CONFIG_USB_LEGOTOWER=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
 CONFIG_XFS_FS=m
 CONFIG_AUTOFS4_FS=y
 CONFIG_ISO9660_FS=y
@@ -149,7 +131,6 @@ CONFIG_VFAT_FS=m
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
@@ -159,18 +140,13 @@ CONFIG_NLS_ASCII=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 CONFIG_HEADERS_CHECK=y
-CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_MD5=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_DES=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
-CONFIG_LIBCRC32C=m
index f6a4c01..088ab94 100644 (file)
@@ -1,16 +1,13 @@
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
-CONFIG_FHANDLE=y
+# CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_RD_BZIP2=y
-CONFIG_RD_LZMA=y
-CONFIG_RD_LZO=y
 CONFIG_EXPERT=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_SLAB=y
@@ -23,7 +20,6 @@ CONFIG_PA8X00=y
 CONFIG_64BIT=y
 CONFIG_SMP=y
 CONFIG_PREEMPT=y
-# CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_IOMMU_CCIO=y
 CONFIG_PCI=y
 CONFIG_PCI_LBA=y
@@ -146,7 +142,6 @@ CONFIG_FB_FOREIGN_ENDIAN=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 # CONFIG_FB_STI is not set
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 # CONFIG_BACKLIGHT_GENERIC is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
@@ -157,12 +152,9 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_CLUT224 is not set
 CONFIG_SOUND=m
 CONFIG_SND=m
+CONFIG_SND_VERBOSE_PRINTK=y
 CONFIG_SND_SEQUENCER=m
 CONFIG_SND_SEQ_DUMMY=m
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-CONFIG_SND_SEQUENCER_OSS=y
-CONFIG_SND_VERBOSE_PRINTK=y
 CONFIG_SND_AD1889=m
 # CONFIG_SND_USB is not set
 # CONFIG_SND_GSC is not set
@@ -174,8 +166,6 @@ CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT4_FS=m
 CONFIG_REISERFS_FS=m
 CONFIG_REISERFS_PROC_INFO=y
 CONFIG_XFS_FS=m
@@ -238,11 +228,8 @@ CONFIG_DEBUG_SLAB=y
 CONFIG_DEBUG_SLAB_LEAK=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_LOCKUP_DETECTOR=y
-CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
 CONFIG_PANIC_ON_OOPS=y
 CONFIG_DEBUG_RT_MUTEXES=y
-CONFIG_PROVE_RCU_DELAY=y
 CONFIG_DEBUG_BLOCK_EXT_DEVT=y
 CONFIG_LATENCYTOP=y
 CONFIG_KEYS=y
index 310b665..52c9050 100644 (file)
@@ -1,11 +1,9 @@
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_SLAB=y
@@ -41,9 +39,7 @@ CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
-# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=m
-CONFIG_IPV6=y
 CONFIG_INET6_AH=y
 CONFIG_INET6_ESP=y
 CONFIG_INET6_IPCOMP=y
@@ -82,26 +78,23 @@ CONFIG_MD_RAID1=y
 CONFIG_MD_RAID10=y
 CONFIG_BLK_DEV_DM=y
 CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
 CONFIG_BONDING=m
+CONFIG_DUMMY=m
 CONFIG_TUN=m
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=m
-CONFIG_LASI_82596=y
-CONFIG_NET_TULIP=y
-CONFIG_TULIP=y
-CONFIG_NET_PCI=y
 CONFIG_ACENIC=y
 CONFIG_TIGON3=y
-CONFIG_NET_PCMCIA=y
+CONFIG_NET_TULIP=y
+CONFIG_TULIP=y
+CONFIG_LASI_82596=y
 CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
 CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
 # CONFIG_KEYBOARD_HIL_OLD is not set
 CONFIG_MOUSE_SERIAL=y
+CONFIG_LEGACY_PTY_COUNT=64
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_CS=y
@@ -109,31 +102,24 @@ CONFIG_SERIAL_8250_NR_UARTS=17
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_LEGACY_PTY_COUNT=64
 CONFIG_PRINTER=m
 CONFIG_PPDEV=m
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=128
 CONFIG_DUMMY_CONSOLE_ROWS=48
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x16=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
 # CONFIG_LOGO_LINUX_CLUT224 is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
-CONFIG_SND_SEQUENCER=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_SEQUENCER_OSS=y
 CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SEQUENCER=y
 CONFIG_SND_AD1889=y
 CONFIG_SND_HARMONY=y
 CONFIG_HID_GYRATION=y
@@ -141,7 +127,6 @@ CONFIG_HID_NTRIG=y
 CONFIG_HID_PANTHERLORD=y
 CONFIG_HID_PETALYNX=y
 CONFIG_HID_SAMSUNG=y
-CONFIG_HID_SONY=y
 CONFIG_HID_SUNPLUS=y
 CONFIG_HID_TOPSEED=y
 CONFIG_USB=y
@@ -150,21 +135,15 @@ CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_UHCI_HCD=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_AUTOFS_FS=y
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
 CONFIG_VFAT_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=y
 CONFIG_NFSD_V4=y
-CONFIG_RPCSEC_GSS_SPKM3=m
-CONFIG_SMB_FS=m
-CONFIG_SMB_NLS_DEFAULT=y
 CONFIG_CIFS=m
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_737=m
@@ -204,30 +183,24 @@ CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_KOI8_R=m
 CONFIG_NLS_KOI8_U=m
 CONFIG_NLS_UTF8=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 CONFIG_HEADERS_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_MUTEXES=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_KEYS=y
-CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
 CONFIG_LIBCRC32C=m
+CONFIG_FONTS=y
index 8688ba7..37ae4b5 100644 (file)
@@ -2,15 +2,11 @@ CONFIG_LOCALVERSION="-32bit"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
-CONFIG_FHANDLE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_RD_BZIP2=y
-CONFIG_RD_LZMA=y
-CONFIG_RD_LZO=y
 CONFIG_EXPERT=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_PERF_EVENTS=y
@@ -49,7 +45,6 @@ CONFIG_INET_ESP=m
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=m
 CONFIG_LLC2=m
 # CONFIG_WIRELESS is not set
@@ -149,10 +144,8 @@ CONFIG_PRINTER=m
 CONFIG_PPDEV=m
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
-CONFIG_POWER_SUPPLY=y
 # CONFIG_HWMON is not set
 CONFIG_AGP=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB=y
 CONFIG_FB_FOREIGN_ENDIAN=y
 CONFIG_FB_MODE_HELPERS=y
@@ -169,11 +162,8 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_CLUT224 is not set
 CONFIG_SOUND=m
 CONFIG_SND=m
-CONFIG_SND_SEQUENCER=m
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-CONFIG_SND_SEQUENCER_OSS=y
 CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SEQUENCER=m
 CONFIG_SND_AD1889=m
 CONFIG_SND_HARMONY=m
 CONFIG_HIDRAW=y
@@ -223,12 +213,7 @@ CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_SECURITY=y
 CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_SECURITY=y
-CONFIG_EXT4_FS=y
-CONFIG_XFS_FS=m
-CONFIG_XFS_QUOTA=y
-CONFIG_XFS_RT=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
@@ -293,15 +278,12 @@ CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DEBUG_STACKOVERFLOW=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
-CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
-CONFIG_RCU_CPU_STALL_INFO=y
 CONFIG_LATENCYTOP=y
 CONFIG_LKDTM=m
 CONFIG_KEYS=y
-CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_HMAC=y
 CONFIG_CRYPTO_MD5=y
@@ -320,7 +302,6 @@ CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_DEFLATE=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
 CONFIG_CRC_T10DIF=y
 CONFIG_FONTS=y
index c564e6e..d39e7f8 100644 (file)
@@ -8,10 +8,11 @@ CONFIG_TASKSTATS=y
 CONFIG_TASK_DELAY_ACCT=y
 CONFIG_TASK_XACCT=y
 CONFIG_TASK_IO_ACCOUNTING=y
-# CONFIG_UTS_NS is not set
-# CONFIG_IPC_NS is not set
-# CONFIG_PID_NS is not set
-# CONFIG_NET_NS is not set
+CONFIG_CGROUPS=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CPUSETS=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -52,7 +53,6 @@ CONFIG_INET_ESP=m
 CONFIG_INET_XFRM_MODE_TRANSPORT=m
 CONFIG_INET_XFRM_MODE_TUNNEL=m
 CONFIG_INET_XFRM_MODE_BEET=m
-CONFIG_INET_LRO=m
 CONFIG_INET_DIAG=m
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_ADVANCED is not set
@@ -84,7 +84,6 @@ CONFIG_PATA_SIL680=y
 CONFIG_ATA_GENERIC=y
 CONFIG_MD=y
 CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_RAID=m
 CONFIG_DM_UEVENT=y
@@ -138,21 +137,21 @@ CONFIG_QLGE=m
 # CONFIG_NET_VENDOR_TI is not set
 # CONFIG_NET_VENDOR_VIA is not set
 # CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_MDIO_BITBANG=m
 CONFIG_PHYLIB=y
-CONFIG_MARVELL_PHY=m
-CONFIG_DAVICOM_PHY=m
-CONFIG_QSEMI_PHY=m
-CONFIG_LXT_PHY=m
-CONFIG_CICADA_PHY=m
-CONFIG_VITESSE_PHY=m
-CONFIG_SMSC_PHY=m
 CONFIG_BROADCOM_PHY=m
+CONFIG_CICADA_PHY=m
+CONFIG_DAVICOM_PHY=m
 CONFIG_ICPLUS_PHY=m
-CONFIG_REALTEK_PHY=m
+CONFIG_LSI_ET1011C_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_MARVELL_PHY=m
 CONFIG_NATIONAL_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_REALTEK_PHY=m
+CONFIG_SMSC_PHY=m
 CONFIG_STE10XP=m
-CONFIG_LSI_ET1011C_PHY=m
-CONFIG_MDIO_BITBANG=m
+CONFIG_VITESSE_PHY=m
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
@@ -166,10 +165,8 @@ CONFIG_INPUT_MISC=y
 CONFIG_SERIO_SERPORT=m
 # CONFIG_HP_SDC is not set
 CONFIG_SERIO_RAW=m
-CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_NOZOMI=m
-# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_8250=y
 # CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
 CONFIG_SERIAL_8250_CONSOLE=y
@@ -207,10 +204,8 @@ CONFIG_AGP=y
 CONFIG_AGP_PARISC=y
 CONFIG_DRM=y
 CONFIG_DRM_RADEON=y
-CONFIG_DRM_RADEON_UMS=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_MODE_HELPERS=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_BACKLIGHT_GENERIC is not set
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_LOGO=y
@@ -246,8 +241,6 @@ CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_SECURITY=y
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_SECURITY=y
-CONFIG_EXT4_FS=y
-CONFIG_EXT4_FS_SECURITY=y
 CONFIG_XFS_FS=m
 CONFIG_BTRFS_FS=m
 CONFIG_QUOTA=y
@@ -286,27 +279,16 @@ CONFIG_DEBUG_FS=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_LOCKUP_DETECTOR=y
-CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
-CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
 # CONFIG_SCHED_DEBUG is not set
-CONFIG_TIMER_STATS=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_DEFLATE=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=m
 CONFIG_LIBCRC32C=y
-CONFIG_XZ_DEC_X86=y
-CONFIG_XZ_DEC_POWERPC=y
-CONFIG_XZ_DEC_IA64=y
-CONFIG_XZ_DEC_ARM=y
-CONFIG_XZ_DEC_ARMTHUMB=y
-CONFIG_XZ_DEC_SPARC=y
index a9909c2..a411395 100644 (file)
@@ -1,5 +1,3 @@
-
-generic-y += auxvec.h
 generic-y += barrier.h
 generic-y += clkdev.h
 generic-y += current.h
@@ -11,14 +9,12 @@ generic-y += hw_irq.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
-generic-y += kvm_para.h
+generic-y += kprobes.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += param.h
 generic-y += percpu.h
-generic-y += poll.h
 generic-y += preempt.h
 generic-y += seccomp.h
 generic-y += segment.h
@@ -28,4 +24,3 @@ generic-y += user.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += kprobes.h
index d274227..07ea467 100644 (file)
@@ -27,7 +27,7 @@
        do {                                                            \
                asm volatile("\n"                                       \
                             "1:\t" PARISC_BUG_BREAK_ASM "\n"           \
-                            "\t.pushsection __bug_table,\"a\"\n"       \
+                            "\t.pushsection __bug_table,\"aw\"\n"      \
                             "2:\t" ASM_WORD_INSN "1b, %c0\n"           \
                             "\t.short %c1, %c2\n"                      \
                             "\t.org 2b+%c3\n"                          \
@@ -50,7 +50,7 @@
        do {                                                            \
                asm volatile("\n"                                       \
                             "1:\t" PARISC_BUG_BREAK_ASM "\n"           \
-                            "\t.pushsection __bug_table,\"a\"\n"       \
+                            "\t.pushsection __bug_table,\"aw\"\n"      \
                             "2:\t" ASM_WORD_INSN "1b, %c0\n"           \
                             "\t.short %c1, %c2\n"                      \
                             "\t.org 2b+%c3\n"                          \
@@ -64,7 +64,7 @@
        do {                                                            \
                asm volatile("\n"                                       \
                             "1:\t" PARISC_BUG_BREAK_ASM "\n"           \
-                            "\t.pushsection __bug_table,\"a\"\n"       \
+                            "\t.pushsection __bug_table,\"aw\"\n"      \
                             "2:\t" ASM_WORD_INSN "1b\n"                \
                             "\t.short %c0\n"                           \
                             "\t.org 2b+%c1\n"                          \
index 32e105f..e3c0586 100644 (file)
 #define PDC_PAT_MEM_SETGM              9L /* Set Good Memory value        */
 #define PDC_PAT_MEM_ADD_PAGE           10L /* ADDs a page to the cell      */
 #define PDC_PAT_MEM_ADDRESS            11L /* Get Physical Location From   */
-                                                /* Memory Address               */
+                                           /* Memory Address               */
 #define PDC_PAT_MEM_GET_TXT_SIZE       12L /* Get Formatted Text Size   */
 #define PDC_PAT_MEM_GET_PD_TXT         13L /* Get PD Formatted Text     */
 #define PDC_PAT_MEM_GET_CELL_TXT       14L /* Get Cell Formatted Text   */
@@ -228,6 +228,17 @@ struct pdc_pat_mem_read_pd_retinfo { /* PDC_PAT_MEM/PDC_PAT_MEM_PD_READ */
        unsigned long pdt_entries;
 };
 
+struct pdc_pat_mem_phys_mem_location { /* PDC_PAT_MEM/PDC_PAT_MEM_ADDRESS */
+       u64 cabinet:8;
+       u64 ign1:8;
+       u64 ign2:8;
+       u64 cell_slot:8;
+       u64 ign3:8;
+       u64 dimm_slot:8; /* DIMM slot, e.g. 0x1A, 0x2B, show user hex value! */
+       u64 ign4:8;
+       u64 source:4; /* for mem: always 0x07 */
+       u64 source_detail:4; /* for mem: always 0x04 (SIMM or DIMM) */
+};
 
 struct pdc_pat_pd_addr_map_entry {
        unsigned char entry_type;       /* 1 = Memory Descriptor Entry Type */
@@ -319,6 +330,9 @@ extern int pdc_pat_mem_read_cell_pdt(struct pdc_pat_mem_read_pd_retinfo *pret,
 extern int pdc_pat_mem_read_pd_pdt(struct pdc_pat_mem_read_pd_retinfo *pret,
                unsigned long *pdt_entries_ptr, unsigned long count,
                unsigned long offset);
+extern int pdc_pat_mem_get_dimm_phys_location(
+                struct pdc_pat_mem_phys_mem_location *pret,
+                unsigned long phys_addr);
 
 #endif /* __ASSEMBLY__ */
 
index 1fd962a..cab33a0 100644 (file)
@@ -6,7 +6,6 @@
  */
 #include <asm/page.h>
 #include <asm/cache.h>
-#include <asm-generic/uaccess-unaligned.h>
 
 #include <linux/bug.h>
 #include <linux/string.h>
index 3971c60..196d2a4 100644 (file)
@@ -1,4 +1,8 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += auxvec.h
+generic-y += kvm_para.h
+generic-y += param.h
+generic-y += poll.h
 generic-y += resource.h
index 674c68a..d0e3321 100644 (file)
@@ -60,7 +60,7 @@
 #define TIOCGPKT       _IOR('T', 0x38, int) /* Get packet mode state */
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
-#define TIOCGPTPEER    _IOR('T', 0x41, int) /* Safely open the slave */
+#define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
 
 #define FIONCLEX       0x5450  /* these numbers need to be adjusted. */
 #define FIOCLEX                0x5451
index c32a090..85a92db 100644 (file)
@@ -453,8 +453,8 @@ void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
          before it can be accessed through the kernel mapping. */
        preempt_disable();
        flush_dcache_page_asm(__pa(vfrom), vaddr);
-       preempt_enable();
        copy_page_asm(vto, vfrom);
+       preempt_enable();
 }
 EXPORT_SYMBOL(copy_user_page);
 
@@ -539,6 +539,10 @@ void flush_cache_mm(struct mm_struct *mm)
        struct vm_area_struct *vma;
        pgd_t *pgd;
 
+       /* Flush the TLB to avoid speculation if coherency is required. */
+       if (parisc_requires_coherency())
+               flush_tlb_all();
+
        /* Flushing the whole cache on each cpu takes forever on
           rp3440, etc.  So, avoid it if the mm isn't too big.  */
        if (mm_total_size(mm) >= parisc_cache_flush_threshold) {
@@ -577,33 +581,22 @@ void flush_cache_mm(struct mm_struct *mm)
 void flush_cache_range(struct vm_area_struct *vma,
                unsigned long start, unsigned long end)
 {
-       unsigned long addr;
-       pgd_t *pgd;
-
        BUG_ON(!vma->vm_mm->context);
 
+       /* Flush the TLB to avoid speculation if coherency is required. */
+       if (parisc_requires_coherency())
+               flush_tlb_range(vma, start, end);
+
        if ((end - start) >= parisc_cache_flush_threshold) {
                flush_cache_all();
                return;
        }
 
-       if (vma->vm_mm->context == mfsp(3)) {
-               flush_user_dcache_range_asm(start, end);
-               if (vma->vm_flags & VM_EXEC)
-                       flush_user_icache_range_asm(start, end);
-               return;
-       }
+       BUG_ON(vma->vm_mm->context != mfsp(3));
 
-       pgd = vma->vm_mm->pgd;
-       for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
-               unsigned long pfn;
-               pte_t *ptep = get_ptep(pgd, addr);
-               if (!ptep)
-                       continue;
-               pfn = pte_pfn(*ptep);
-               if (pfn_valid(pfn))
-                       __flush_cache_page(vma, addr, PFN_PHYS(pfn));
-       }
+       flush_user_dcache_range_asm(start, end);
+       if (vma->vm_flags & VM_EXEC)
+               flush_user_icache_range_asm(start, end);
 }
 
 void
@@ -612,7 +605,8 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
        BUG_ON(!vma->vm_mm->context);
 
        if (pfn_valid(pfn)) {
-               flush_tlb_page(vma, vmaddr);
+               if (parisc_requires_coherency())
+                       flush_tlb_page(vma, vmaddr);
                __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
        }
 }
index 9819025..f622a31 100644 (file)
@@ -1481,12 +1481,44 @@ int pdc_pat_mem_read_pd_pdt(struct pdc_pat_mem_read_pd_retinfo *pret,
                unsigned long offset)
 {
        int retval;
-       unsigned long flags;
+       unsigned long flags, entries;
 
        spin_lock_irqsave(&pdc_lock, flags);
        retval = mem_pdc_call(PDC_PAT_MEM, PDC_PAT_MEM_PD_READ,
-               __pa(&pret), __pa(pdt_entries_ptr),
+               __pa(&pdc_result), __pa(pdt_entries_ptr),
                count, offset);
+
+       if (retval == PDC_OK) {
+               entries = min(pdc_result[0], count);
+               pret->actual_count_bytes = entries;
+               pret->pdt_entries = entries / sizeof(unsigned long);
+       }
+
+       spin_unlock_irqrestore(&pdc_lock, flags);
+
+       return retval;
+}
+
+/**
+ * pdc_pat_mem_get_dimm_phys_location - Get physical DIMM slot via PAT firmware
+ * @pret: ptr to hold returned information
+ * @phys_addr: physical address to examine
+ *
+ */
+int pdc_pat_mem_get_dimm_phys_location(
+               struct pdc_pat_mem_phys_mem_location *pret,
+               unsigned long phys_addr)
+{
+       int retval;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdc_lock, flags);
+       retval = mem_pdc_call(PDC_PAT_MEM, PDC_PAT_MEM_ADDRESS,
+               __pa(&pdc_result), phys_addr);
+
+       if (retval == PDC_OK)
+               memcpy(pret, &pdc_result, sizeof(*pret));
+
        spin_unlock_irqrestore(&pdc_lock, flags);
 
        return retval;
index ba5e1c7..5404e40 100644 (file)
@@ -413,6 +413,10 @@ static inline void stack_overflow_check(struct pt_regs *regs)
        if (regs->sr[7])
                return;
 
+       /* exit if already in panic */
+       if (sysctl_panic_on_stackoverflow < 0)
+               return;
+
        /* calculate kernel stack usage */
        stack_usage = sp - stack_start;
 #ifdef CONFIG_IRQSTACKS
@@ -454,8 +458,10 @@ check_kernel_stack:
 #ifdef CONFIG_IRQSTACKS
 panic_check:
 #endif
-       if (sysctl_panic_on_stackoverflow)
+       if (sysctl_panic_on_stackoverflow) {
+               sysctl_panic_on_stackoverflow = -1; /* disable further checks */
                panic("low stack detected by irq handler - check messages\n");
+       }
 #endif
 }
 
index f3a797e..d02874e 100644 (file)
@@ -112,10 +112,12 @@ void __init pdc_pdt_init(void)
 #ifdef CONFIG_64BIT
                struct pdc_pat_mem_read_pd_retinfo pat_pret;
 
+               /* try old obsolete PAT firmware function first */
+               pdt_type = PDT_PAT_OLD;
                ret = pdc_pat_mem_read_cell_pdt(&pat_pret, pdt_entry,
                        MAX_PDT_ENTRIES);
                if (ret != PDC_OK) {
-                       pdt_type = PDT_PAT_OLD;
+                       pdt_type = PDT_PAT_NEW;
                        ret = pdc_pat_mem_read_pd_pdt(&pat_pret, pdt_entry,
                                MAX_PDT_TABLE_SIZE, 0);
                }
@@ -131,11 +133,20 @@ void __init pdc_pdt_init(void)
        }
 
        for (i = 0; i < pdt_status.pdt_entries; i++) {
-               if (i < 20)
-                       pr_warn("PDT: BAD PAGE #%d at 0x%08lx (error_type = %lu)\n",
-                               i,
-                               pdt_entry[i] & PAGE_MASK,
-                               pdt_entry[i] & 1);
+               struct pdc_pat_mem_phys_mem_location loc;
+
+               /* get DIMM slot number */
+               loc.dimm_slot = 0xff;
+#ifdef CONFIG_64BIT
+               pdc_pat_mem_get_dimm_phys_location(&loc, pdt_entry[i]);
+#endif
+
+               pr_warn("PDT: BAD PAGE #%d at 0x%08lx, "
+                       "DIMM slot %02x (error_type = %lu)\n",
+                       i,
+                       pdt_entry[i] & PAGE_MASK,
+                       loc.dimm_slot,
+                       pdt_entry[i] & 1);
 
                /* mark memory page bad */
                memblock_reserve(pdt_entry[i] & PAGE_MASK, PAGE_SIZE);
index b64d7d2..a45a67d 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/uaccess.h>
 #include <linux/rcupdate.h>
 #include <linux/random.h>
+#include <linux/nmi.h>
 
 #include <asm/io.h>
 #include <asm/asm-offsets.h>
@@ -145,6 +146,7 @@ void machine_power_off(void)
 
        /* prevent soft lockup/stalled CPU messages for endless loop. */
        rcu_sysrq_start();
+       lockup_detector_suspend();
        for (;;);
 }
 
index 3d6ef1b..ffe2cbf 100644 (file)
@@ -78,6 +78,8 @@ SECTIONS
                *(.text.sys_exit)
                *(.text.do_sigaltstack)
                *(.text.do_fork)
+               *(.text.div)
+               *($$*)                  /* millicode routines */
                *(.text.*)
                *(.fixup)
                *(.lock.text)           /* out-of-line lock text */
index 7177a3f..36f858c 100644 (file)
@@ -82,7 +82,7 @@ config NR_IRQS
 
 config NMI_IPI
        bool
-       depends on SMP && (DEBUGGER || KEXEC_CORE)
+       depends on SMP && (DEBUGGER || KEXEC_CORE || HARDLOCKUP_DETECTOR)
        default y
 
 config STACKTRACE_SUPPORT
@@ -125,6 +125,7 @@ config PPC
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_DMA_SET_COHERENT_MASK
        select ARCH_HAS_ELF_RANDOMIZE
+       select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_GCOV_PROFILE_ALL
        select ARCH_HAS_SCALED_CPUTIME          if VIRT_CPU_ACCOUNTING_NATIVE
        select ARCH_HAS_SG_CHAIN
@@ -192,11 +193,13 @@ config PPC
        select HAVE_MEMBLOCK
        select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_MOD_ARCH_SPECIFIC
-       select HAVE_NMI                         if PERF_EVENTS
+       select HAVE_NMI                         if PERF_EVENTS || (PPC64 && PPC_BOOK3S)
+       select HAVE_HARDLOCKUP_DETECTOR_ARCH    if (PPC64 && PPC_BOOK3S)
        select HAVE_OPROFILE
        select HAVE_OPTPROBES                   if PPC64
        select HAVE_PERF_EVENTS
        select HAVE_PERF_EVENTS_NMI             if PPC64
+       select HAVE_HARDLOCKUP_DETECTOR_PERF    if HAVE_PERF_EVENTS_NMI && !HAVE_HARDLOCKUP_DETECTOR_ARCH
        select HAVE_PERF_REGS
        select HAVE_PERF_USER_STACK_DUMP
        select HAVE_RCU_TABLE_FREE              if SMP
index 8d4ed73..e2b3e7a 100644 (file)
@@ -59,6 +59,19 @@ machine-$(CONFIG_PPC64) += 64
 machine-$(CONFIG_CPU_LITTLE_ENDIAN) += le
 UTS_MACHINE := $(subst $(space),,$(machine-y))
 
+# XXX This needs to be before we override LD below
+ifdef CONFIG_PPC32
+KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
+else
+ifeq ($(call ld-ifversion, -ge, 225000000, y),y)
+# Have the linker provide sfpr if possible.
+# There is a corresponding test in arch/powerpc/lib/Makefile
+KBUILD_LDFLAGS_MODULE += --save-restore-funcs
+else
+KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
+endif
+endif
+
 ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y)
 override LD    += -EL
 LDEMULATION    := lppc
@@ -190,18 +203,6 @@ else
 CHECKFLAGS     += -D__LITTLE_ENDIAN__
 endif
 
-ifdef CONFIG_PPC32
-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
-else
-ifeq ($(call ld-ifversion, -ge, 225000000, y),y)
-# Have the linker provide sfpr if possible.
-# There is a corresponding test in arch/powerpc/lib/Makefile
-KBUILD_LDFLAGS_MODULE += --save-restore-funcs
-else
-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
-endif
-endif
-
 ifeq ($(CONFIG_476FPE_ERR46),y)
        KBUILD_LDFLAGS_MODULE += --ppc476-workaround \
                -T $(srctree)/arch/powerpc/platforms/44x/ppc476_modules.lds
index 2b90335..a2cc801 100644 (file)
@@ -560,7 +560,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
  * Atomically increments @v by 1, so long as @v is non-zero.
  * Returns non-zero if @v was non-zero, and zero otherwise.
  */
-static __inline__ long atomic64_inc_not_zero(atomic64_t *v)
+static __inline__ int atomic64_inc_not_zero(atomic64_t *v)
 {
        long t1, t2;
 
@@ -579,7 +579,7 @@ static __inline__ long atomic64_inc_not_zero(atomic64_t *v)
        : "r" (&v->counter)
        : "cc", "xer", "memory");
 
-       return t1;
+       return t1 != 0;
 }
 
 #endif /* __powerpc64__ */
index 0ce513f..36fc7bf 100644 (file)
@@ -91,6 +91,7 @@ static inline int hash__pgd_bad(pgd_t pgd)
 }
 #ifdef CONFIG_STRICT_KERNEL_RWX
 extern void hash__mark_rodata_ro(void);
+extern void hash__mark_initmem_nx(void);
 #endif
 
 extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
index 77529a3..5b4023c 100644 (file)
@@ -59,13 +59,14 @@ extern struct patb_entry *partition_tb;
 #define PRTS_MASK      0x1f            /* process table size field */
 #define PRTB_MASK      0x0ffffffffffff000UL
 
-/*
- * Limit process table to PAGE_SIZE table. This
- * also limit the max pid we can support.
- * MAX_USER_CONTEXT * 16 bytes of space.
- */
-#define PRTB_SIZE_SHIFT        (CONTEXT_BITS + 4)
-#define PRTB_ENTRIES   (1ul << CONTEXT_BITS)
+/* Number of supported PID bits */
+extern unsigned int mmu_pid_bits;
+
+/* Base PID to allocate from */
+extern unsigned int mmu_base_pid;
+
+#define PRTB_SIZE_SHIFT        (mmu_pid_bits + 4)
+#define PRTB_ENTRIES   (1ul << mmu_pid_bits)
 
 /*
  * Power9 currently only support 64K partition table size.
index 20b1485..e2329db 100644 (file)
@@ -56,7 +56,7 @@ static inline pgd_t *radix__pgd_alloc(struct mm_struct *mm)
        return (pgd_t *)__get_free_page(pgtable_gfp_flags(mm, PGALLOC_GFP));
 #else
        struct page *page;
-       page = alloc_pages(pgtable_gfp_flags(mm, PGALLOC_GFP | __GFP_REPEAT),
+       page = alloc_pages(pgtable_gfp_flags(mm, PGALLOC_GFP | __GFP_RETRY_MAYFAIL),
                                4);
        if (!page)
                return NULL;
index c0737c8..d1da415 100644 (file)
@@ -1192,5 +1192,6 @@ static inline const int pud_pfn(pud_t pud)
        BUILD_BUG();
        return 0;
 }
+
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ */
index 487709f..544440b 100644 (file)
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
 extern void radix__mark_rodata_ro(void);
+extern void radix__mark_initmem_nx(void);
 #endif
 
 static inline unsigned long __radix_pte_update(pte_t *ptep, unsigned long clr,
index 0151af6..87fcc19 100644 (file)
@@ -18,7 +18,7 @@
 #include <asm/asm-offsets.h>
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 .macro EMIT_BUG_ENTRY addr,file,line,flags
-        .section __bug_table,"a"
+        .section __bug_table,"aw"
 5001:   PPC_LONG \addr, 5002f
         .short \line, \flags
         .org 5001b+BUG_ENTRY_SIZE
@@ -29,7 +29,7 @@
 .endm
 #else
 .macro EMIT_BUG_ENTRY addr,file,line,flags
-        .section __bug_table,"a"
+        .section __bug_table,"aw"
 5001:   PPC_LONG \addr
         .short \flags
         .org 5001b+BUG_ENTRY_SIZE
    sizeof(struct bug_entry), respectively */
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 #define _EMIT_BUG_ENTRY                                \
-       ".section __bug_table,\"a\"\n"          \
+       ".section __bug_table,\"aw\"\n"         \
        "2:\t" PPC_LONG "1b, %0\n"              \
        "\t.short %1, %2\n"                     \
        ".org 2b+%3\n"                          \
        ".previous\n"
 #else
 #define _EMIT_BUG_ENTRY                                \
-       ".section __bug_table,\"a\"\n"          \
+       ".section __bug_table,\"aw\"\n"         \
        "2:\t" PPC_LONG "1b\n"                  \
        "\t.short %2\n"                         \
        ".org 2b+%3\n"                          \
index da7e943..0c76675 100644 (file)
@@ -45,7 +45,7 @@ extern void set_context(unsigned long id, pgd_t *pgd);
 
 #ifdef CONFIG_PPC_BOOK3S_64
 extern void radix__switch_mmu_context(struct mm_struct *prev,
-                                    struct mm_struct *next);
+                                     struct mm_struct *next);
 static inline void switch_mmu_context(struct mm_struct *prev,
                                      struct mm_struct *next,
                                      struct task_struct *tsk)
@@ -67,6 +67,12 @@ extern void __destroy_context(unsigned long context_id);
 extern void mmu_context_init(void);
 #endif
 
+#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE) && defined(CONFIG_PPC_RADIX_MMU)
+extern void radix_kvm_prefetch_workaround(struct mm_struct *mm);
+#else
+static inline void radix_kvm_prefetch_workaround(struct mm_struct *mm) { }
+#endif
+
 extern void switch_cop(struct mm_struct *next);
 extern int use_cop(unsigned long acop, struct mm_struct *mm);
 extern void drop_cop(unsigned long acop, struct mm_struct *mm);
@@ -79,9 +85,13 @@ static inline void switch_mm_irqs_off(struct mm_struct *prev,
                                      struct mm_struct *next,
                                      struct task_struct *tsk)
 {
+       bool new_on_cpu = false;
+
        /* Mark this context has been used on the new CPU */
-       if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(next)))
+       if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(next))) {
                cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
+               new_on_cpu = true;
+       }
 
        /* 32-bit keeps track of the current PGDIR in the thread struct */
 #ifdef CONFIG_PPC32
@@ -109,6 +119,10 @@ static inline void switch_mm_irqs_off(struct mm_struct *prev,
        if (cpu_has_feature(CPU_FTR_ALTIVEC))
                asm volatile ("dssall");
 #endif /* CONFIG_ALTIVEC */
+
+       if (new_on_cpu)
+               radix_kvm_prefetch_workaround(next);
+
        /*
         * The actual HW switching method differs between the various
         * sub architectures. Out of line for now
index ff1ccb3..6f8e79c 100644 (file)
@@ -1,4 +1,15 @@
 #ifndef _ASM_NMI_H
 #define _ASM_NMI_H
 
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+extern void arch_touch_nmi_watchdog(void);
+
+extern void arch_trigger_cpumask_backtrace(const cpumask_t *mask,
+                                          bool exclude_self);
+#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
+
+#else
+static inline void arch_touch_nmi_watchdog(void) {}
+#endif
+
 #endif /* _ASM_NMI_H */
index ef930ba..3130a73 100644 (file)
@@ -876,6 +876,15 @@ struct OpalIoPhb4ErrorData {
 enum {
        OPAL_REINIT_CPUS_HILE_BE        = (1 << 0),
        OPAL_REINIT_CPUS_HILE_LE        = (1 << 1),
+
+       /* These two define the base MMU mode of the host on P9
+        *
+        * On P9 Nimbus DD2.0 and Cumlus (and later), KVM can still
+        * create hash guests in "radix" mode with care (full core
+        * switch only).
+        */
+       OPAL_REINIT_CPUS_MMU_HASH       = (1 << 2),
+       OPAL_REINIT_CPUS_MMU_RADIX      = (1 << 3),
 };
 
 typedef struct oppanel_line {
index dd01212..afae9a3 100644 (file)
@@ -80,6 +80,13 @@ unsigned long vmalloc_to_phys(void *vmalloc_addr);
 
 void pgtable_cache_add(unsigned shift, void (*ctor)(void *));
 void pgtable_cache_init(void);
+
+#ifdef CONFIG_STRICT_KERNEL_RWX
+void mark_initmem_nx(void);
+#else
+static inline void mark_initmem_nx(void) { }
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_PGTABLE_H */
index 7e50e47..a3b6575 100644 (file)
@@ -1303,7 +1303,7 @@ static inline void msr_check_and_clear(unsigned long bits)
                                "       .llong 0\n"                     \
                                ".previous"                             \
                        : "=r" (rval) \
-                       : "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL)); \
+                       : "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL) : "cr0"); \
                        rval;})
 #else
 #define mftb()         ({unsigned long rval;   \
index ebddb21..8ea9850 100644 (file)
@@ -55,6 +55,8 @@ struct smp_ops_t {
        int   (*cpu_bootable)(unsigned int nr);
 };
 
+extern void smp_flush_nmi_ipi(u64 delay_us);
+extern int smp_send_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us);
 extern void smp_send_debugger_break(void);
 extern void start_secondary_resume(void);
 extern void smp_generic_give_timebase(void);
index 4cf57f2..9c0e60c 100644 (file)
@@ -90,9 +90,6 @@
 #define __put_user_inatomic(x, ptr) \
        __put_user_nosleep((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
 
-#define __get_user_unaligned __get_user
-#define __put_user_unaligned __put_user
-
 extern long __put_user_bad(void);
 
 /*
index bfd609a..e3b1046 100644 (file)
 #define TIOCGPKT       _IOR('T', 0x38, int) /* Get packet mode state */
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
-#define TIOCGPTPEER    _IOR('T', 0x41, int) /* Safely open the slave */
+#define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
 
 #define TIOCSERCONFIG  0x5453
 #define TIOCSERGWILD   0x5454
index 0845eeb..4aa7c14 100644 (file)
@@ -38,6 +38,7 @@ obj-$(CONFIG_PPC64)           += setup_64.o sys_ppc32.o \
                                   signal_64.o ptrace32.o \
                                   paca.o nvram_64.o firmware.o
 obj-$(CONFIG_VDSO32)           += vdso32/
+obj-$(CONFIG_HARDLOCKUP_DETECTOR)      += watchdog.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += hw_breakpoint.o
 obj-$(CONFIG_PPC_BOOK3S_64)    += cpu_setup_ppc970.o cpu_setup_pa6t.o
 obj-$(CONFIG_PPC_BOOK3S_64)    += cpu_setup_power.o
index 10cb289..610955f 100644 (file)
@@ -218,13 +218,20 @@ __init_tlb_power8:
        ptesync
 1:     blr
 
+/*
+ * Flush the TLB in hash mode. Hash must flush with RIC=2 once for process
+ * and one for partition scope to clear process and partition table entries.
+ */
 __init_tlb_power9:
-       li      r6,POWER9_TLB_SETS_HASH
+       li      r6,POWER9_TLB_SETS_HASH - 1
        mtctr   r6
        li      r7,0xc00        /* IS field = 0b11 */
+       li      r8,0
        ptesync
-2:     tlbiel  r7
-       addi    r7,r7,0x1000
+       PPC_TLBIEL(7, 8, 2, 1, 0)
+       PPC_TLBIEL(7, 8, 2, 0, 0)
+2:     addi    r7,r7,0x1000
+       PPC_TLBIEL(7, 8, 0, 0, 0)
        bdnz    2b
        ptesync
 1:     blr
index 4c7656d..1df770e 100644 (file)
@@ -94,9 +94,6 @@ static void (*init_pmu_registers)(void);
 
 static void cpufeatures_flush_tlb(void)
 {
-       unsigned long rb;
-       unsigned int i, num_sets;
-
        /*
         * This is a temporary measure to keep equivalent TLB flush as the
         * cputable based setup code.
@@ -105,24 +102,15 @@ static void cpufeatures_flush_tlb(void)
        case PVR_POWER8:
        case PVR_POWER8E:
        case PVR_POWER8NVL:
-               num_sets = POWER8_TLB_SETS;
+               __flush_tlb_power8(POWER8_TLB_SETS);
                break;
        case PVR_POWER9:
-               num_sets = POWER9_TLB_SETS_HASH;
+               __flush_tlb_power9(POWER9_TLB_SETS_HASH);
                break;
        default:
-               num_sets = 1;
                pr_err("unknown CPU version for boot TLB flush\n");
                break;
        }
-
-       asm volatile("ptesync" : : : "memory");
-       rb = TLBIEL_INVAL_SET;
-       for (i = 0; i < num_sets; i++) {
-               asm volatile("tlbiel %0" : : "r" (rb));
-               rb += 1 << TLBIEL_INVAL_SET_SHIFT;
-       }
-       asm volatile("ptesync" : : : "memory");
 }
 
 static void __restore_cpu_cpufeatures(void)
index 4c18a5f..9029afd 100644 (file)
@@ -824,7 +824,7 @@ EXC_COMMON(trap_0b_common, 0xb00, unknown_exception)
  * r3 volatile parameter and return value for status
  * r4-r10 volatile input and output value
  * r11 volatile hypercall number and output value
- * r12 volatile
+ * r12 volatile input and output value
  * r13-r31 nonvolatile
  * LR nonvolatile
  * CTR volatile
@@ -834,25 +834,26 @@ EXC_COMMON(trap_0b_common, 0xb00, unknown_exception)
  * Other registers nonvolatile
  *
  * The intersection of volatile registers that don't contain possible
- * inputs is: r12, cr0, xer, ctr. We may use these as scratch regs
- * upon entry without saving.
+ * inputs is: cr0, xer, ctr. We may use these as scratch regs upon entry
+ * without saving, though xer is not a good idea to use, as hardware may
+ * interpret some bits so it may be costly to change them.
  */
 #ifdef CONFIG_KVM_BOOK3S_64_HANDLER
        /*
         * There is a little bit of juggling to get syscall and hcall
-        * working well. Save r10 in ctr to be restored in case it is a
-        * hcall.
+        * working well. Save r13 in ctr to avoid using SPRG scratch
+        * register.
         *
         * Userspace syscalls have already saved the PPR, hcalls must save
         * it before setting HMT_MEDIUM.
         */
 #define SYSCALL_KVMTEST                                                        \
-       mr      r12,r13;                                                \
+       mtctr   r13;                                                    \
        GET_PACA(r13);                                                  \
-       mtctr   r10;                                                    \
+       std     r10,PACA_EXGEN+EX_R10(r13);                             \
        KVMTEST_PR(0xc00); /* uses r10, branch to do_kvm_0xc00_system_call */ \
        HMT_MEDIUM;                                                     \
-       mr      r9,r12;                                                 \
+       mfctr   r9;
 
 #else
 #define SYSCALL_KVMTEST                                                        \
@@ -935,8 +936,8 @@ EXC_VIRT_END(system_call, 0x4c00, 0x100)
         * This is a hcall, so register convention is as above, with these
         * differences:
         * r13 = PACA
-        * r12 = orig r13
-        * ctr = orig r10
+        * ctr = orig r13
+        * orig r10 saved in PACA
         */
 TRAMP_KVM_BEGIN(do_kvm_0xc00)
         /*
@@ -944,14 +945,13 @@ TRAMP_KVM_BEGIN(do_kvm_0xc00)
          * HMT_MEDIUM. That allows the KVM code to save that value into the
          * guest state (it is the guest's PPR value).
          */
-       OPT_GET_SPR(r0, SPRN_PPR, CPU_FTR_HAS_PPR)
+       OPT_GET_SPR(r10, SPRN_PPR, CPU_FTR_HAS_PPR)
        HMT_MEDIUM
-       OPT_SAVE_REG_TO_PACA(PACA_EXGEN+EX_PPR, r0, CPU_FTR_HAS_PPR)
+       OPT_SAVE_REG_TO_PACA(PACA_EXGEN+EX_PPR, r10, CPU_FTR_HAS_PPR)
        mfctr   r10
-       SET_SCRATCH0(r12)
+       SET_SCRATCH0(r10)
        std     r9,PACA_EXGEN+EX_R9(r13)
        mfcr    r9
-       std     r10,PACA_EXGEN+EX_R10(r13)
        KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xc00)
 #endif
 
@@ -1314,6 +1314,31 @@ EXC_REAL_NONE(0x1800, 0x100)
 EXC_VIRT_NONE(0x5800, 0x100)
 #endif
 
+#if defined(CONFIG_HARDLOCKUP_DETECTOR) && defined(CONFIG_HAVE_HARDLOCKUP_DETECTOR_ARCH)
+
+#define MASKED_DEC_HANDLER_LABEL 3f
+
+#define MASKED_DEC_HANDLER(_H)                         \
+3: /* soft-nmi */                                      \
+       std     r12,PACA_EXGEN+EX_R12(r13);             \
+       GET_SCRATCH0(r10);                              \
+       std     r10,PACA_EXGEN+EX_R13(r13);             \
+       EXCEPTION_PROLOG_PSERIES_1(soft_nmi_common, _H)
+
+EXC_COMMON_BEGIN(soft_nmi_common)
+       mr      r10,r1
+       ld      r1,PACAEMERGSP(r13)
+       ld      r1,PACA_NMI_EMERG_SP(r13)
+       subi    r1,r1,INT_FRAME_SIZE
+       EXCEPTION_COMMON_NORET_STACK(PACA_EXGEN, 0x900,
+                       system_reset, soft_nmi_interrupt,
+                       ADD_NVGPRS;ADD_RECONCILE)
+       b       ret_from_except
+
+#else
+#define MASKED_DEC_HANDLER_LABEL 2f /* normal return */
+#define MASKED_DEC_HANDLER(_H)
+#endif
 
 /*
  * An interrupt came in while soft-disabled. We set paca->irq_happened, then:
@@ -1336,7 +1361,7 @@ masked_##_H##interrupt:                                   \
        lis     r10,0x7fff;                             \
        ori     r10,r10,0xffff;                         \
        mtspr   SPRN_DEC,r10;                           \
-       b       2f;                                     \
+       b       MASKED_DEC_HANDLER_LABEL;               \
 1:     cmpwi   r10,PACA_IRQ_DBELL;                     \
        beq     2f;                                     \
        cmpwi   r10,PACA_IRQ_HMI;                       \
@@ -1351,7 +1376,8 @@ masked_##_H##interrupt:                                   \
        ld      r11,PACA_EXGEN+EX_R11(r13);             \
        GET_SCRATCH0(r13);                              \
        ##_H##rfid;                                     \
-       b       .
+       b       .;                                      \
+       MASKED_DEC_HANDLER(_H)
 
 /*
  * Real mode exceptions actually use this too, but alternate
index 3079518..dc0c49c 100644 (file)
@@ -999,8 +999,7 @@ static int fadump_create_elfcore_headers(char *bufp)
 
        phdr->p_paddr   = fadump_relocate(paddr_vmcoreinfo_note());
        phdr->p_offset  = phdr->p_paddr;
-       phdr->p_memsz   = vmcoreinfo_max_size;
-       phdr->p_filesz  = vmcoreinfo_max_size;
+       phdr->p_memsz   = phdr->p_filesz = VMCOREINFO_NOTE_SIZE;
 
        /* Increment number of program headers. */
        (elf->e_phnum)++;
index 5adb390..516ebef 100644 (file)
@@ -30,6 +30,7 @@
  * Use unused space in the interrupt stack to save and restore
  * registers for winkle support.
  */
+#define _MMCR0 GPR0
 #define _SDR1  GPR3
 #define _PTCR  GPR3
 #define _RPR   GPR4
@@ -272,6 +273,14 @@ power_enter_stop:
        b       pnv_wakeup_noloss
 
 .Lhandle_esl_ec_set:
+       /*
+        * POWER9 DD2 can incorrectly set PMAO when waking up after a
+        * state-loss idle. Saving and restoring MMCR0 over idle is a
+        * workaround.
+        */
+       mfspr   r4,SPRN_MMCR0
+       std     r4,_MMCR0(r1)
+
 /*
  * Check if the requested state is a deep idle state.
  */
@@ -450,10 +459,14 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_300)
 pnv_restore_hyp_resource_arch300:
        /*
         * Workaround for POWER9, if we lost resources, the ERAT
-        * might have been mixed up and needs flushing.
+        * might have been mixed up and needs flushing. We also need
+        * to reload MMCR0 (see comment above).
         */
        blt     cr3,1f
        PPC_INVALIDATE_ERAT
+       ld      r1,PACAR1(r13)
+       ld      r4,_MMCR0(r1)
+       mtspr   SPRN_MMCR0,r4
 1:
        /*
         * POWER ISA 3. Use PSSCR to determine if we
index 9ad37f8..1086ea3 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/kvm_para.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/nmi.h> /* hardlockup_detector_disable() */
 
 #include <asm/reg.h>
 #include <asm/sections.h>
@@ -718,6 +719,12 @@ static __init void kvm_free_tmp(void)
 
 static int __init kvm_guest_init(void)
 {
+       /*
+        * The hardlockup detector is likely to get false positives in
+        * KVM guests, so disable it by default.
+        */
+       hardlockup_detector_disable();
+
        if (!kvm_para_available())
                goto free_tmp;
 
index d24e689..b76ca19 100644 (file)
@@ -53,6 +53,60 @@ static void flush_tlb_206(unsigned int num_sets, unsigned int action)
        asm volatile("ptesync" : : : "memory");
 }
 
+static void flush_tlb_300(unsigned int num_sets, unsigned int action)
+{
+       unsigned long rb;
+       unsigned int i;
+       unsigned int r;
+
+       switch (action) {
+       case TLB_INVAL_SCOPE_GLOBAL:
+               rb = TLBIEL_INVAL_SET;
+               break;
+       case TLB_INVAL_SCOPE_LPID:
+               rb = TLBIEL_INVAL_SET_LPID;
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       asm volatile("ptesync" : : : "memory");
+
+       if (early_radix_enabled())
+               r = 1;
+       else
+               r = 0;
+
+       /*
+        * First flush table/PWC caches with set 0, then flush the
+        * rest of the sets, partition scope. Radix must then do it
+        * all again with process scope. Hash just has to flush
+        * process table.
+        */
+       asm volatile(PPC_TLBIEL(%0, %1, %2, %3, %4) : :
+                       "r"(rb), "r"(0), "i"(2), "i"(0), "r"(r));
+       for (i = 1; i < num_sets; i++) {
+               unsigned long set = i * (1<<TLBIEL_INVAL_SET_SHIFT);
+
+               asm volatile(PPC_TLBIEL(%0, %1, %2, %3, %4) : :
+                               "r"(rb+set), "r"(0), "i"(2), "i"(0), "r"(r));
+       }
+
+       asm volatile(PPC_TLBIEL(%0, %1, %2, %3, %4) : :
+                       "r"(rb), "r"(0), "i"(2), "i"(1), "r"(r));
+       if (early_radix_enabled()) {
+               for (i = 1; i < num_sets; i++) {
+                       unsigned long set = i * (1<<TLBIEL_INVAL_SET_SHIFT);
+
+                       asm volatile(PPC_TLBIEL(%0, %1, %2, %3, %4) : :
+                               "r"(rb+set), "r"(0), "i"(2), "i"(1), "r"(r));
+               }
+       }
+
+       asm volatile("ptesync" : : : "memory");
+}
+
 /*
  * Generic routines to flush TLB on POWER processors. These routines
  * are used as flush_tlb hook in the cpu_spec.
@@ -79,7 +133,7 @@ void __flush_tlb_power9(unsigned int action)
        else
                num_sets = POWER9_TLB_SETS_HASH;
 
-       flush_tlb_206(num_sets, action);
+       flush_tlb_300(num_sets, action);
 }
 
 
index c119044..8ac0bd2 100644 (file)
@@ -614,6 +614,18 @@ _GLOBAL(kexec_sequence)
        li      r0,0
        std     r0,16(r1)
 
+BEGIN_FTR_SECTION
+       /*
+        * This is the best time to turn AMR/IAMR off.
+        * key 0 is used in radix for supervisor<->user
+        * protection, but on hash key 0 is reserved
+        * ideally we want to enter with a clean state.
+        * NOTE, we rely on r0 being 0 from above.
+        */
+       mtspr   SPRN_IAMR,r0
+       mtspr   SPRN_AMOR,r0
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
+
        /* save regs for local vars on new stack.
         * yes, we won't go back, but ...
         */
index dd8a04f..613f79f 100644 (file)
@@ -15,6 +15,9 @@
 
 #undef DEBUG_PROM
 
+/* we cannot use FORTIFY as it brings in new symbols */
+#define __NO_FORTIFY
+
 #include <stdarg.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
index 4640f6d..af23d4b 100644 (file)
@@ -751,22 +751,3 @@ unsigned long memory_block_size_bytes(void)
 struct ppc_pci_io ppc_pci_io;
 EXPORT_SYMBOL(ppc_pci_io);
 #endif
-
-#ifdef CONFIG_HARDLOCKUP_DETECTOR
-u64 hw_nmi_get_sample_period(int watchdog_thresh)
-{
-       return ppc_proc_freq * watchdog_thresh;
-}
-
-/*
- * The hardlockup detector breaks PMU event based branches and is likely
- * to get false positives in KVM guests, so disable it by default.
- */
-static int __init disable_hardlockup_detector(void)
-{
-       hardlockup_detector_disable();
-
-       return 0;
-}
-early_initcall(disable_hardlockup_detector);
-#endif
index c6b8bac..997c88d 100644 (file)
@@ -435,13 +435,31 @@ static void do_smp_send_nmi_ipi(int cpu)
        }
 }
 
+void smp_flush_nmi_ipi(u64 delay_us)
+{
+       unsigned long flags;
+
+       nmi_ipi_lock_start(&flags);
+       while (nmi_ipi_busy_count) {
+               nmi_ipi_unlock_end(&flags);
+               udelay(1);
+               if (delay_us) {
+                       delay_us--;
+                       if (!delay_us)
+                               return;
+               }
+               nmi_ipi_lock_start(&flags);
+       }
+       nmi_ipi_unlock_end(&flags);
+}
+
 /*
  * - cpu is the target CPU (must not be this CPU), or NMI_IPI_ALL_OTHERS.
  * - fn is the target callback function.
  * - delay_us > 0 is the delay before giving up waiting for targets to
  *   enter the handler, == 0 specifies indefinite delay.
  */
-static int smp_send_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us)
+int smp_send_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us)
 {
        unsigned long flags;
        int me = raw_smp_processor_id();
diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c
new file mode 100644 (file)
index 0000000..b67f8b0
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Watchdog support on powerpc systems.
+ *
+ * Copyright 2017, IBM Corporation.
+ *
+ * This uses code from arch/sparc/kernel/nmi.c and kernel/watchdog.c
+ */
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/percpu.h>
+#include <linux/cpu.h>
+#include <linux/nmi.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/kprobes.h>
+#include <linux/hardirq.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/kdebug.h>
+#include <linux/sched/debug.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+
+#include <asm/paca.h>
+
+/*
+ * The watchdog has a simple timer that runs on each CPU, once per timer
+ * period. This is the heartbeat.
+ *
+ * Then there are checks to see if the heartbeat has not triggered on a CPU
+ * for the panic timeout period. Currently the watchdog only supports an
+ * SMP check, so the heartbeat only turns on when we have 2 or more CPUs.
+ *
+ * This is not an NMI watchdog, but Linux uses that name for a generic
+ * watchdog in some cases, so NMI gets used in some places.
+ */
+
+static cpumask_t wd_cpus_enabled __read_mostly;
+
+static u64 wd_panic_timeout_tb __read_mostly; /* timebase ticks until panic */
+static u64 wd_smp_panic_timeout_tb __read_mostly; /* panic other CPUs */
+
+static u64 wd_timer_period_ms __read_mostly;  /* interval between heartbeat */
+
+static DEFINE_PER_CPU(struct timer_list, wd_timer);
+static DEFINE_PER_CPU(u64, wd_timer_tb);
+
+/*
+ * These are for the SMP checker. CPUs clear their pending bit in their
+ * heartbeat. If the bitmask becomes empty, the time is noted and the
+ * bitmask is refilled.
+ *
+ * All CPUs clear their bit in the pending mask every timer period.
+ * Once all have cleared, the time is noted and the bits are reset.
+ * If the time since all clear was greater than the panic timeout,
+ * we can panic with the list of stuck CPUs.
+ *
+ * This will work best with NMI IPIs for crash code so the stuck CPUs
+ * can be pulled out to get their backtraces.
+ */
+static unsigned long __wd_smp_lock;
+static cpumask_t wd_smp_cpus_pending;
+static cpumask_t wd_smp_cpus_stuck;
+static u64 wd_smp_last_reset_tb;
+
+static inline void wd_smp_lock(unsigned long *flags)
+{
+       /*
+        * Avoid locking layers if possible.
+        * This may be called from low level interrupt handlers at some
+        * point in future.
+        */
+       local_irq_save(*flags);
+       while (unlikely(test_and_set_bit_lock(0, &__wd_smp_lock)))
+               cpu_relax();
+}
+
+static inline void wd_smp_unlock(unsigned long *flags)
+{
+       clear_bit_unlock(0, &__wd_smp_lock);
+       local_irq_restore(*flags);
+}
+
+static void wd_lockup_ipi(struct pt_regs *regs)
+{
+       pr_emerg("Watchdog CPU:%d Hard LOCKUP\n", raw_smp_processor_id());
+       print_modules();
+       print_irqtrace_events(current);
+       if (regs)
+               show_regs(regs);
+       else
+               dump_stack();
+
+       if (hardlockup_panic)
+               nmi_panic(regs, "Hard LOCKUP");
+}
+
+static void set_cpu_stuck(int cpu, u64 tb)
+{
+       cpumask_set_cpu(cpu, &wd_smp_cpus_stuck);
+       cpumask_clear_cpu(cpu, &wd_smp_cpus_pending);
+       if (cpumask_empty(&wd_smp_cpus_pending)) {
+               wd_smp_last_reset_tb = tb;
+               cpumask_andnot(&wd_smp_cpus_pending,
+                               &wd_cpus_enabled,
+                               &wd_smp_cpus_stuck);
+       }
+}
+
+static void watchdog_smp_panic(int cpu, u64 tb)
+{
+       unsigned long flags;
+       int c;
+
+       wd_smp_lock(&flags);
+       /* Double check some things under lock */
+       if ((s64)(tb - wd_smp_last_reset_tb) < (s64)wd_smp_panic_timeout_tb)
+               goto out;
+       if (cpumask_test_cpu(cpu, &wd_smp_cpus_pending))
+               goto out;
+       if (cpumask_weight(&wd_smp_cpus_pending) == 0)
+               goto out;
+
+       pr_emerg("Watchdog CPU:%d detected Hard LOCKUP other CPUS:%*pbl\n",
+                       cpu, cpumask_pr_args(&wd_smp_cpus_pending));
+
+       /*
+        * Try to trigger the stuck CPUs.
+        */
+       for_each_cpu(c, &wd_smp_cpus_pending) {
+               if (c == cpu)
+                       continue;
+               smp_send_nmi_ipi(c, wd_lockup_ipi, 1000000);
+       }
+       smp_flush_nmi_ipi(1000000);
+
+       /* Take the stuck CPU out of the watch group */
+       for_each_cpu(c, &wd_smp_cpus_pending)
+               set_cpu_stuck(c, tb);
+
+out:
+       wd_smp_unlock(&flags);
+
+       printk_safe_flush();
+       /*
+        * printk_safe_flush() seems to require another print
+        * before anything actually goes out to console.
+        */
+       if (sysctl_hardlockup_all_cpu_backtrace)
+               trigger_allbutself_cpu_backtrace();
+
+       if (hardlockup_panic)
+               nmi_panic(NULL, "Hard LOCKUP");
+}
+
+static void wd_smp_clear_cpu_pending(int cpu, u64 tb)
+{
+       if (!cpumask_test_cpu(cpu, &wd_smp_cpus_pending)) {
+               if (unlikely(cpumask_test_cpu(cpu, &wd_smp_cpus_stuck))) {
+                       unsigned long flags;
+
+                       pr_emerg("Watchdog CPU:%d became unstuck\n", cpu);
+                       wd_smp_lock(&flags);
+                       cpumask_clear_cpu(cpu, &wd_smp_cpus_stuck);
+                       wd_smp_unlock(&flags);
+               }
+               return;
+       }
+       cpumask_clear_cpu(cpu, &wd_smp_cpus_pending);
+       if (cpumask_empty(&wd_smp_cpus_pending)) {
+               unsigned long flags;
+
+               wd_smp_lock(&flags);
+               if (cpumask_empty(&wd_smp_cpus_pending)) {
+                       wd_smp_last_reset_tb = tb;
+                       cpumask_andnot(&wd_smp_cpus_pending,
+                                       &wd_cpus_enabled,
+                                       &wd_smp_cpus_stuck);
+               }
+               wd_smp_unlock(&flags);
+       }
+}
+
+static void watchdog_timer_interrupt(int cpu)
+{
+       u64 tb = get_tb();
+
+       per_cpu(wd_timer_tb, cpu) = tb;
+
+       wd_smp_clear_cpu_pending(cpu, tb);
+
+       if ((s64)(tb - wd_smp_last_reset_tb) >= (s64)wd_smp_panic_timeout_tb)
+               watchdog_smp_panic(cpu, tb);
+}
+
+void soft_nmi_interrupt(struct pt_regs *regs)
+{
+       unsigned long flags;
+       int cpu = raw_smp_processor_id();
+       u64 tb;
+
+       if (!cpumask_test_cpu(cpu, &wd_cpus_enabled))
+               return;
+
+       nmi_enter();
+       tb = get_tb();
+       if (tb - per_cpu(wd_timer_tb, cpu) >= wd_panic_timeout_tb) {
+               per_cpu(wd_timer_tb, cpu) = tb;
+
+               wd_smp_lock(&flags);
+               if (cpumask_test_cpu(cpu, &wd_smp_cpus_stuck)) {
+                       wd_smp_unlock(&flags);
+                       goto out;
+               }
+               set_cpu_stuck(cpu, tb);
+
+               pr_emerg("Watchdog CPU:%d Hard LOCKUP\n", cpu);
+               print_modules();
+               print_irqtrace_events(current);
+               if (regs)
+                       show_regs(regs);
+               else
+                       dump_stack();
+
+               wd_smp_unlock(&flags);
+
+               if (sysctl_hardlockup_all_cpu_backtrace)
+                       trigger_allbutself_cpu_backtrace();
+
+               if (hardlockup_panic)
+                       nmi_panic(regs, "Hard LOCKUP");
+       }
+       if (wd_panic_timeout_tb < 0x7fffffff)
+               mtspr(SPRN_DEC, wd_panic_timeout_tb);
+
+out:
+       nmi_exit();
+}
+
+static void wd_timer_reset(unsigned int cpu, struct timer_list *t)
+{
+       t->expires = jiffies + msecs_to_jiffies(wd_timer_period_ms);
+       if (wd_timer_period_ms > 1000)
+               t->expires = __round_jiffies_up(t->expires, cpu);
+       add_timer_on(t, cpu);
+}
+
+static void wd_timer_fn(unsigned long data)
+{
+       struct timer_list *t = this_cpu_ptr(&wd_timer);
+       int cpu = smp_processor_id();
+
+       watchdog_timer_interrupt(cpu);
+
+       wd_timer_reset(cpu, t);
+}
+
+void arch_touch_nmi_watchdog(void)
+{
+       int cpu = smp_processor_id();
+
+       watchdog_timer_interrupt(cpu);
+}
+EXPORT_SYMBOL(arch_touch_nmi_watchdog);
+
+static void start_watchdog_timer_on(unsigned int cpu)
+{
+       struct timer_list *t = per_cpu_ptr(&wd_timer, cpu);
+
+       per_cpu(wd_timer_tb, cpu) = get_tb();
+
+       setup_pinned_timer(t, wd_timer_fn, 0);
+       wd_timer_reset(cpu, t);
+}
+
+static void stop_watchdog_timer_on(unsigned int cpu)
+{
+       struct timer_list *t = per_cpu_ptr(&wd_timer, cpu);
+
+       del_timer_sync(t);
+}
+
+static int start_wd_on_cpu(unsigned int cpu)
+{
+       if (cpumask_test_cpu(cpu, &wd_cpus_enabled)) {
+               WARN_ON(1);
+               return 0;
+       }
+
+       if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED))
+               return 0;
+
+       if (watchdog_suspended)
+               return 0;
+
+       if (!cpumask_test_cpu(cpu, &watchdog_cpumask))
+               return 0;
+
+       cpumask_set_cpu(cpu, &wd_cpus_enabled);
+       if (cpumask_weight(&wd_cpus_enabled) == 1) {
+               cpumask_set_cpu(cpu, &wd_smp_cpus_pending);
+               wd_smp_last_reset_tb = get_tb();
+       }
+       smp_wmb();
+       start_watchdog_timer_on(cpu);
+
+       return 0;
+}
+
+static int stop_wd_on_cpu(unsigned int cpu)
+{
+       if (!cpumask_test_cpu(cpu, &wd_cpus_enabled))
+               return 0; /* Can happen in CPU unplug case */
+
+       stop_watchdog_timer_on(cpu);
+
+       cpumask_clear_cpu(cpu, &wd_cpus_enabled);
+       wd_smp_clear_cpu_pending(cpu, get_tb());
+
+       return 0;
+}
+
+static void watchdog_calc_timeouts(void)
+{
+       wd_panic_timeout_tb = watchdog_thresh * ppc_tb_freq;
+
+       /* Have the SMP detector trigger a bit later */
+       wd_smp_panic_timeout_tb = wd_panic_timeout_tb * 3 / 2;
+
+       /* 2/5 is the factor that the perf based detector uses */
+       wd_timer_period_ms = watchdog_thresh * 1000 * 2 / 5;
+}
+
+void watchdog_nmi_reconfigure(void)
+{
+       int cpu;
+
+       watchdog_calc_timeouts();
+
+       for_each_cpu(cpu, &wd_cpus_enabled)
+               stop_wd_on_cpu(cpu);
+
+       for_each_cpu_and(cpu, cpu_online_mask, &watchdog_cpumask)
+               start_wd_on_cpu(cpu);
+}
+
+/*
+ * This runs after lockup_detector_init() which sets up watchdog_cpumask.
+ */
+static int __init powerpc_watchdog_init(void)
+{
+       int err;
+
+       watchdog_calc_timeouts();
+
+       err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powerpc/watchdog:online",
+                               start_wd_on_cpu, stop_wd_on_cpu);
+       if (err < 0)
+               pr_warn("Watchdog could not be initialized");
+
+       return 0;
+}
+arch_initcall(powerpc_watchdog_init);
+
+static void handle_backtrace_ipi(struct pt_regs *regs)
+{
+       nmi_cpu_backtrace(regs);
+}
+
+static void raise_backtrace_ipi(cpumask_t *mask)
+{
+       unsigned int cpu;
+
+       for_each_cpu(cpu, mask) {
+               if (cpu == smp_processor_id())
+                       handle_backtrace_ipi(NULL);
+               else
+                       smp_send_nmi_ipi(cpu, handle_backtrace_ipi, 1000000);
+       }
+}
+
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
+{
+       nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_backtrace_ipi);
+}
index 710e491..b42812e 100644 (file)
@@ -93,7 +93,7 @@ int kvmppc_allocate_hpt(struct kvm_hpt_info *info, u32 order)
        }
 
        if (!hpt)
-               hpt = __get_free_pages(GFP_KERNEL|__GFP_ZERO|__GFP_REPEAT
+               hpt = __get_free_pages(GFP_KERNEL|__GFP_ZERO|__GFP_RETRY_MAYFAIL
                                       |__GFP_NOWARN, order - PAGE_SHIFT);
 
        if (!hpt)
@@ -164,8 +164,10 @@ long kvmppc_alloc_reset_hpt(struct kvm *kvm, int order)
                goto out;
        }
 
-       if (kvm->arch.hpt.virt)
+       if (kvm->arch.hpt.virt) {
                kvmppc_free_hpt(&kvm->arch.hpt);
+               kvmppc_rmap_reset(kvm);
+       }
 
        err = kvmppc_allocate_hpt(&info, order);
        if (err < 0)
index 0b436df..359c79c 100644 (file)
@@ -3211,6 +3211,8 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        run->fail_entry.hardware_entry_failure_reason = 0;
                        return -EINVAL;
                }
+               /* Enable TM so we can read the TM SPRs */
+               mtmsr(mfmsr() | MSR_TM);
                current->thread.tm_tfhar = mfspr(SPRN_TFHAR);
                current->thread.tm_tfiar = mfspr(SPRN_TFIAR);
                current->thread.tm_texasr = mfspr(SPRN_TEXASR);
index cb44065..c52184a 100644 (file)
@@ -1443,12 +1443,14 @@ mc_cont:
        ori     r6,r6,1
        mtspr   SPRN_CTRLT,r6
 4:
-       /* Read the guest SLB and save it away */
+       /* Check if we are running hash or radix and store it in cr2 */
        ld      r5, VCPU_KVM(r9)
        lbz     r0, KVM_RADIX(r5)
-       cmpwi   r0, 0
+       cmpwi   cr2,r0,0
+
+       /* Read the guest SLB and save it away */
        li      r5, 0
-       bne     3f                      /* for radix, save 0 entries */
+       bne     cr2, 3f                 /* for radix, save 0 entries */
        lwz     r0,VCPU_SLB_NR(r9)      /* number of entries in SLB */
        mtctr   r0
        li      r6,0
@@ -1712,11 +1714,6 @@ BEGIN_FTR_SECTION_NESTED(96)
 END_FTR_SECTION_NESTED(CPU_FTR_ARCH_300, 0, 96)
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 22:
-       /* Clear out SLB */
-       li      r5,0
-       slbmte  r5,r5
-       slbia
-       ptesync
 
        /* Restore host values of some registers */
 BEGIN_FTR_SECTION
@@ -1737,10 +1734,56 @@ BEGIN_FTR_SECTION
        mtspr   SPRN_PID, r7
        mtspr   SPRN_IAMR, r8
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
+
+#ifdef CONFIG_PPC_RADIX_MMU
+       /*
+        * Are we running hash or radix ?
+        */
+       beq     cr2,3f
+
+       /* Radix: Handle the case where the guest used an illegal PID */
+       LOAD_REG_ADDR(r4, mmu_base_pid)
+       lwz     r3, VCPU_GUEST_PID(r9)
+       lwz     r5, 0(r4)
+       cmpw    cr0,r3,r5
+       blt     2f
+
+       /*
+        * Illegal PID, the HW might have prefetched and cached in the TLB
+        * some translations for the  LPID 0 / guest PID combination which
+        * Linux doesn't know about, so we need to flush that PID out of
+        * the TLB. First we need to set LPIDR to 0 so tlbiel applies to
+        * the right context.
+       */
+       li      r0,0
+       mtspr   SPRN_LPID,r0
+       isync
+
+       /* Then do a congruence class local flush */
+       ld      r6,VCPU_KVM(r9)
+       lwz     r0,KVM_TLB_SETS(r6)
+       mtctr   r0
+       li      r7,0x400                /* IS field = 0b01 */
+       ptesync
+       sldi    r0,r3,32                /* RS has PID */
+1:     PPC_TLBIEL(7,0,2,1,1)           /* RIC=2, PRS=1, R=1 */
+       addi    r7,r7,0x1000
+       bdnz    1b
+       ptesync
+
+2:     /* Flush the ERAT on radix P9 DD1 guest exit */
 BEGIN_FTR_SECTION
        PPC_INVALIDATE_ERAT
 END_FTR_SECTION_IFSET(CPU_FTR_POWER9_DD1)
+       b       4f
+#endif /* CONFIG_PPC_RADIX_MMU */
 
+       /* Hash: clear out SLB */
+3:     li      r5,0
+       slbmte  r5,r5
+       slbia
+       ptesync
+4:
        /*
         * POWER7/POWER8 guest -> host partition switch code.
         * We don't have to lock against tlbies but we do
index f391770..41cf5ae 100644 (file)
@@ -233,192 +233,192 @@ static long calc_offset(struct fixup_entry *entry, unsigned int *p)
 
 static void test_basic_patching(void)
 {
-       extern unsigned int ftr_fixup_test1;
-       extern unsigned int end_ftr_fixup_test1;
-       extern unsigned int ftr_fixup_test1_orig;
-       extern unsigned int ftr_fixup_test1_expected;
-       int size = &end_ftr_fixup_test1 - &ftr_fixup_test1;
+       extern unsigned int ftr_fixup_test1[];
+       extern unsigned int end_ftr_fixup_test1[];
+       extern unsigned int ftr_fixup_test1_orig[];
+       extern unsigned int ftr_fixup_test1_expected[];
+       int size = end_ftr_fixup_test1 - ftr_fixup_test1;
 
        fixup.value = fixup.mask = 8;
-       fixup.start_off = calc_offset(&fixup, &ftr_fixup_test1 + 1);
-       fixup.end_off = calc_offset(&fixup, &ftr_fixup_test1 + 2);
+       fixup.start_off = calc_offset(&fixup, ftr_fixup_test1 + 1);
+       fixup.end_off = calc_offset(&fixup, ftr_fixup_test1 + 2);
        fixup.alt_start_off = fixup.alt_end_off = 0;
 
        /* Sanity check */
-       check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
+       check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0);
 
        /* Check we don't patch if the value matches */
        patch_feature_section(8, &fixup);
-       check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
+       check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0);
 
        /* Check we do patch if the value doesn't match */
        patch_feature_section(0, &fixup);
-       check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_expected, size) == 0);
+       check(memcmp(ftr_fixup_test1, ftr_fixup_test1_expected, size) == 0);
 
        /* Check we do patch if the mask doesn't match */
-       memcpy(&ftr_fixup_test1, &ftr_fixup_test1_orig, size);
-       check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
+       memcpy(ftr_fixup_test1, ftr_fixup_test1_orig, size);
+       check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0);
        patch_feature_section(~8, &fixup);
-       check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_expected, size) == 0);
+       check(memcmp(ftr_fixup_test1, ftr_fixup_test1_expected, size) == 0);
 }
 
 static void test_alternative_patching(void)
 {
-       extern unsigned int ftr_fixup_test2;
-       extern unsigned int end_ftr_fixup_test2;
-       extern unsigned int ftr_fixup_test2_orig;
-       extern unsigned int ftr_fixup_test2_alt;
-       extern unsigned int ftr_fixup_test2_expected;
-       int size = &end_ftr_fixup_test2 - &ftr_fixup_test2;
+       extern unsigned int ftr_fixup_test2[];
+       extern unsigned int end_ftr_fixup_test2[];
+       extern unsigned int ftr_fixup_test2_orig[];
+       extern unsigned int ftr_fixup_test2_alt[];
+       extern unsigned int ftr_fixup_test2_expected[];
+       int size = end_ftr_fixup_test2 - ftr_fixup_test2;
 
        fixup.value = fixup.mask = 0xF;
-       fixup.start_off = calc_offset(&fixup, &ftr_fixup_test2 + 1);
-       fixup.end_off = calc_offset(&fixup, &ftr_fixup_test2 + 2);
-       fixup.alt_start_off = calc_offset(&fixup, &ftr_fixup_test2_alt);
-       fixup.alt_end_off = calc_offset(&fixup, &ftr_fixup_test2_alt + 1);
+       fixup.start_off = calc_offset(&fixup, ftr_fixup_test2 + 1);
+       fixup.end_off = calc_offset(&fixup, ftr_fixup_test2 + 2);
+       fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test2_alt);
+       fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test2_alt + 1);
 
        /* Sanity check */
-       check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0);
+       check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0);
 
        /* Check we don't patch if the value matches */
        patch_feature_section(0xF, &fixup);
-       check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0);
+       check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0);
 
        /* Check we do patch if the value doesn't match */
        patch_feature_section(0, &fixup);
-       check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_expected, size) == 0);
+       check(memcmp(ftr_fixup_test2, ftr_fixup_test2_expected, size) == 0);
 
        /* Check we do patch if the mask doesn't match */
-       memcpy(&ftr_fixup_test2, &ftr_fixup_test2_orig, size);
-       check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0);
+       memcpy(ftr_fixup_test2, ftr_fixup_test2_orig, size);
+       check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0);
        patch_feature_section(~0xF, &fixup);
-       check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_expected, size) == 0);
+       check(memcmp(ftr_fixup_test2, ftr_fixup_test2_expected, size) == 0);
 }
 
 static void test_alternative_case_too_big(void)
 {
-       extern unsigned int ftr_fixup_test3;
-       extern unsigned int end_ftr_fixup_test3;
-       extern unsigned int ftr_fixup_test3_orig;
-       extern unsigned int ftr_fixup_test3_alt;
-       int size = &end_ftr_fixup_test3 - &ftr_fixup_test3;
+       extern unsigned int ftr_fixup_test3[];
+       extern unsigned int end_ftr_fixup_test3[];
+       extern unsigned int ftr_fixup_test3_orig[];
+       extern unsigned int ftr_fixup_test3_alt[];
+       int size = end_ftr_fixup_test3 - ftr_fixup_test3;
 
        fixup.value = fixup.mask = 0xC;
-       fixup.start_off = calc_offset(&fixup, &ftr_fixup_test3 + 1);
-       fixup.end_off = calc_offset(&fixup, &ftr_fixup_test3 + 2);
-       fixup.alt_start_off = calc_offset(&fixup, &ftr_fixup_test3_alt);
-       fixup.alt_end_off = calc_offset(&fixup, &ftr_fixup_test3_alt + 2);
+       fixup.start_off = calc_offset(&fixup, ftr_fixup_test3 + 1);
+       fixup.end_off = calc_offset(&fixup, ftr_fixup_test3 + 2);
+       fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test3_alt);
+       fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test3_alt + 2);
 
        /* Sanity check */
-       check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
+       check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0);
 
        /* Expect nothing to be patched, and the error returned to us */
        check(patch_feature_section(0xF, &fixup) == 1);
-       check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
+       check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0);
        check(patch_feature_section(0, &fixup) == 1);
-       check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
+       check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0);
        check(patch_feature_section(~0xF, &fixup) == 1);
-       check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
+       check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0);
 }
 
 static void test_alternative_case_too_small(void)
 {
-       extern unsigned int ftr_fixup_test4;
-       extern unsigned int end_ftr_fixup_test4;
-       extern unsigned int ftr_fixup_test4_orig;
-       extern unsigned int ftr_fixup_test4_alt;
-       extern unsigned int ftr_fixup_test4_expected;
-       int size = &end_ftr_fixup_test4 - &ftr_fixup_test4;
+       extern unsigned int ftr_fixup_test4[];
+       extern unsigned int end_ftr_fixup_test4[];
+       extern unsigned int ftr_fixup_test4_orig[];
+       extern unsigned int ftr_fixup_test4_alt[];
+       extern unsigned int ftr_fixup_test4_expected[];
+       int size = end_ftr_fixup_test4 - ftr_fixup_test4;
        unsigned long flag;
 
        /* Check a high-bit flag */
        flag = 1UL << ((sizeof(unsigned long) - 1) * 8);
        fixup.value = fixup.mask = flag;
-       fixup.start_off = calc_offset(&fixup, &ftr_fixup_test4 + 1);
-       fixup.end_off = calc_offset(&fixup, &ftr_fixup_test4 + 5);
-       fixup.alt_start_off = calc_offset(&fixup, &ftr_fixup_test4_alt);
-       fixup.alt_end_off = calc_offset(&fixup, &ftr_fixup_test4_alt + 2);
+       fixup.start_off = calc_offset(&fixup, ftr_fixup_test4 + 1);
+       fixup.end_off = calc_offset(&fixup, ftr_fixup_test4 + 5);
+       fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test4_alt);
+       fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test4_alt + 2);
 
        /* Sanity check */
-       check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0);
+       check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0);
 
        /* Check we don't patch if the value matches */
        patch_feature_section(flag, &fixup);
-       check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0);
+       check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0);
 
        /* Check we do patch if the value doesn't match */
        patch_feature_section(0, &fixup);
-       check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_expected, size) == 0);
+       check(memcmp(ftr_fixup_test4, ftr_fixup_test4_expected, size) == 0);
 
        /* Check we do patch if the mask doesn't match */
-       memcpy(&ftr_fixup_test4, &ftr_fixup_test4_orig, size);
-       check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0);
+       memcpy(ftr_fixup_test4, ftr_fixup_test4_orig, size);
+       check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0);
        patch_feature_section(~flag, &fixup);
-       check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_expected, size) == 0);
+       check(memcmp(ftr_fixup_test4, ftr_fixup_test4_expected, size) == 0);
 }
 
 static void test_alternative_case_with_branch(void)
 {
-       extern unsigned int ftr_fixup_test5;
-       extern unsigned int end_ftr_fixup_test5;
-       extern unsigned int ftr_fixup_test5_expected;
-       int size = &end_ftr_fixup_test5 - &ftr_fixup_test5;
+       extern unsigned int ftr_fixup_test5[];
+       extern unsigned int end_ftr_fixup_test5[];
+       extern unsigned int ftr_fixup_test5_expected[];
+       int size = end_ftr_fixup_test5 - ftr_fixup_test5;
 
-       check(memcmp(&ftr_fixup_test5, &ftr_fixup_test5_expected, size) == 0);
+       check(memcmp(ftr_fixup_test5, ftr_fixup_test5_expected, size) == 0);
 }
 
 static void test_alternative_case_with_external_branch(void)
 {
-       extern unsigned int ftr_fixup_test6;
-       extern unsigned int end_ftr_fixup_test6;
-       extern unsigned int ftr_fixup_test6_expected;
-       int size = &end_ftr_fixup_test6 - &ftr_fixup_test6;
+       extern unsigned int ftr_fixup_test6[];
+       extern unsigned int end_ftr_fixup_test6[];
+       extern unsigned int ftr_fixup_test6_expected[];
+       int size = end_ftr_fixup_test6 - ftr_fixup_test6;
 
-       check(memcmp(&ftr_fixup_test6, &ftr_fixup_test6_expected, size) == 0);
+       check(memcmp(ftr_fixup_test6, ftr_fixup_test6_expected, size) == 0);
 }
 
 static void test_cpu_macros(void)
 {
-       extern u8 ftr_fixup_test_FTR_macros;
-       extern u8 ftr_fixup_test_FTR_macros_expected;
-       unsigned long size = &ftr_fixup_test_FTR_macros_expected -
-                            &ftr_fixup_test_FTR_macros;
+       extern u8 ftr_fixup_test_FTR_macros[];
+       extern u8 ftr_fixup_test_FTR_macros_expected[];
+       unsigned long size = ftr_fixup_test_FTR_macros_expected -
+                            ftr_fixup_test_FTR_macros;
 
        /* The fixups have already been done for us during boot */
-       check(memcmp(&ftr_fixup_test_FTR_macros,
-                    &ftr_fixup_test_FTR_macros_expected, size) == 0);
+       check(memcmp(ftr_fixup_test_FTR_macros,
+                    ftr_fixup_test_FTR_macros_expected, size) == 0);
 }
 
 static void test_fw_macros(void)
 {
 #ifdef CONFIG_PPC64
-       extern u8 ftr_fixup_test_FW_FTR_macros;
-       extern u8 ftr_fixup_test_FW_FTR_macros_expected;
-       unsigned long size = &ftr_fixup_test_FW_FTR_macros_expected -
-                            &ftr_fixup_test_FW_FTR_macros;
+       extern u8 ftr_fixup_test_FW_FTR_macros[];
+       extern u8 ftr_fixup_test_FW_FTR_macros_expected[];
+       unsigned long size = ftr_fixup_test_FW_FTR_macros_expected -
+                            ftr_fixup_test_FW_FTR_macros;
 
        /* The fixups have already been done for us during boot */
-       check(memcmp(&ftr_fixup_test_FW_FTR_macros,
-                    &ftr_fixup_test_FW_FTR_macros_expected, size) == 0);
+       check(memcmp(ftr_fixup_test_FW_FTR_macros,
+                    ftr_fixup_test_FW_FTR_macros_expected, size) == 0);
 #endif
 }
 
 static void test_lwsync_macros(void)
 {
-       extern u8 lwsync_fixup_test;
-       extern u8 end_lwsync_fixup_test;
-       extern u8 lwsync_fixup_test_expected_LWSYNC;
-       extern u8 lwsync_fixup_test_expected_SYNC;
-       unsigned long size = &end_lwsync_fixup_test -
-                            &lwsync_fixup_test;
+       extern u8 lwsync_fixup_test[];
+       extern u8 end_lwsync_fixup_test[];
+       extern u8 lwsync_fixup_test_expected_LWSYNC[];
+       extern u8 lwsync_fixup_test_expected_SYNC[];
+       unsigned long size = end_lwsync_fixup_test -
+                            lwsync_fixup_test;
 
        /* The fixups have already been done for us during boot */
        if (cur_cpu_spec->cpu_features & CPU_FTR_LWSYNC) {
-               check(memcmp(&lwsync_fixup_test,
-                            &lwsync_fixup_test_expected_LWSYNC, size) == 0);
+               check(memcmp(lwsync_fixup_test,
+                            lwsync_fixup_test_expected_LWSYNC, size) == 0);
        } else {
-               check(memcmp(&lwsync_fixup_test,
-                            &lwsync_fixup_test_expected_SYNC, size) == 0);
+               check(memcmp(lwsync_fixup_test,
+                            lwsync_fixup_test_expected_SYNC, size) == 0);
        }
 }
 
index 33117f8..ee33327 100644 (file)
@@ -683,8 +683,10 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
        case 19:
                switch ((instr >> 1) & 0x3ff) {
                case 0:         /* mcrf */
-                       rd = (instr >> 21) & 0x1c;
-                       ra = (instr >> 16) & 0x1c;
+                       rd = 7 - ((instr >> 23) & 0x7);
+                       ra = 7 - ((instr >> 18) & 0x7);
+                       rd *= 4;
+                       ra *= 4;
                        val = (regs->ccr >> ra) & 0xf;
                        regs->ccr = (regs->ccr & ~(0xfUL << rd)) | (val << rd);
                        goto instr_done;
@@ -964,6 +966,19 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 #endif
 
                case 19:        /* mfcr */
+                       if ((instr >> 20) & 1) {
+                               imm = 0xf0000000UL;
+                               for (sh = 0; sh < 8; ++sh) {
+                                       if (instr & (0x80000 >> sh)) {
+                                               regs->gpr[rd] = regs->ccr & imm;
+                                               break;
+                                       }
+                                       imm >>= 4;
+                               }
+
+                               goto instr_done;
+                       }
+
                        regs->gpr[rd] = regs->ccr;
                        regs->gpr[rd] &= 0xffffffffUL;
                        goto instr_done;
index 8541f18..46b4e67 100644 (file)
@@ -402,6 +402,7 @@ void __init mem_init(void)
 void free_initmem(void)
 {
        ppc_md.progress = ppc_printk_progress;
+       mark_initmem_nx();
        free_initmem_default(POISON_FREE_INITMEM);
 }
 
index 0ee6be4..5d78b19 100644 (file)
 /*
  * Top of mmap area (just below the process stack).
  *
- * Leave at least a ~128 MB hole on 32bit applications.
- *
- * On 64bit applications we randomise the stack by 1GB so we need to
- * space our mmap start address by a further 1GB, otherwise there is a
- * chance the mmap area will end up closer to the stack than our ulimit
- * requires.
+ * Leave at least a ~128 MB hole.
  */
-#define MIN_GAP32 (128*1024*1024)
-#define MIN_GAP64 ((128 + 1024)*1024*1024UL)
-#define MIN_GAP ((is_32bit_task()) ? MIN_GAP32 : MIN_GAP64)
+#define MIN_GAP (128*1024*1024)
 #define MAX_GAP (TASK_SIZE/6*5)
 
 static inline int mmap_is_legacy(void)
@@ -71,9 +64,26 @@ unsigned long arch_mmap_rnd(void)
        return rnd << PAGE_SHIFT;
 }
 
+static inline unsigned long stack_maxrandom_size(void)
+{
+       if (!(current->flags & PF_RANDOMIZE))
+               return 0;
+
+       /* 8MB for 32bit, 1GB for 64bit */
+       if (is_32bit_task())
+               return (1<<23);
+       else
+               return (1<<30);
+}
+
 static inline unsigned long mmap_base(unsigned long rnd)
 {
        unsigned long gap = rlimit(RLIMIT_STACK);
+       unsigned long pad = stack_maxrandom_size() + stack_guard_gap;
+
+       /* Values close to RLIM_INFINITY can overflow. */
+       if (gap + pad > gap)
+               gap += pad;
 
        if (gap < MIN_GAP)
                gap = MIN_GAP;
index 71de2c6..a75f638 100644 (file)
@@ -126,9 +126,10 @@ static int hash__init_new_context(struct mm_struct *mm)
 static int radix__init_new_context(struct mm_struct *mm)
 {
        unsigned long rts_field;
-       int index;
+       int index, max_id;
 
-       index = alloc_context_id(1, PRTB_ENTRIES - 1);
+       max_id = (1 << mmu_pid_bits) - 1;
+       index = alloc_context_id(mmu_base_pid, max_id);
        if (index < 0)
                return index;
 
@@ -138,6 +139,14 @@ static int radix__init_new_context(struct mm_struct *mm)
        rts_field = radix__get_tree_size();
        process_tb[index].prtb0 = cpu_to_be64(rts_field | __pa(mm->pgd) | RADIX_PGD_INDEX_SIZE);
 
+       /*
+        * Order the above store with subsequent update of the PID
+        * register (at which point HW can start loading/caching
+        * the entry) and the corresponding load by the MMU from
+        * the L2 cache.
+        */
+       asm volatile("ptesync;isync" : : : "memory");
+
        mm->context.npu_context = NULL;
 
        return index;
@@ -223,9 +232,15 @@ void destroy_context(struct mm_struct *mm)
        mm->context.cop_lockp = NULL;
 #endif /* CONFIG_PPC_ICSWX */
 
-       if (radix_enabled())
-               process_tb[mm->context.id].prtb1 = 0;
-       else
+       if (radix_enabled()) {
+               /*
+                * Radix doesn't have a valid bit in the process table
+                * entries. However we know that at least P9 implementation
+                * will avoid caching an entry with an invalid RTS field,
+                * and 0 is invalid. So this will do.
+                */
+               process_tb[mm->context.id].prtb0 = 0;
+       } else
                subpage_prot_free(mm);
        destroy_pagetable_page(mm);
        __destroy_context(mm->context.id);
index 188b410..443a2c6 100644 (file)
@@ -425,33 +425,51 @@ int hash__has_transparent_hugepage(void)
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
-void hash__mark_rodata_ro(void)
+static bool hash__change_memory_range(unsigned long start, unsigned long end,
+                                     unsigned long newpp)
 {
-       unsigned long start = (unsigned long)_stext;
-       unsigned long end = (unsigned long)__init_begin;
        unsigned long idx;
        unsigned int step, shift;
-       unsigned long newpp = PP_RXXX;
 
        shift = mmu_psize_defs[mmu_linear_psize].shift;
        step = 1 << shift;
 
-       start = ((start + step - 1) >> shift) << shift;
-       end = (end >> shift) << shift;
+       start = ALIGN_DOWN(start, step);
+       end = ALIGN(end, step); // aligns up
 
-       pr_devel("marking ro start %lx, end %lx, step %x\n",
-                       start, end, step);
+       if (start >= end)
+               return false;
 
-       if (start == end) {
-               pr_warn("could not set rodata ro, relocate the start"
-                       " of the kernel to a 0x%x boundary\n", step);
-               return;
-       }
+       pr_debug("Changing page protection on range 0x%lx-0x%lx, to 0x%lx, step 0x%x\n",
+                start, end, newpp, step);
 
        for (idx = start; idx < end; idx += step)
                /* Not sure if we can do much with the return value */
                mmu_hash_ops.hpte_updateboltedpp(newpp, idx, mmu_linear_psize,
                                                        mmu_kernel_ssize);
 
+       return true;
+}
+
+void hash__mark_rodata_ro(void)
+{
+       unsigned long start, end;
+
+       start = (unsigned long)_stext;
+       end = (unsigned long)__init_begin;
+
+       WARN_ON(!hash__change_memory_range(start, end, PP_RXXX));
+}
+
+void hash__mark_initmem_nx(void)
+{
+       unsigned long start, end, pp;
+
+       start = (unsigned long)__init_begin;
+       end = (unsigned long)__init_end;
+
+       pp = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL));
+
+       WARN_ON(!hash__change_memory_range(start, end, pp));
 }
 #endif
index 8c13e42..671a45d 100644 (file)
@@ -25,6 +25,9 @@
 
 #include <trace/events/thp.h>
 
+unsigned int mmu_pid_bits;
+unsigned int mmu_base_pid;
+
 static int native_register_process_table(unsigned long base, unsigned long pg_sz,
                                         unsigned long table_size)
 {
@@ -112,10 +115,9 @@ set_the_pte:
 }
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
-void radix__mark_rodata_ro(void)
+void radix__change_memory_range(unsigned long start, unsigned long end,
+                               unsigned long clear)
 {
-       unsigned long start = (unsigned long)_stext;
-       unsigned long end = (unsigned long)__init_begin;
        unsigned long idx;
        pgd_t *pgdp;
        pud_t *pudp;
@@ -125,7 +127,8 @@ void radix__mark_rodata_ro(void)
        start = ALIGN_DOWN(start, PAGE_SIZE);
        end = PAGE_ALIGN(end); // aligns up
 
-       pr_devel("marking ro start %lx, end %lx\n", start, end);
+       pr_debug("Changing flags on range %lx-%lx removing 0x%lx\n",
+                start, end, clear);
 
        for (idx = start; idx < end; idx += PAGE_SIZE) {
                pgdp = pgd_offset_k(idx);
@@ -147,11 +150,29 @@ void radix__mark_rodata_ro(void)
                if (!ptep)
                        continue;
 update_the_pte:
-               radix__pte_update(&init_mm, idx, ptep, _PAGE_WRITE, 0, 0);
+               radix__pte_update(&init_mm, idx, ptep, clear, 0, 0);
        }
 
        radix__flush_tlb_kernel_range(start, end);
 }
+
+void radix__mark_rodata_ro(void)
+{
+       unsigned long start, end;
+
+       start = (unsigned long)_stext;
+       end = (unsigned long)__init_begin;
+
+       radix__change_memory_range(start, end, _PAGE_WRITE);
+}
+
+void radix__mark_initmem_nx(void)
+{
+       unsigned long start = (unsigned long)__init_begin;
+       unsigned long end = (unsigned long)__init_end;
+
+       radix__change_memory_range(start, end, _PAGE_EXEC);
+}
 #endif /* CONFIG_STRICT_KERNEL_RWX */
 
 static inline void __meminit print_mapping(unsigned long start,
@@ -243,11 +264,34 @@ static void __init radix_init_pgtable(void)
        for_each_memblock(memory, reg)
                WARN_ON(create_physical_mapping(reg->base,
                                                reg->base + reg->size));
+
+       /* Find out how many PID bits are supported */
+       if (cpu_has_feature(CPU_FTR_HVMODE)) {
+               if (!mmu_pid_bits)
+                       mmu_pid_bits = 20;
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+               /*
+                * When KVM is possible, we only use the top half of the
+                * PID space to avoid collisions between host and guest PIDs
+                * which can cause problems due to prefetch when exiting the
+                * guest with AIL=3
+                */
+               mmu_base_pid = 1 << (mmu_pid_bits - 1);
+#else
+               mmu_base_pid = 1;
+#endif
+       } else {
+               /* The guest uses the bottom half of the PID space */
+               if (!mmu_pid_bits)
+                       mmu_pid_bits = 19;
+               mmu_base_pid = 1;
+       }
+
        /*
         * Allocate Partition table and process table for the
         * host.
         */
-       BUILD_BUG_ON_MSG((PRTB_SIZE_SHIFT > 36), "Process table size too large.");
+       BUG_ON(PRTB_SIZE_SHIFT > 36);
        process_tb = early_alloc_pgtable(1UL << PRTB_SIZE_SHIFT);
        /*
         * Fill in the process table.
@@ -321,6 +365,12 @@ static int __init radix_dt_scan_page_sizes(unsigned long node,
        if (type == NULL || strcmp(type, "cpu") != 0)
                return 0;
 
+       /* Find MMU PID size */
+       prop = of_get_flat_dt_prop(node, "ibm,mmu-pid-bits", &size);
+       if (prop && size == 4)
+               mmu_pid_bits = be32_to_cpup(prop);
+
+       /* Grab page size encodings */
        prop = of_get_flat_dt_prop(node, "ibm,processor-radix-AP-encodings", &size);
        if (!prop)
                return 0;
index 5c0b795..0736e94 100644 (file)
@@ -505,4 +505,12 @@ void mark_rodata_ro(void)
        else
                hash__mark_rodata_ro();
 }
+
+void mark_initmem_nx(void)
+{
+       if (radix_enabled())
+               radix__mark_initmem_nx();
+       else
+               hash__mark_initmem_nx();
+}
 #endif
index e94fbd4..781532d 100644 (file)
@@ -36,7 +36,7 @@ void subpage_prot_free(struct mm_struct *mm)
                }
        }
        addr = 0;
-       for (i = 0; i < 2; ++i) {
+       for (i = 0; i < (TASK_SIZE_USER64 >> 43); ++i) {
                p = spt->protptrs[i];
                if (!p)
                        continue;
index 744e016..16ae1bb 100644 (file)
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 #include <linux/memblock.h>
-#include <asm/ppc-opcode.h>
 
+#include <asm/ppc-opcode.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 #include <asm/trace.h>
-
+#include <asm/cputhreads.h>
 
 #define RIC_FLUSH_TLB 0
 #define RIC_FLUSH_PWC 1
@@ -454,3 +454,44 @@ void radix__flush_tlb_pte_p9_dd1(unsigned long old_pte, struct mm_struct *mm,
        else
                radix__flush_tlb_page_psize(mm, address, mmu_virtual_psize);
 }
+
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+extern void radix_kvm_prefetch_workaround(struct mm_struct *mm)
+{
+       unsigned int pid = mm->context.id;
+
+       if (unlikely(pid == MMU_NO_CONTEXT))
+               return;
+
+       /*
+        * If this context hasn't run on that CPU before and KVM is
+        * around, there's a slim chance that the guest on another
+        * CPU just brought in obsolete translation into the TLB of
+        * this CPU due to a bad prefetch using the guest PID on
+        * the way into the hypervisor.
+        *
+        * We work around this here. If KVM is possible, we check if
+        * any sibling thread is in KVM. If it is, the window may exist
+        * and thus we flush that PID from the core.
+        *
+        * A potential future improvement would be to mark which PIDs
+        * have never been used on the system and avoid it if the PID
+        * is new and the process has no other cpumask bit set.
+        */
+       if (cpu_has_feature(CPU_FTR_HVMODE) && radix_enabled()) {
+               int cpu = smp_processor_id();
+               int sib = cpu_first_thread_sibling(cpu);
+               bool flush = false;
+
+               for (; sib <= cpu_last_thread_sibling(cpu) && !flush; sib++) {
+                       if (sib == cpu)
+                               continue;
+                       if (paca[sib].kvm_hstate.kvm_vcpu)
+                               flush = true;
+               }
+               if (flush)
+                       _tlbiel_pid(pid, RIC_FLUSH_ALL);
+       }
+}
+EXPORT_SYMBOL_GPL(radix_kvm_prefetch_workaround);
+#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
index 8125160..3f3aa9a 100644 (file)
@@ -90,13 +90,15 @@ static void mmcra_sdar_mode(u64 event, unsigned long *mmcra)
         *      MMCRA[SDAR_MODE] will be set to 0b01
         * For rest
         *      MMCRA[SDAR_MODE] will be set from event code.
+        *      If sdar_mode from event is zero, default to 0b01. Hardware
+        *      requires that we set a non-zero value.
         */
        if (cpu_has_feature(CPU_FTR_ARCH_300)) {
                if (is_event_marked(event) || (*mmcra & MMCRA_SAMPLE_ENABLE))
                        *mmcra &= MMCRA_SDAR_MODE_NO_UPDATES;
-               else if (!cpu_has_feature(CPU_FTR_POWER9_DD1))
+               else if (!cpu_has_feature(CPU_FTR_POWER9_DD1) && p9_SDAR_MODE(event))
                        *mmcra |=  p9_SDAR_MODE(event) << MMCRA_SDAR_MODE_SHIFT;
-               else if (cpu_has_feature(CPU_FTR_POWER9_DD1))
+               else
                        *mmcra |= MMCRA_SDAR_MODE_TLB;
        } else
                *mmcra |= MMCRA_SDAR_MODE_TLB;
index 80204e0..5068918 100644 (file)
@@ -51,8 +51,12 @@ EVENT(PM_DTLB_MISS,                          0x300fc)
 EVENT(PM_ITLB_MISS,                            0x400fc)
 /* Run_Instructions */
 EVENT(PM_RUN_INST_CMPL,                                0x500fa)
+/* Alternate event code for PM_RUN_INST_CMPL */
+EVENT(PM_RUN_INST_CMPL_ALT,                    0x400fa)
 /* Run_cycles */
 EVENT(PM_RUN_CYC,                              0x600f4)
+/* Alternate event code for Run_cycles */
+EVENT(PM_RUN_CYC_ALT,                          0x200f4)
 /* Instruction Dispatched */
 EVENT(PM_INST_DISP,                            0x200f2)
 EVENT(PM_INST_DISP_ALT,                                0x300f2)
index f17435e..2280cf8 100644 (file)
@@ -107,6 +107,8 @@ extern struct attribute_group isa207_pmu_format_group;
 /* Table of alternatives, sorted by column 0 */
 static const unsigned int power9_event_alternatives[][MAX_ALT] = {
        { PM_INST_DISP,                 PM_INST_DISP_ALT },
+       { PM_RUN_CYC_ALT,               PM_RUN_CYC },
+       { PM_RUN_INST_CMPL_ALT,         PM_RUN_INST_CMPL },
 };
 
 static int power9_get_alternatives(u64 event, unsigned int flags, u64 alt[])
index d8af9bc..9558d72 100644 (file)
@@ -605,6 +605,24 @@ static const match_table_t spufs_tokens = {
        { Opt_err,    NULL  },
 };
 
+static int spufs_show_options(struct seq_file *m, struct dentry *root)
+{
+       struct spufs_sb_info *sbi = spufs_get_sb_info(root->d_sb);
+       struct inode *inode = root->d_inode;
+
+       if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID))
+               seq_printf(m, ",uid=%u",
+                          from_kuid_munged(&init_user_ns, inode->i_uid));
+       if (!gid_eq(inode->i_gid, GLOBAL_ROOT_GID))
+               seq_printf(m, ",gid=%u",
+                          from_kgid_munged(&init_user_ns, inode->i_gid));
+       if ((inode->i_mode & S_IALLUGO) != 0775)
+               seq_printf(m, ",mode=%o", inode->i_mode);
+       if (sbi->debug)
+               seq_puts(m, ",debug");
+       return 0;
+}
+
 static int
 spufs_parse_options(struct super_block *sb, char *options, struct inode *root)
 {
@@ -724,11 +742,9 @@ spufs_fill_super(struct super_block *sb, void *data, int silent)
                .destroy_inode = spufs_destroy_inode,
                .statfs = simple_statfs,
                .evict_inode = spufs_evict_inode,
-               .show_options = generic_show_options,
+               .show_options = spufs_show_options,
        };
 
-       save_mount_options(sb, data);
-
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
index 59684b4..cad6b57 100644 (file)
@@ -59,6 +59,8 @@ static struct task_struct *kopald_tsk;
 
 void opal_configure_cores(void)
 {
+       u64 reinit_flags = 0;
+
        /* Do the actual re-init, This will clobber all FPRs, VRs, etc...
         *
         * It will preserve non volatile GPRs and HSPRG0/1. It will
@@ -66,11 +68,24 @@ void opal_configure_cores(void)
         * but it might clobber a bunch.
         */
 #ifdef __BIG_ENDIAN__
-       opal_reinit_cpus(OPAL_REINIT_CPUS_HILE_BE);
+       reinit_flags |= OPAL_REINIT_CPUS_HILE_BE;
 #else
-       opal_reinit_cpus(OPAL_REINIT_CPUS_HILE_LE);
+       reinit_flags |= OPAL_REINIT_CPUS_HILE_LE;
 #endif
 
+       /*
+        * POWER9 always support running hash:
+        *  ie. Host hash  supports  hash guests
+        *      Host radix supports  hash/radix guests
+        */
+       if (early_cpu_has_feature(CPU_FTR_ARCH_300)) {
+               reinit_flags |= OPAL_REINIT_CPUS_MMU_HASH;
+               if (early_radix_enabled())
+                       reinit_flags |= OPAL_REINIT_CPUS_MMU_RADIX;
+       }
+
+       opal_reinit_cpus(reinit_flags);
+
        /* Restore some bits */
        if (cur_cpu_spec->cpu_restore)
                cur_cpu_spec->cpu_restore();
index 2dc7e5f..897aa14 100644 (file)
@@ -225,6 +225,8 @@ static void pnv_kexec_wait_secondaries_down(void)
 
 static void pnv_kexec_cpu_down(int crash_shutdown, int secondary)
 {
+       u64 reinit_flags;
+
        if (xive_enabled())
                xive_kexec_teardown_cpu(secondary);
        else
@@ -254,8 +256,15 @@ static void pnv_kexec_cpu_down(int crash_shutdown, int secondary)
                 * We might be running as little-endian - now that interrupts
                 * are disabled, reset the HILE bit to big-endian so we don't
                 * take interrupts in the wrong endian later
+                *
+                * We reinit to enable both radix and hash on P9 to ensure
+                * the mode used by the next kernel is always supported.
                 */
-               opal_reinit_cpus(OPAL_REINIT_CPUS_HILE_BE);
+               reinit_flags = OPAL_REINIT_CPUS_HILE_BE;
+               if (cpu_has_feature(CPU_FTR_ARCH_300))
+                       reinit_flags |= OPAL_REINIT_CPUS_MMU_RADIX |
+                               OPAL_REINIT_CPUS_MMU_HASH;
+               opal_reinit_cpus(reinit_flags);
        }
 }
 #endif /* CONFIG_KEXEC_CORE */
index e5bf1e8..011ef21 100644 (file)
@@ -82,7 +82,6 @@ static int pSeries_reconfig_remove_node(struct device_node *np)
 
        of_detach_node(np);
        of_node_put(parent);
-       of_node_put(np); /* Must decrement the refcount */
        return 0;
 }
 
index 1bbd9db..ce9cc12 100644 (file)
@@ -14,7 +14,7 @@
                ".section .rodata.str,\"aMS\",@progbits,1\n"    \
                "2:     .asciz  \""__FILE__"\"\n"               \
                ".previous\n"                                   \
-               ".section __bug_table,\"a\"\n"                  \
+               ".section __bug_table,\"aw\"\n"                 \
                "3:     .long   1b-3b,2b-3b\n"                  \
                "       .short  %0,%1\n"                        \
                "       .org    3b+%2\n"                        \
@@ -30,7 +30,7 @@
        asm volatile(                                   \
                "0:     j       0b+2\n"                 \
                "1:\n"                                  \
-               ".section __bug_table,\"a\"\n"          \
+               ".section __bug_table,\"aw\"\n"         \
                "2:     .long   1b-2b\n"                \
                "       .short  %0\n"                   \
                "       .org    2b+%1\n"                \
index 28b5281..304cfe4 100644 (file)
@@ -249,9 +249,6 @@ int __put_user_bad(void) __attribute__((noreturn));
 
 int __get_user_bad(void) __attribute__((noreturn));
 
-#define __put_user_unaligned __put_user
-#define __get_user_unaligned __get_user
-
 unsigned long __must_check
 raw_copy_in_user(void __user *to, const void __user *from, unsigned long n);
 
index 49a6bd4..3d0b14a 100644 (file)
@@ -246,6 +246,7 @@ void arch_crash_save_vmcoreinfo(void)
        VMCOREINFO_SYMBOL(lowcore_ptr);
        VMCOREINFO_SYMBOL(high_memory);
        VMCOREINFO_LENGTH(lowcore_ptr, NR_CPUS);
+       mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note());
 }
 
 void machine_shutdown(void)
index 0c82f79..c1bf75f 100644 (file)
@@ -998,7 +998,7 @@ static int perf_push_sample(struct perf_event *event, struct sf_raw_sample *sfr)
        psw_bits(regs.psw).ia   = sfr->basic.ia;
        psw_bits(regs.psw).dat  = sfr->basic.T;
        psw_bits(regs.psw).wait = sfr->basic.W;
-       psw_bits(regs.psw).per  = sfr->basic.P;
+       psw_bits(regs.psw).pstate = sfr->basic.P;
        psw_bits(regs.psw).as   = sfr->basic.AS;
 
        /*
index 3ae756c..3d1d808 100644 (file)
@@ -496,11 +496,6 @@ static void __init setup_memory_end(void)
        pr_notice("The maximum memory size is %luMB\n", memory_end >> 20);
 }
 
-static void __init setup_vmcoreinfo(void)
-{
-       mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note());
-}
-
 #ifdef CONFIG_CRASH_DUMP
 
 /*
@@ -939,7 +934,6 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
        setup_resources();
-       setup_vmcoreinfo();
        setup_lowcore();
        smp_fill_possible_mask();
        cpu_detect_mhz_feature();
index 3f2884e..af09d34 100644 (file)
@@ -1324,7 +1324,7 @@ static long kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
 {
        uint8_t *keys;
        uint64_t hva;
-       int i, r = 0;
+       int srcu_idx, i, r = 0;
 
        if (args->flags != 0)
                return -EINVAL;
@@ -1342,6 +1342,7 @@ static long kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
                return -ENOMEM;
 
        down_read(&current->mm->mmap_sem);
+       srcu_idx = srcu_read_lock(&kvm->srcu);
        for (i = 0; i < args->count; i++) {
                hva = gfn_to_hva(kvm, args->start_gfn + i);
                if (kvm_is_error_hva(hva)) {
@@ -1353,6 +1354,7 @@ static long kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
                if (r)
                        break;
        }
+       srcu_read_unlock(&kvm->srcu, srcu_idx);
        up_read(&current->mm->mmap_sem);
 
        if (!r) {
@@ -1370,7 +1372,7 @@ static long kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
 {
        uint8_t *keys;
        uint64_t hva;
-       int i, r = 0;
+       int srcu_idx, i, r = 0;
 
        if (args->flags != 0)
                return -EINVAL;
@@ -1396,6 +1398,7 @@ static long kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
                goto out;
 
        down_read(&current->mm->mmap_sem);
+       srcu_idx = srcu_read_lock(&kvm->srcu);
        for (i = 0; i < args->count; i++) {
                hva = gfn_to_hva(kvm, args->start_gfn + i);
                if (kvm_is_error_hva(hva)) {
@@ -1413,6 +1416,7 @@ static long kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
                if (r)
                        break;
        }
+       srcu_read_unlock(&kvm->srcu, srcu_idx);
        up_read(&current->mm->mmap_sem);
 out:
        kvfree(keys);
index d4d409b..4a1f736 100644 (file)
@@ -591,11 +591,11 @@ void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
        unsigned long ptev;
        pgste_t pgste;
 
-       /* Clear storage key */
+       /* Clear storage key ACC and F, but set R/C */
        preempt_disable();
        pgste = pgste_get_lock(ptep);
-       pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT |
-                             PGSTE_GR_BIT | PGSTE_GC_BIT);
+       pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT);
+       pgste_val(pgste) |= PGSTE_GR_BIT | PGSTE_GC_BIT;
        ptev = pte_val(*ptep);
        if (!(ptev & _PAGE_INVALID) && (ptev & _PAGE_WRITE))
                page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 1);
index 590c91a..1a6f9c3 100644 (file)
@@ -1,39 +1,20 @@
-
-generic-y += bitsperlong.h
 generic-y += clkdev.h
 generic-y += current.h
 generic-y += delay.h
 generic-y += div64.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += exec.h
-generic-y += fcntl.h
-generic-y += ioctl.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
-generic-y += kvm_para.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
-generic-y += msgbuf.h
-generic-y += param.h
 generic-y += parport.h
 generic-y += percpu.h
-generic-y += poll.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += rwsem.h
-generic-y += sembuf.h
 generic-y += serial.h
-generic-y += shmbuf.h
 generic-y += sizes.h
-generic-y += socket.h
-generic-y += statfs.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += trace_clock.h
-generic-y += ucontext.h
 generic-y += xor.h
index 1b77f06..5b50863 100644 (file)
  */
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 #define _EMIT_BUG_ENTRY                                \
-       "\t.pushsection __bug_table,\"a\"\n"    \
+       "\t.pushsection __bug_table,\"aw\"\n"   \
        "2:\t.long 1b, %O1\n"                   \
        "\t.short %O2, %O3\n"                   \
        "\t.org 2b+%O4\n"                       \
        "\t.popsection\n"
 #else
 #define _EMIT_BUG_ENTRY                                \
-       "\t.pushsection __bug_table,\"a\"\n"    \
+       "\t.pushsection __bug_table,\"aw\"\n"   \
        "2:\t.long 1b\n"                        \
        "\t.short %O3\n"                        \
        "\t.org 2b+%O4\n"                       \
@@ -48,6 +48,7 @@ do {                                                  \
                   "i" (__FILE__),                      \
                   "i" (__LINE__), "i" (0),             \
                   "i" (sizeof(struct bug_entry)));     \
+       unreachable();                                  \
 } while (0)
 
 #define __WARN_FLAGS(flags)                            \
index 5d84df5..275fcae 100644 (file)
 #ifndef __ASM_SH_FLAT_H
 #define __ASM_SH_FLAT_H
 
+#include <asm/unaligned.h>
+
 #define        flat_argvp_envp_on_stack()              0
 #define        flat_old_ram_flag(flags)                (flags)
 #define        flat_reloc_valid(reloc, size)           ((reloc) <= (size))
-#define        flat_get_addr_from_rp(rp, relval, flags, p)     get_unaligned(rp)
-#define        flat_put_addr_at_rp(rp, val, relval)    put_unaligned(val,rp)
+static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
+                                       u32 *addr, u32 *persistent)
+{
+       *addr = get_unaligned((__force u32 *)rp);
+       return 0;
+}
+static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel)
+{
+       put_unaligned(addr, (__force u32 *)rp);
+       return 0;
+}
 #define        flat_get_relocate_addr(rel)             (rel)
 #define        flat_set_persistent(relval, p)          ({ (void)p; 0; })
 
index d9df3a7..141515a 100644 (file)
@@ -19,6 +19,7 @@ static __always_inline void boot_init_stack_canary(void)
        /* Try to get a semi random initial value. */
        get_random_bytes(&canary, sizeof(canary));
        canary ^= LINUX_VERSION_CODE;
+       canary &= CANARY_MASK;
 
        current->stack_canary = canary;
        __stack_chk_guard = current->stack_canary;
index b55fc2a..e285313 100644 (file)
@@ -1,4 +1,22 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ipcbuf.h
+generic-y += kvm_para.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += poll.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += shmbuf.h
 generic-y += siginfo.h
+generic-y += socket.h
+generic-y += statfs.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += ucontext.h
index eec7901..787bac9 100644 (file)
@@ -93,7 +93,7 @@
 #define TIOCGPKT       _IOR('T', 0x38, int) /* Get packet mode state */
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
-#define TIOCGPTPEER    _IOR('T', 0x41, int) /* Safely open the slave */
+#define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
 
 #define TIOCSERCONFIG  _IO('T', 83) /* 0x5453 */
 #define TIOCSERGWILD   _IOR('T', 84,  int) /* 0x5454 */
index d94dade..445b5e6 100644 (file)
@@ -234,7 +234,7 @@ static void sh64_icache_inv_current_user_range(unsigned long start, unsigned lon
 #define DUMMY_ALLOCO_AREA_SIZE ((L1_CACHE_BYTES << 10) + (1024 * 4))
 static unsigned char dummy_alloco_area[DUMMY_ALLOCO_AREA_SIZE] __cacheline_aligned = { 0, };
 
-static void inline sh64_dcache_purge_sets(int sets_to_purge_base, int n_sets)
+static inline void sh64_dcache_purge_sets(int sets_to_purge_base, int n_sets)
 {
        /* Purge all ways in a particular block of sets, specified by the base
           set number and number of sets.  Can handle wrap-around, if that's
index e9e837b..80ddc01 100644 (file)
@@ -18,5 +18,4 @@ generic-y += preempt.h
 generic-y += rwsem.h
 generic-y += serial.h
 generic-y += trace_clock.h
-generic-y += types.h
 generic-y += word-at-a-time.h
index 26ad2b2..284eac3 100644 (file)
@@ -7,6 +7,7 @@ void nmi_adjust_hz(unsigned int new_hz);
 
 extern atomic_t nmi_active;
 
+void arch_touch_nmi_watchdog(void);
 void start_nmi_watchdog(void *unused);
 void stop_nmi_watchdog(void *unused);
 
index ec9c04d..ff05992 100644 (file)
@@ -54,6 +54,7 @@ extern struct trap_per_cpu trap_block[NR_CPUS];
 void init_cur_cpu_trap(struct thread_info *);
 void setup_tba(void);
 extern int ncpus_probed;
+extern u64 cpu_mondo_counter[NR_CPUS];
 
 unsigned long real_hard_smp_processor_id(void);
 
index 113d84e..6d4c997 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/string.h>
 #include <asm/asi.h>
 #include <asm/spitfire.h>
-#include <asm-generic/uaccess-unaligned.h>
 #include <asm/extable_64.h>
 
 #include <asm/processor.h>
index b15bf6b..2178c78 100644 (file)
@@ -1,2 +1,4 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
+
+generic-y += types.h
index 6d27398..f5df72b 100644 (file)
@@ -88,7 +88,7 @@
 #define TIOCGPTN       _IOR('t', 134, unsigned int) /* Get Pty Number */
 #define TIOCSPTLCK     _IOW('t', 135, int) /* Lock/unlock PTY */
 #define TIOCSIG                _IOW('t', 136, int) /* Generate signal on Pty slave */
-#define TIOCGPTPEER    _IOR('t', 137, int) /* Safely open the slave */
+#define TIOCGPTPEER    _IO('t', 137) /* Safely open the slave */
 
 /* Little f */
 #define FIOCLEX                _IO('f', 1)
index e4b4e79..fa466ce 100644 (file)
@@ -205,7 +205,7 @@ static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
        handle_size = (sizeof(struct mdesc_handle) -
                       sizeof(struct mdesc_hdr) +
                       mdesc_size);
-       base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_REPEAT);
+       base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_RETRY_MAYFAIL);
        if (!base)
                return NULL;
 
index 95e73c6..048ad78 100644 (file)
@@ -51,7 +51,7 @@ static DEFINE_PER_CPU(unsigned int, last_irq_sum);
 static DEFINE_PER_CPU(long, alert_counter);
 static DEFINE_PER_CPU(int, nmi_touch);
 
-void touch_nmi_watchdog(void)
+void arch_touch_nmi_watchdog(void)
 {
        if (atomic_read(&nmi_active)) {
                int cpu;
@@ -61,10 +61,8 @@ void touch_nmi_watchdog(void)
                                per_cpu(nmi_touch, cpu) = 1;
                }
        }
-
-       touch_softlockup_watchdog();
 }
-EXPORT_SYMBOL(touch_nmi_watchdog);
+EXPORT_SYMBOL(arch_touch_nmi_watchdog);
 
 static void die_nmi(const char *str, struct pt_regs *regs, int do_panic)
 {
index 24f21c7..f10e2f7 100644 (file)
@@ -673,12 +673,14 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
 static int dma_4v_supported(struct device *dev, u64 device_mask)
 {
        struct iommu *iommu = dev->archdata.iommu;
-       u64 dma_addr_mask;
+       u64 dma_addr_mask = iommu->dma_addr_mask;
 
-       if (device_mask > DMA_BIT_MASK(32) && iommu->atu)
-               dma_addr_mask = iommu->atu->dma_addr_mask;
-       else
-               dma_addr_mask = iommu->dma_addr_mask;
+       if (device_mask > DMA_BIT_MASK(32)) {
+               if (iommu->atu)
+                       dma_addr_mask = iommu->atu->dma_addr_mask;
+               else
+                       return 0;
+       }
 
        if ((device_mask & dma_addr_mask) == dma_addr_mask)
                return 1;
index fdf3104..3218bc4 100644 (file)
@@ -622,22 +622,48 @@ retry:
        }
 }
 
-/* Multi-cpu list version.  */
+#define        CPU_MONDO_COUNTER(cpuid)        (cpu_mondo_counter[cpuid])
+#define        MONDO_USEC_WAIT_MIN             2
+#define        MONDO_USEC_WAIT_MAX             100
+#define        MONDO_RETRY_LIMIT               500000
+
+/* Multi-cpu list version.
+ *
+ * Deliver xcalls to 'cnt' number of cpus in 'cpu_list'.
+ * Sometimes not all cpus receive the mondo, requiring us to re-send
+ * the mondo until all cpus have received, or cpus are truly stuck
+ * unable to receive mondo, and we timeout.
+ * Occasionally a target cpu strand is borrowed briefly by hypervisor to
+ * perform guest service, such as PCIe error handling. Consider the
+ * service time, 1 second overall wait is reasonable for 1 cpu.
+ * Here two in-between mondo check wait time are defined: 2 usec for
+ * single cpu quick turn around and up to 100usec for large cpu count.
+ * Deliver mondo to large number of cpus could take longer, we adjusts
+ * the retry count as long as target cpus are making forward progress.
+ */
 static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt)
 {
-       int retries, this_cpu, prev_sent, i, saw_cpu_error;
+       int this_cpu, tot_cpus, prev_sent, i, rem;
+       int usec_wait, retries, tot_retries;
+       u16 first_cpu = 0xffff;
+       unsigned long xc_rcvd = 0;
        unsigned long status;
+       int ecpuerror_id = 0;
+       int enocpu_id = 0;
        u16 *cpu_list;
+       u16 cpu;
 
        this_cpu = smp_processor_id();
-
        cpu_list = __va(tb->cpu_list_pa);
-
-       saw_cpu_error = 0;
-       retries = 0;
+       usec_wait = cnt * MONDO_USEC_WAIT_MIN;
+       if (usec_wait > MONDO_USEC_WAIT_MAX)
+               usec_wait = MONDO_USEC_WAIT_MAX;
+       retries = tot_retries = 0;
+       tot_cpus = cnt;
        prev_sent = 0;
+
        do {
-               int forward_progress, n_sent;
+               int n_sent, mondo_delivered, target_cpu_busy;
 
                status = sun4v_cpu_mondo_send(cnt,
                                              tb->cpu_list_pa,
@@ -645,94 +671,113 @@ static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt)
 
                /* HV_EOK means all cpus received the xcall, we're done.  */
                if (likely(status == HV_EOK))
-                       break;
+                       goto xcall_done;
+
+               /* If not these non-fatal errors, panic */
+               if (unlikely((status != HV_EWOULDBLOCK) &&
+                       (status != HV_ECPUERROR) &&
+                       (status != HV_ENOCPU)))
+                       goto fatal_errors;
 
                /* First, see if we made any forward progress.
                 *
+                * Go through the cpu_list, count the target cpus that have
+                * received our mondo (n_sent), and those that did not (rem).
+                * Re-pack cpu_list with the cpus remain to be retried in the
+                * front - this simplifies tracking the truly stalled cpus.
+                *
                 * The hypervisor indicates successful sends by setting
                 * cpu list entries to the value 0xffff.
+                *
+                * EWOULDBLOCK means some target cpus did not receive the
+                * mondo and retry usually helps.
+                *
+                * ECPUERROR means at least one target cpu is in error state,
+                * it's usually safe to skip the faulty cpu and retry.
+                *
+                * ENOCPU means one of the target cpu doesn't belong to the
+                * domain, perhaps offlined which is unexpected, but not
+                * fatal and it's okay to skip the offlined cpu.
                 */
+               rem = 0;
                n_sent = 0;
                for (i = 0; i < cnt; i++) {
-                       if (likely(cpu_list[i] == 0xffff))
+                       cpu = cpu_list[i];
+                       if (likely(cpu == 0xffff)) {
                                n_sent++;
+                       } else if ((status == HV_ECPUERROR) &&
+                               (sun4v_cpu_state(cpu) == HV_CPU_STATE_ERROR)) {
+                               ecpuerror_id = cpu + 1;
+                       } else if (status == HV_ENOCPU && !cpu_online(cpu)) {
+                               enocpu_id = cpu + 1;
+                       } else {
+                               cpu_list[rem++] = cpu;
+                       }
                }
 
-               forward_progress = 0;
-               if (n_sent > prev_sent)
-                       forward_progress = 1;
+               /* No cpu remained, we're done. */
+               if (rem == 0)
+                       break;
 
-               prev_sent = n_sent;
+               /* Otherwise, update the cpu count for retry. */
+               cnt = rem;
 
-               /* If we get a HV_ECPUERROR, then one or more of the cpus
-                * in the list are in error state.  Use the cpu_state()
-                * hypervisor call to find out which cpus are in error state.
+               /* Record the overall number of mondos received by the
+                * first of the remaining cpus.
                 */
-               if (unlikely(status == HV_ECPUERROR)) {
-                       for (i = 0; i < cnt; i++) {
-                               long err;
-                               u16 cpu;
+               if (first_cpu != cpu_list[0]) {
+                       first_cpu = cpu_list[0];
+                       xc_rcvd = CPU_MONDO_COUNTER(first_cpu);
+               }
 
-                               cpu = cpu_list[i];
-                               if (cpu == 0xffff)
-                                       continue;
+               /* Was any mondo delivered successfully? */
+               mondo_delivered = (n_sent > prev_sent);
+               prev_sent = n_sent;
 
-                               err = sun4v_cpu_state(cpu);
-                               if (err == HV_CPU_STATE_ERROR) {
-                                       saw_cpu_error = (cpu + 1);
-                                       cpu_list[i] = 0xffff;
-                               }
-                       }
-               } else if (unlikely(status != HV_EWOULDBLOCK))
-                       goto fatal_mondo_error;
+               /* or, was any target cpu busy processing other mondos? */
+               target_cpu_busy = (xc_rcvd < CPU_MONDO_COUNTER(first_cpu));
+               xc_rcvd = CPU_MONDO_COUNTER(first_cpu);
 
-               /* Don't bother rewriting the CPU list, just leave the
-                * 0xffff and non-0xffff entries in there and the
-                * hypervisor will do the right thing.
-                *
-                * Only advance timeout state if we didn't make any
-                * forward progress.
+               /* Retry count is for no progress. If we're making progress,
+                * reset the retry count.
                 */
-               if (unlikely(!forward_progress)) {
-                       if (unlikely(++retries > 10000))
-                               goto fatal_mondo_timeout;
-
-                       /* Delay a little bit to let other cpus catch up
-                        * on their cpu mondo queue work.
-                        */
-                       udelay(2 * cnt);
+               if (likely(mondo_delivered || target_cpu_busy)) {
+                       tot_retries += retries;
+                       retries = 0;
+               } else if (unlikely(retries > MONDO_RETRY_LIMIT)) {
+                       goto fatal_mondo_timeout;
                }
-       } while (1);
 
-       if (unlikely(saw_cpu_error))
-               goto fatal_mondo_cpu_error;
+               /* Delay a little bit to let other cpus catch up on
+                * their cpu mondo queue work.
+                */
+               if (!mondo_delivered)
+                       udelay(usec_wait);
 
-       return;
+               retries++;
+       } while (1);
 
-fatal_mondo_cpu_error:
-       printk(KERN_CRIT "CPU[%d]: SUN4V mondo cpu error, some target cpus "
-              "(including %d) were in error state\n",
-              this_cpu, saw_cpu_error - 1);
+xcall_done:
+       if (unlikely(ecpuerror_id > 0)) {
+               pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) was in error state\n",
+                      this_cpu, ecpuerror_id - 1);
+       } else if (unlikely(enocpu_id > 0)) {
+               pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) does not belong to the domain\n",
+                      this_cpu, enocpu_id - 1);
+       }
        return;
 
+fatal_errors:
+       /* fatal errors include bad alignment, etc */
+       pr_crit("CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) mondo_block_pa(%lx)\n",
+              this_cpu, tot_cpus, tb->cpu_list_pa, tb->cpu_mondo_block_pa);
+       panic("Unexpected SUN4V mondo error %lu\n", status);
+
 fatal_mondo_timeout:
-       printk(KERN_CRIT "CPU[%d]: SUN4V mondo timeout, no forward "
-              " progress after %d retries.\n",
-              this_cpu, retries);
-       goto dump_cpu_list_and_out;
-
-fatal_mondo_error:
-       printk(KERN_CRIT "CPU[%d]: Unexpected SUN4V mondo error %lu\n",
-              this_cpu, status);
-       printk(KERN_CRIT "CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) "
-              "mondo_block_pa(%lx)\n",
-              this_cpu, cnt, tb->cpu_list_pa, tb->cpu_mondo_block_pa);
-
-dump_cpu_list_and_out:
-       printk(KERN_CRIT "CPU[%d]: CPU list [ ", this_cpu);
-       for (i = 0; i < cnt; i++)
-               printk("%u ", cpu_list[i]);
-       printk("]\n");
+       /* some cpus being non-responsive to the cpu mondo */
+       pr_crit("CPU[%d]: SUN4V mondo timeout, cpu(%d) made no forward progress after %d retries. Total target cpus(%d).\n",
+              this_cpu, first_cpu, (tot_retries + retries), tot_cpus);
+       panic("SUN4V mondo timeout panic\n");
 }
 
 static void (*xcall_deliver_impl)(struct trap_per_cpu *, int);
index 559bc5e..3463199 100644 (file)
@@ -26,6 +26,21 @@ sun4v_cpu_mondo:
        ldxa    [%g0] ASI_SCRATCHPAD, %g4
        sub     %g4, TRAP_PER_CPU_FAULT_INFO, %g4
 
+       /* Get smp_processor_id() into %g3 */
+       sethi   %hi(trap_block), %g5
+       or      %g5, %lo(trap_block), %g5
+       sub     %g4, %g5, %g3
+       srlx    %g3, TRAP_BLOCK_SZ_SHIFT, %g3
+
+       /* Increment cpu_mondo_counter[smp_processor_id()] */
+       sethi   %hi(cpu_mondo_counter), %g5
+       or      %g5, %lo(cpu_mondo_counter), %g5
+       sllx    %g3, 3, %g3
+       add     %g5, %g3, %g5
+       ldx     [%g5], %g3
+       add     %g3, 1, %g3
+       stx     %g3, [%g5]
+
        /* Get CPU mondo queue base phys address into %g7.  */
        ldx     [%g4 + TRAP_PER_CPU_CPU_MONDO_PA], %g7
 
index 196ee5e..ad31af1 100644 (file)
@@ -2733,6 +2733,7 @@ void do_getpsr(struct pt_regs *regs)
        }
 }
 
+u64 cpu_mondo_counter[NR_CPUS] = {0};
 struct trap_per_cpu trap_block[NR_CPUS];
 EXPORT_SYMBOL(trap_block);
 
index 16f0b08..d28d2b8 100644 (file)
@@ -2,37 +2,18 @@ generic-y += bug.h
 generic-y += bugs.h
 generic-y += clkdev.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += exec.h
 generic-y += extable.h
 generic-y += fb.h
-generic-y += fcntl.h
 generic-y += hw_irq.h
-generic-y += ioctl.h
-generic-y += ioctls.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += msgbuf.h
-generic-y += param.h
 generic-y += parport.h
-generic-y += poll.h
-generic-y += posix_types.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += seccomp.h
-generic-y += sembuf.h
 generic-y += serial.h
-generic-y += shmbuf.h
-generic-y += shmparam.h
-generic-y += socket.h
-generic-y += sockios.h
-generic-y += statfs.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += trace_clock.h
-generic-y += types.h
 generic-y += xor.h
index d0c79c1..cb4fbe7 100644 (file)
@@ -19,7 +19,6 @@
  * User space memory access functions
  */
 #include <linux/mm.h>
-#include <asm-generic/uaccess-unaligned.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 
index c55a3d4..328e622 100644 (file)
 
 #ifndef __ARCH_ABI_H__
 
-#if !defined __need_int_reg_t && !defined __DOXYGEN__
-# define __ARCH_ABI_H__
-# include <arch/chip.h>
-#endif
-
-/* Provide the basic machine types. */
-#ifndef __INT_REG_BITS
-
-/** Number of bits in a register. */
-#if defined __tilegx__
-# define __INT_REG_BITS 64
-#elif defined __tilepro__
-# define __INT_REG_BITS 32
-#elif !defined __need_int_reg_t
+#ifndef __tile__   /* support uncommon use of arch headers in non-tile builds */
 # include <arch/chip.h>
 # define __INT_REG_BITS CHIP_WORD_SIZE()
-#else
-# error Unrecognized architecture with __need_int_reg_t
-#endif
-
-#if __INT_REG_BITS == 64
-
-#ifndef __ASSEMBLER__
-/** Unsigned type that can hold a register. */
-typedef unsigned long long __uint_reg_t;
-
-/** Signed type that can hold a register. */
-typedef long long __int_reg_t;
-#endif
-
-/** String prefix to use for printf(). */
-#define __INT_REG_FMT "ll"
-
-#else
-
-#ifndef __ASSEMBLER__
-/** Unsigned type that can hold a register. */
-typedef unsigned long __uint_reg_t;
-
-/** Signed type that can hold a register. */
-typedef long __int_reg_t;
-#endif
-
-/** String prefix to use for printf(). */
-#define __INT_REG_FMT "l"
-
 #endif
-#endif /* __INT_REG_BITS */
 
+#include <arch/intreg.h>
 
+/* __need_int_reg_t is deprecated: just include <arch/intreg.h> */
 #ifndef __need_int_reg_t
 
+#define __ARCH_ABI_H__
 
 #ifndef __ASSEMBLER__
 /** Unsigned type that can hold a register. */
diff --git a/arch/tile/include/uapi/arch/intreg.h b/arch/tile/include/uapi/arch/intreg.h
new file mode 100644 (file)
index 0000000..1cf2fbf
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/**
+ * @file
+ *
+ * Provide types and defines for the type that can hold a register,
+ * in the implementation namespace.
+ */
+
+#ifndef __ARCH_INTREG_H__
+#define __ARCH_INTREG_H__
+
+/*
+ * Get number of bits in a register.  __INT_REG_BITS may be defined
+ * prior to including this header to force a particular bit width.
+ */
+
+#ifndef __INT_REG_BITS
+# if defined __tilegx__
+#  define __INT_REG_BITS 64
+# elif defined __tilepro__
+#  define __INT_REG_BITS 32
+# else
+#  error Unrecognized architecture
+# endif
+#endif
+
+#if __INT_REG_BITS == 64
+
+# ifndef __ASSEMBLER__
+/** Unsigned type that can hold a register. */
+typedef unsigned long long __uint_reg_t;
+
+/** Signed type that can hold a register. */
+typedef long long __int_reg_t;
+# endif
+
+/** String prefix to use for printf(). */
+# define __INT_REG_FMT "ll"
+
+#elif __INT_REG_BITS == 32
+
+# ifndef __ASSEMBLER__
+/** Unsigned type that can hold a register. */
+typedef unsigned long __uint_reg_t;
+
+/** Signed type that can hold a register. */
+typedef long __int_reg_t;
+# endif
+
+/** String prefix to use for printf(). */
+# define __INT_REG_FMT "l"
+
+#else
+# error Unrecognized value of __INT_REG_BITS
+#endif
+
+#endif /* !__ARCH_INTREG_H__ */
index 0c74c3c..5711de0 100644 (file)
@@ -1,4 +1,23 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += statfs.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
 generic-y += ucontext.h
index 3a97e4d..5f757e0 100644 (file)
@@ -857,36 +857,6 @@ void __init mem_init(void)
 #endif
 }
 
-/*
- * this is for the non-NUMA, single node SMP system case.
- * Specifically, in the case of x86, we will always add
- * memory to the highmem for now.
- */
-#ifndef CONFIG_NEED_MULTIPLE_NODES
-int arch_add_memory(u64 start, u64 size, bool for_device)
-{
-       struct pglist_data *pgdata = &contig_page_data;
-       struct zone *zone = pgdata->node_zones + MAX_NR_ZONES-1;
-       unsigned long start_pfn = start >> PAGE_SHIFT;
-       unsigned long nr_pages = size >> PAGE_SHIFT;
-
-       return __add_pages(zone, start_pfn, nr_pages);
-}
-
-int remove_memory(u64 start, u64 size)
-{
-       return -EINVAL;
-}
-
-#ifdef CONFIG_MEMORY_HOTREMOVE
-int arch_remove_memory(u64 start, u64 size)
-{
-       /* TODO */
-       return -EBUSY;
-}
-#endif
-#endif
-
 struct kmem_cache *pgd_cache;
 
 void __init pgtable_cache_init(void)
index 0ca46ed..6ca4f66 100644 (file)
@@ -59,10 +59,14 @@ KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/um
 # Same things for in6addr_loopback and mktime - found in libc. For these two we
 # only get link-time error, luckily.
 #
+# -Dlongjmp=kernel_longjmp prevents anything from referencing the libpthread.a
+# embedded copy of longjmp, same thing for setjmp.
+#
 # These apply to USER_CFLAGS to.
 
 KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \
        $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap      \
+       -Dlongjmp=kernel_longjmp -Dsetjmp=kernel_setjmp \
        -Din6addr_loopback=kernel_in6addr_loopback \
        -Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr
 
index 7b361f3..c90817b 100644 (file)
@@ -192,6 +192,9 @@ __uml_exitcall(console_exit);
 
 static int console_chan_setup(char *str)
 {
+       if (!strncmp(str, "sole=", 5))  /* console= option specifies tty */
+               return 0;
+
        line_setup(vt_conf, MAX_TTYS, &def_conf, str, "console");
        return 1;
 }
index 1330553..9e6d599 100644 (file)
@@ -15,7 +15,7 @@
   PROVIDE (_unprotected_end = .);
 
   . = ALIGN(4096);
-  .note : { *(.note.*) }
+  NOTES
   EXCEPTION_TABLE(0)
 
   BUG_TABLE
diff --git a/arch/um/include/asm/io.h b/arch/um/include/asm/io.h
new file mode 100644 (file)
index 0000000..8f35d57
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _ASM_UM_IO_H
+#define _ASM_UM_IO_H
+
+#define ioremap ioremap
+static inline void __iomem *ioremap(phys_addr_t offset, size_t size)
+{
+       return (void __iomem *)(unsigned long)offset;
+}
+
+#define iounmap iounmap
+static inline void iounmap(void __iomem *addr)
+{
+}
+
+#include <asm-generic/io.h>
+
+#endif
index cd1fa97..574e03f 100644 (file)
@@ -242,6 +242,10 @@ extern void setup_hostinfo(char *buf, int len);
 extern void os_dump_core(void) __attribute__ ((noreturn));
 extern void um_early_printk(const char *s, unsigned int n);
 extern void os_fix_helper_signals(void);
+extern void os_info(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+extern void os_warn(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
 
 /* time.c */
 extern void os_idle_sleep(unsigned long long nsecs);
index a9deece..13f404e 100644 (file)
@@ -8,8 +8,6 @@
 #ifndef __STUB_DATA_H
 #define __STUB_DATA_H
 
-#include <time.h>
-
 struct stub_data {
        unsigned long offset;
        int fd;
index 4c9861b..f02596e 100644 (file)
@@ -89,8 +89,8 @@ void __init setup_physmem(unsigned long start, unsigned long reserve_end,
        offset = uml_reserved - uml_physmem;
        map_size = len - offset;
        if(map_size <= 0) {
-               printf("Too few physical memory! Needed=%d, given=%d\n",
-                      offset, len);
+               os_warn("Too few physical memory! Needed=%lu, given=%lu\n",
+                       offset, len);
                exit(1);
        }
 
@@ -99,9 +99,9 @@ void __init setup_physmem(unsigned long start, unsigned long reserve_end,
        err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
                            map_size, 1, 1, 1);
        if (err < 0) {
-               printf("setup_physmem - mapping %ld bytes of memory at 0x%p "
-                      "failed - errno = %d\n", map_size,
-                      (void *) uml_reserved, err);
+               os_warn("setup_physmem - mapping %ld bytes of memory at 0x%p "
+                       "failed - errno = %d\n", map_size,
+                       (void *) uml_reserved, err);
                exit(1);
        }
 
index 5915887..4e6fcb3 100644 (file)
@@ -183,6 +183,16 @@ void fatal_sigsegv(void)
        os_dump_core();
 }
 
+/**
+ * segv_handler() - the SIGSEGV handler
+ * @sig:       the signal number
+ * @unused_si: the signal info struct; unused in this handler
+ * @regs:      the ptrace register information
+ *
+ * The handler first extracts the faultinfo from the UML ptrace regs struct.
+ * If the userfault did not happen in an UML userspace process, bad_segv is called.
+ * Otherwise the signal did happen in a cloned userspace process, handle it.
+ */
 void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
 {
        struct faultinfo * fi = UPT_FAULTINFO(regs);
index 7b56401..f433690 100644 (file)
@@ -34,7 +34,7 @@ static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
 static void __init add_arg(char *arg)
 {
        if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
-               printf("add_arg: Too many command line arguments!\n");
+               os_warn("add_arg: Too many command line arguments!\n");
                exit(1);
        }
        if (strlen(command_line) > 0)
@@ -120,6 +120,7 @@ static const char *usage_string =
 
 static int __init uml_version_setup(char *line, int *add)
 {
+       /* Explicitly use printf() to show version in stdout */
        printf("%s\n", init_utsname()->release);
        exit(0);
 
@@ -148,8 +149,8 @@ __uml_setup("root=", uml_root_setup,
 
 static int __init no_skas_debug_setup(char *line, int *add)
 {
-       printf("'debug' is not necessary to gdb UML in skas mode - run \n");
-       printf("'gdb linux'\n");
+       os_warn("'debug' is not necessary to gdb UML in skas mode - run\n");
+       os_warn("'gdb linux'\n");
 
        return 0;
 }
@@ -165,6 +166,7 @@ static int __init Usage(char *line, int *add)
 
        printf(usage_string, init_utsname()->release);
        p = &__uml_help_start;
+       /* Explicitly use printf() to show help in stdout */
        while (p < &__uml_help_end) {
                printf("%s", *p);
                p++;
@@ -283,8 +285,8 @@ int __init linux_main(int argc, char **argv)
 
        diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
        if (diff > 1024 * 1024) {
-               printf("Adding %ld bytes to physical memory to account for "
-                      "exec-shield gap\n", diff);
+               os_info("Adding %ld bytes to physical memory to account for "
+                       "exec-shield gap\n", diff);
                physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
        }
 
@@ -324,8 +326,8 @@ int __init linux_main(int argc, char **argv)
        end_vm = start_vm + virtmem_size;
 
        if (virtmem_size < physmem_size)
-               printf("Kernel virtual memory size shrunk to %lu bytes\n",
-                      virtmem_size);
+               os_info("Kernel virtual memory size shrunk to %lu bytes\n",
+                       virtmem_size);
 
        os_flush_stdout();
 
index f6cc3bd..10bf4ac 100644 (file)
@@ -16,14 +16,14 @@ static int __init set_umid_arg(char *name, int *add)
        int err;
 
        if (umid_inited) {
-               printf("umid already set\n");
+               os_warn("umid already set\n");
                return 0;
        }
 
        *add = 0;
        err = set_umid(name);
        if (err == -EEXIST)
-               printf("umid '%s' already in use\n", name);
+               os_warn("umid '%s' already in use\n", name);
        else if (!err)
                umid_inited = 1;
 
index 8fb25ca..84a0777 100644 (file)
@@ -136,7 +136,7 @@ int main(int argc, char**argv)
        int ret;
        argc--;
        if (!argc) {
-               fprintf(stderr, "Not enough arguments\n");
+               os_warn("Not enough arguments\n");
                return 1;
        }
        argv++;
index 9d499de..5f970ec 100644 (file)
@@ -74,8 +74,8 @@ static void install_fatal_handler(int sig)
        action.sa_restorer = NULL;
        action.sa_handler = last_ditch_exit;
        if (sigaction(sig, &action, NULL) < 0) {
-               printf("failed to install handler for signal %d - errno = %d\n",
-                      sig, errno);
+               os_warn("failed to install handler for signal %d "
+                       "- errno = %d\n", sig, errno);
                exit(1);
        }
 }
@@ -175,7 +175,7 @@ int __init main(int argc, char **argv, char **envp)
        /* disable SIGIO for the fds and set SIGIO to be ignored */
        err = deactivate_all_fds();
        if (err)
-               printf("deactivate_all_fds failed, errno = %d\n", -err);
+               os_warn("deactivate_all_fds failed, errno = %d\n", -err);
 
        /*
         * Let any pending signals fire now.  This ensures
@@ -184,14 +184,13 @@ int __init main(int argc, char **argv, char **envp)
         */
        unblock_signals();
 
+       os_info("\n");
        /* Reboot */
        if (ret) {
-               printf("\n");
                execvp(new_argv[0], new_argv);
                perror("Failed to exec kernel");
                ret = 1;
        }
-       printf("\n");
        return uml_exitcode;
 }
 
index 8b17676..e162a95 100644 (file)
@@ -25,13 +25,13 @@ static int __init check_tmpfs(const char *dir)
 {
        struct statfs st;
 
-       printf("Checking if %s is on tmpfs...", dir);
+       os_info("Checking if %s is on tmpfs...", dir);
        if (statfs(dir, &st) < 0) {
-               printf("%s\n", strerror(errno));
+               os_info("%s\n", strerror(errno));
        } else if (st.f_type != TMPFS_MAGIC) {
-               printf("no\n");
+               os_info("no\n");
        } else {
-               printf("OK\n");
+               os_info("OK\n");
                return 0;
        }
        return -1;
@@ -61,18 +61,18 @@ static char * __init choose_tempdir(void)
        int i;
        const char *dir;
 
-       printf("Checking environment variables for a tempdir...");
+       os_info("Checking environment variables for a tempdir...");
        for (i = 0; vars[i]; i++) {
                dir = getenv(vars[i]);
                if ((dir != NULL) && (*dir != '\0')) {
-                       printf("%s\n", dir);
+                       os_info("%s\n", dir);
                        if (check_tmpfs(dir) >= 0)
                                goto done;
                        else
                                goto warn;
                }
        }
-       printf("none found\n");
+       os_info("none found\n");
 
        for (i = 0; tmpfs_dirs[i]; i++) {
                dir = tmpfs_dirs[i];
@@ -82,7 +82,7 @@ static char * __init choose_tempdir(void)
 
        dir = fallback_dir;
 warn:
-       printf("Warning: tempdir %s is not on tmpfs\n", dir);
+       os_warn("Warning: tempdir %s is not on tmpfs\n", dir);
 done:
        /* Make a copy since getenv results may not remain valid forever. */
        return strdup(dir);
@@ -100,7 +100,7 @@ static int __init make_tempfile(const char *template)
        if (tempdir == NULL) {
                tempdir = choose_tempdir();
                if (tempdir == NULL) {
-                       fprintf(stderr, "Failed to choose tempdir: %s\n",
+                       os_warn("Failed to choose tempdir: %s\n",
                                strerror(errno));
                        return -1;
                }
@@ -125,7 +125,7 @@ static int __init make_tempfile(const char *template)
        strcat(tempname, template);
        fd = mkstemp(tempname);
        if (fd < 0) {
-               fprintf(stderr, "open - cannot create %s: %s\n", tempname,
+               os_warn("open - cannot create %s: %s\n", tempname,
                        strerror(errno));
                goto out;
        }
@@ -194,16 +194,16 @@ void __init check_tmpexec(void)
 
        addr = mmap(NULL, UM_KERN_PAGE_SIZE,
                    PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
-       printf("Checking PROT_EXEC mmap in %s...", tempdir);
+       os_info("Checking PROT_EXEC mmap in %s...", tempdir);
        if (addr == MAP_FAILED) {
                err = errno;
-               printf("%s\n", strerror(err));
+               os_warn("%s\n", strerror(err));
                close(fd);
                if (err == EPERM)
-                       printf("%s must be not mounted noexec\n", tempdir);
+                       os_warn("%s must be not mounted noexec\n", tempdir);
                exit(1);
        }
-       printf("OK\n");
+       os_info("OK\n");
        munmap(addr, UM_KERN_PAGE_SIZE);
 
        close(fd);
index 03b3c4c..819d686 100644 (file)
@@ -108,7 +108,7 @@ static void get_skas_faultinfo(int pid, struct faultinfo *fi)
        wait_stub_done(pid);
 
        /*
-        * faultinfo is prepared by the stub-segv-handler at start of
+        * faultinfo is prepared by the stub_segv_handler at start of
         * the stub stack page. We just have to copy it.
         */
        memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
@@ -175,6 +175,21 @@ static void handle_trap(int pid, struct uml_pt_regs *regs,
 
 extern char __syscall_stub_start[];
 
+/**
+ * userspace_tramp() - userspace trampoline
+ * @stack:     pointer to the new userspace stack page, can be NULL, if? FIXME:
+ *
+ * The userspace trampoline is used to setup a new userspace process in start_userspace() after it was clone()'ed.
+ * This function will run on a temporary stack page.
+ * It ptrace()'es itself, then
+ * Two pages are mapped into the userspace address space:
+ * - STUB_CODE (with EXEC), which contains the skas stub code
+ * - STUB_DATA (with R/W), which contains a data page that is used to transfer certain data between the UML userspace process and the UML kernel.
+ * Also for the userspace process a SIGSEGV handler is installed to catch pagefaults in the userspace process.
+ * And last the process stops itself to give control to the UML kernel for this userspace process.
+ *
+ * Return: Always zero, otherwise the current userspace process is ended with non null exit() call
+ */
 static int userspace_tramp(void *stack)
 {
        void *addr;
@@ -236,12 +251,24 @@ static int userspace_tramp(void *stack)
 
 int userspace_pid[NR_CPUS];
 
+/**
+ * start_userspace() - prepare a new userspace process
+ * @stub_stack:        pointer to the stub stack. Can be NULL, if? FIXME:
+ *
+ * Setups a new temporary stack page that is used while userspace_tramp() runs
+ * Clones the kernel process into a new userspace process, with FDs only.
+ *
+ * Return: When positive: the process id of the new userspace process,
+ *         when negative: an error number.
+ * FIXME: can PIDs become negative?!
+ */
 int start_userspace(unsigned long stub_stack)
 {
        void *stack;
        unsigned long sp;
        int pid, status, n, flags, err;
 
+       /* setup a temporary stack page */
        stack = mmap(NULL, UM_KERN_PAGE_SIZE,
                     PROT_READ | PROT_WRITE | PROT_EXEC,
                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -252,10 +279,12 @@ int start_userspace(unsigned long stub_stack)
                return err;
        }
 
+       /* set stack pointer to the end of the stack page, so it can grow downwards */
        sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *);
 
        flags = CLONE_FILES | SIGCHLD;
 
+       /* clone into new userspace process */
        pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
        if (pid < 0) {
                err = -errno;
@@ -323,11 +352,17 @@ void userspace(struct uml_pt_regs *regs)
                 * fail.  In this case, there is nothing to do but
                 * just kill the process.
                 */
-               if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp))
+               if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) {
+                       printk(UM_KERN_ERR "userspace - ptrace set regs "
+                              "failed, errno = %d\n", errno);
                        fatal_sigsegv();
+               }
 
-               if (put_fp_registers(pid, regs->fp))
+               if (put_fp_registers(pid, regs->fp)) {
+                       printk(UM_KERN_ERR "userspace - ptrace set fp regs "
+                              "failed, errno = %d\n", errno);
                        fatal_sigsegv();
+               }
 
                /* Now we set local_using_sysemu to be used for one loop */
                local_using_sysemu = get_using_sysemu();
index 22a358e..b1b6b75 100644 (file)
@@ -166,7 +166,7 @@ static void __init check_sysemu(void)
        unsigned long regs[MAX_REG_NR];
        int pid, n, status, count=0;
 
-       non_fatal("Checking syscall emulation patch for ptrace...");
+       os_info("Checking syscall emulation patch for ptrace...");
        sysemu_supported = 0;
        pid = start_ptraced_child();
 
@@ -199,10 +199,10 @@ static void __init check_sysemu(void)
                goto fail_stopped;
 
        sysemu_supported = 1;
-       non_fatal("OK\n");
+       os_info("OK\n");
        set_using_sysemu(!force_sysemu_disabled);
 
-       non_fatal("Checking advanced syscall emulation patch for ptrace...");
+       os_info("Checking advanced syscall emulation patch for ptrace...");
        pid = start_ptraced_child();
 
        if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
@@ -244,7 +244,7 @@ static void __init check_sysemu(void)
                goto fail_stopped;
 
        sysemu_supported = 2;
-       non_fatal("OK\n");
+       os_info("OK\n");
 
        if (!force_sysemu_disabled)
                set_using_sysemu(sysemu_supported);
@@ -260,7 +260,7 @@ static void __init check_ptrace(void)
 {
        int pid, syscall, n, status;
 
-       non_fatal("Checking that ptrace can change system call numbers...");
+       os_info("Checking that ptrace can change system call numbers...");
        pid = start_ptraced_child();
 
        if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
@@ -292,7 +292,7 @@ static void __init check_ptrace(void)
                }
        }
        stop_ptraced_child(pid, 0, 1);
-       non_fatal("OK\n");
+       os_info("OK\n");
        check_sysemu();
 }
 
@@ -308,15 +308,17 @@ static void __init check_coredump_limit(void)
                return;
        }
 
-       printf("Core dump limits :\n\tsoft - ");
+       os_info("Core dump limits :\n\tsoft - ");
        if (lim.rlim_cur == RLIM_INFINITY)
-               printf("NONE\n");
-       else printf("%lu\n", lim.rlim_cur);
+               os_info("NONE\n");
+       else
+               os_info("%llu\n", (unsigned long long)lim.rlim_cur);
 
-       printf("\thard - ");
+       os_info("\thard - ");
        if (lim.rlim_max == RLIM_INFINITY)
-               printf("NONE\n");
-       else printf("%lu\n", lim.rlim_max);
+               os_info("NONE\n");
+       else
+               os_info("%llu\n", (unsigned long long)lim.rlim_max);
 }
 
 void __init os_early_checks(void)
@@ -349,7 +351,7 @@ int __init parse_iomem(char *str, int *add)
        driver = str;
        file = strchr(str,',');
        if (file == NULL) {
-               fprintf(stderr, "parse_iomem : failed to parse iomem\n");
+               os_warn("parse_iomem : failed to parse iomem\n");
                goto out;
        }
        *file = '\0';
index c1dc892..998fbb4 100644 (file)
@@ -35,8 +35,9 @@ static int __init make_uml_dir(void)
 
                err = -ENOENT;
                if (home == NULL) {
-                       printk(UM_KERN_ERR "make_uml_dir : no value in "
-                              "environment for $HOME\n");
+                       printk(UM_KERN_ERR
+                               "%s: no value in environment for $HOME\n",
+                               __func__);
                        goto err;
                }
                strlcpy(dir, home, sizeof(dir));
@@ -50,13 +51,15 @@ static int __init make_uml_dir(void)
        err = -ENOMEM;
        uml_dir = malloc(strlen(dir) + 1);
        if (uml_dir == NULL) {
-               printf("make_uml_dir : malloc failed, errno = %d\n", errno);
+               printk(UM_KERN_ERR "%s : malloc failed, errno = %d\n",
+                       __func__, errno);
                goto err;
        }
        strcpy(uml_dir, dir);
 
        if ((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)) {
-               printf("Failed to mkdir '%s': %s\n", uml_dir, strerror(errno));
+               printk(UM_KERN_ERR "Failed to mkdir '%s': %s\n",
+                       uml_dir, strerror(errno));
                err = -errno;
                goto err_free;
        }
@@ -351,7 +354,7 @@ char *get_umid(void)
 static int __init set_uml_dir(char *name, int *add)
 {
        if (*name == '\0') {
-               printf("uml_dir can't be an empty string\n");
+               os_warn("uml_dir can't be an empty string\n");
                return 0;
        }
 
@@ -362,7 +365,7 @@ static int __init set_uml_dir(char *name, int *add)
 
        uml_dir = malloc(strlen(name) + 2);
        if (uml_dir == NULL) {
-               printf("Failed to malloc uml_dir - error = %d\n", errno);
+               os_warn("Failed to malloc uml_dir - error = %d\n", errno);
 
                /*
                 * Return 0 here because do_initcalls doesn't look at
@@ -387,8 +390,8 @@ static void remove_umid_dir(void)
        sprintf(dir, "%s%s", uml_dir, umid);
        err = remove_files_and_dir(dir);
        if (err)
-               printf("remove_umid_dir - remove_files_and_dir failed with "
-                      "err = %d\n", err);
+               os_warn("%s - remove_files_and_dir failed with err = %d\n",
+                       __func__, err);
 }
 
 __uml_exitcall(remove_umid_dir);
index faee55e..8cc8b26 100644 (file)
@@ -13,6 +13,7 @@
 #include <wait.h>
 #include <sys/mman.h>
 #include <sys/utsname.h>
+#include <init.h>
 #include <os.h>
 
 void stack_protections(unsigned long address)
@@ -152,3 +153,36 @@ void um_early_printk(const char *s, unsigned int n)
 {
        printf("%.*s", n, s);
 }
+
+static int quiet_info;
+
+static int __init quiet_cmd_param(char *str, int *add)
+{
+       quiet_info = 1;
+       return 0;
+}
+
+__uml_setup("quiet", quiet_cmd_param,
+"quiet\n"
+"    Turns off information messages during boot.\n\n");
+
+void os_info(const char *fmt, ...)
+{
+       va_list list;
+
+       if (quiet_info)
+               return;
+
+       va_start(list, fmt);
+       vfprintf(stderr, fmt, list);
+       va_end(list);
+}
+
+void os_warn(const char *fmt, ...)
+{
+       va_list list;
+
+       va_start(list, fmt);
+       vfprintf(stderr, fmt, list);
+       va_end(list);
+}
index 7a53a55..fda7e21 100644 (file)
@@ -1,66 +1,38 @@
-
 generic-y += atomic.h
-generic-y += auxvec.h
-generic-y += bitsperlong.h
 generic-y += bugs.h
 generic-y += clkdev.h
 generic-y += current.h
 generic-y += device.h
 generic-y += div64.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += exec.h
 generic-y += extable.h
 generic-y += fb.h
-generic-y += fcntl.h
 generic-y += ftrace.h
 generic-y += futex.h
 generic-y += hardirq.h
 generic-y += hw_irq.h
-generic-y += ioctl.h
-generic-y += ioctls.h
-generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
+generic-y += kprobes.h
 generic-y += local.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
-generic-y += mman.h
 generic-y += module.h
-generic-y += msgbuf.h
-generic-y += param.h
 generic-y += parport.h
 generic-y += percpu.h
-generic-y += poll.h
-generic-y += posix_types.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += sections.h
 generic-y += segment.h
-generic-y += sembuf.h
 generic-y += serial.h
-generic-y += setup.h
-generic-y += shmbuf.h
-generic-y += shmparam.h
-generic-y += signal.h
 generic-y += sizes.h
-generic-y += socket.h
-generic-y += sockios.h
-generic-y += stat.h
-generic-y += statfs.h
-generic-y += swab.h
 generic-y += syscalls.h
-generic-y += termbits.h
-generic-y += termios.h
 generic-y += topology.h
 generic-y += trace_clock.h
-generic-y += types.h
-generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += kprobes.h
index 1c44d3b..759a714 100644 (file)
@@ -1,5 +1,32 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += auxvec.h
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
 generic-y += kvm_para.h
+generic-y += mman.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += resource.h
+generic-y += sembuf.h
+generic-y += setup.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
 generic-y += siginfo.h
+generic-y += signal.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += swab.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
+generic-y += ucontext.h
index 94a1868..781521b 100644 (file)
@@ -50,6 +50,7 @@ config X86
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_FAST_MULTIPLIER
+       select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_GCOV_PROFILE_ALL
        select ARCH_HAS_KCOV                    if X86_64
        select ARCH_HAS_MMIO_FLUSH
@@ -162,6 +163,7 @@ config X86
        select HAVE_PCSPKR_PLATFORM
        select HAVE_PERF_EVENTS
        select HAVE_PERF_EVENTS_NMI
+       select HAVE_HARDLOCKUP_DETECTOR_PERF    if HAVE_PERF_EVENTS_NMI
        select HAVE_PERF_REGS
        select HAVE_PERF_USER_STACK_DUMP
        select HAVE_REGS_AND_STACK_ACCESS_API
index fcb7604..cd20ca0 100644 (file)
@@ -348,6 +348,7 @@ config X86_DEBUG_FPU
 
 config PUNIT_ATOM_DEBUG
        tristate "ATOM Punit debug driver"
+       depends on PCI
        select DEBUG_FS
        select IOSF_MBI
        ---help---
index 0d810fb..d88a2fd 100644 (file)
@@ -73,12 +73,13 @@ UBSAN_SANITIZE := n
 $(obj)/bzImage: asflags-y  := $(SVGA_MODE)
 
 quiet_cmd_image = BUILD   $@
+silent_redirect_image = >/dev/null
 cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \
-                              $(obj)/zoffset.h $@
+                              $(obj)/zoffset.h $@ $($(quiet)redirect_image)
 
 $(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
        $(call if_changed,image)
-       @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
+       @$(kecho) 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
 OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
 $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
index 2c860ad..8a95827 100644 (file)
@@ -34,6 +34,7 @@ KBUILD_CFLAGS += $(cflags-y)
 KBUILD_CFLAGS += -mno-mmx -mno-sse
 KBUILD_CFLAGS += $(call cc-option,-ffreestanding)
 KBUILD_CFLAGS += $(call cc-option,-fno-stack-protector)
+KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member)
 
 KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 GCOV_PROFILE := n
index 00241c8..a0838ab 100644 (file)
@@ -411,3 +411,8 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
        debug_putstr("done.\nBooting the kernel.\n");
        return output;
 }
+
+void fortify_panic(const char *name)
+{
+       error("detected buffer overflow");
+}
index 630e366..16f4912 100644 (file)
 #include "ctype.h"
 #include "string.h"
 
+/*
+ * Undef these macros so that the functions that we provide
+ * here will have the correct names regardless of how string.h
+ * may have chosen to #define them.
+ */
+#undef memcpy
+#undef memset
+#undef memcmp
+
 int memcmp(const void *s1, const void *s2, size_t len)
 {
        bool diff;
index 6cf79e1..0eb9f92 100644 (file)
@@ -1,5 +1,4 @@
 # CONFIG_64BIT is not set
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -125,7 +124,6 @@ CONFIG_NF_CONNTRACK_IPV4=y
 CONFIG_IP_NF_IPTABLES=y
 CONFIG_IP_NF_FILTER=y
 CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_ULOG=y
 CONFIG_NF_NAT=y
 CONFIG_IP_NF_TARGET_MASQUERADE=y
 CONFIG_IP_NF_MANGLE=y
@@ -255,7 +253,6 @@ CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_UHCI_HCD=y
 CONFIG_USB_PRINTER=y
 CONFIG_USB_STORAGE=y
-CONFIG_USB_LIBUSUAL=y
 CONFIG_EDAC=y
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_HCTOSYS is not set
index de45f57..4a4b16e 100644 (file)
@@ -1,4 +1,3 @@
-CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -124,7 +123,6 @@ CONFIG_NF_CONNTRACK_IPV4=y
 CONFIG_IP_NF_IPTABLES=y
 CONFIG_IP_NF_FILTER=y
 CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_ULOG=y
 CONFIG_NF_NAT=y
 CONFIG_IP_NF_TARGET_MASQUERADE=y
 CONFIG_IP_NF_MANGLE=y
@@ -251,7 +249,6 @@ CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_UHCI_HCD=y
 CONFIG_USB_PRINTER=y
 CONFIG_USB_STORAGE=y
-CONFIG_USB_LIBUSUAL=y
 CONFIG_EDAC=y
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_HCTOSYS is not set
index fc61739..f960a04 100644 (file)
@@ -201,7 +201,7 @@ asmlinkage void sha1_transform_avx2(u32 *digest, const char *data,
 
 static bool avx2_usable(void)
 {
-       if (avx_usable() && boot_cpu_has(X86_FEATURE_AVX2)
+       if (false && avx_usable() && boot_cpu_has(X86_FEATURE_AVX2)
                && boot_cpu_has(X86_FEATURE_BMI1)
                && boot_cpu_has(X86_FEATURE_BMI2))
                return true;
index a9a8027..d271fb7 100644 (file)
@@ -705,6 +705,7 @@ apicinterrupt X86_PLATFORM_IPI_VECTOR               x86_platform_ipi                smp_x86_platform_ipi
 #ifdef CONFIG_HAVE_KVM
 apicinterrupt3 POSTED_INTR_VECTOR              kvm_posted_intr_ipi             smp_kvm_posted_intr_ipi
 apicinterrupt3 POSTED_INTR_WAKEUP_VECTOR       kvm_posted_intr_wakeup_ipi      smp_kvm_posted_intr_wakeup_ipi
+apicinterrupt3 POSTED_INTR_NESTED_VECTOR       kvm_posted_intr_nested_ipi      smp_kvm_posted_intr_nested_ipi
 #endif
 
 #ifdef CONFIG_X86_MCE_THRESHOLD
index ff1ea2f..8e3db8f 100644 (file)
@@ -191,8 +191,8 @@ static void release_pmc_hardware(void) {}
 
 static bool check_hw_exists(void)
 {
-       u64 val, val_fail, val_new= ~0;
-       int i, reg, reg_fail, ret = 0;
+       u64 val, val_fail = -1, val_new= ~0;
+       int i, reg, reg_fail = -1, ret = 0;
        int bios_fail = 0;
        int reg_safe = -1;
 
index aa62437..98b0f07 100644 (file)
@@ -1708,6 +1708,120 @@ static __initconst const u64 glm_hw_cache_extra_regs
        },
 };
 
+static __initconst const u64 glp_hw_cache_event_ids
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+       [C(L1D)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = 0x81d0,       /* MEM_UOPS_RETIRED.ALL_LOADS */
+                       [C(RESULT_MISS)]        = 0x0,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = 0x82d0,       /* MEM_UOPS_RETIRED.ALL_STORES */
+                       [C(RESULT_MISS)]        = 0x0,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = 0x0,
+                       [C(RESULT_MISS)]        = 0x0,
+               },
+       },
+       [C(L1I)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = 0x0380,       /* ICACHE.ACCESSES */
+                       [C(RESULT_MISS)]        = 0x0280,       /* ICACHE.MISSES */
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = -1,
+                       [C(RESULT_MISS)]        = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = 0x0,
+                       [C(RESULT_MISS)]        = 0x0,
+               },
+       },
+       [C(LL)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = 0x1b7,        /* OFFCORE_RESPONSE */
+                       [C(RESULT_MISS)]        = 0x1b7,        /* OFFCORE_RESPONSE */
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = 0x1b7,        /* OFFCORE_RESPONSE */
+                       [C(RESULT_MISS)]        = 0x1b7,        /* OFFCORE_RESPONSE */
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = 0x0,
+                       [C(RESULT_MISS)]        = 0x0,
+               },
+       },
+       [C(DTLB)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = 0x81d0,       /* MEM_UOPS_RETIRED.ALL_LOADS */
+                       [C(RESULT_MISS)]        = 0xe08,        /* DTLB_LOAD_MISSES.WALK_COMPLETED */
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = 0x82d0,       /* MEM_UOPS_RETIRED.ALL_STORES */
+                       [C(RESULT_MISS)]        = 0xe49,        /* DTLB_STORE_MISSES.WALK_COMPLETED */
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = 0x0,
+                       [C(RESULT_MISS)]        = 0x0,
+               },
+       },
+       [C(ITLB)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = 0x00c0,       /* INST_RETIRED.ANY_P */
+                       [C(RESULT_MISS)]        = 0x0481,       /* ITLB.MISS */
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = -1,
+                       [C(RESULT_MISS)]        = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = -1,
+                       [C(RESULT_MISS)]        = -1,
+               },
+       },
+       [C(BPU)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = 0x00c4,       /* BR_INST_RETIRED.ALL_BRANCHES */
+                       [C(RESULT_MISS)]        = 0x00c5,       /* BR_MISP_RETIRED.ALL_BRANCHES */
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = -1,
+                       [C(RESULT_MISS)]        = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = -1,
+                       [C(RESULT_MISS)]        = -1,
+               },
+       },
+};
+
+static __initconst const u64 glp_hw_cache_extra_regs
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+       [C(LL)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = GLM_DEMAND_READ|
+                                                 GLM_LLC_ACCESS,
+                       [C(RESULT_MISS)]        = GLM_DEMAND_READ|
+                                                 GLM_LLC_MISS,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = GLM_DEMAND_WRITE|
+                                                 GLM_LLC_ACCESS,
+                       [C(RESULT_MISS)]        = GLM_DEMAND_WRITE|
+                                                 GLM_LLC_MISS,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = 0x0,
+                       [C(RESULT_MISS)]        = 0x0,
+               },
+       },
+};
+
 #define KNL_OT_L2_HITE         BIT_ULL(19) /* Other Tile L2 Hit */
 #define KNL_OT_L2_HITF         BIT_ULL(20) /* Other Tile L2 Hit */
 #define KNL_MCDRAM_LOCAL       BIT_ULL(21)
@@ -3016,6 +3130,9 @@ static int hsw_hw_config(struct perf_event *event)
        return 0;
 }
 
+static struct event_constraint counter0_constraint =
+                       INTEL_ALL_EVENT_CONSTRAINT(0, 0x1);
+
 static struct event_constraint counter2_constraint =
                        EVENT_CONSTRAINT(0, 0x4, 0);
 
@@ -3037,6 +3154,21 @@ hsw_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
        return c;
 }
 
+static struct event_constraint *
+glp_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
+                         struct perf_event *event)
+{
+       struct event_constraint *c;
+
+       /* :ppp means to do reduced skid PEBS which is PMC0 only. */
+       if (event->attr.precise_ip == 3)
+               return &counter0_constraint;
+
+       c = intel_get_event_constraints(cpuc, idx, event);
+
+       return c;
+}
+
 /*
  * Broadwell:
  *
@@ -3265,10 +3397,8 @@ static void intel_pmu_cpu_dying(int cpu)
 static void intel_pmu_sched_task(struct perf_event_context *ctx,
                                 bool sched_in)
 {
-       if (x86_pmu.pebs_active)
-               intel_pmu_pebs_sched_task(ctx, sched_in);
-       if (x86_pmu.lbr_nr)
-               intel_pmu_lbr_sched_task(ctx, sched_in);
+       intel_pmu_pebs_sched_task(ctx, sched_in);
+       intel_pmu_lbr_sched_task(ctx, sched_in);
 }
 
 PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
@@ -3838,6 +3968,32 @@ __init int intel_pmu_init(void)
                pr_cont("Goldmont events, ");
                break;
 
+       case INTEL_FAM6_ATOM_GEMINI_LAKE:
+               memcpy(hw_cache_event_ids, glp_hw_cache_event_ids,
+                      sizeof(hw_cache_event_ids));
+               memcpy(hw_cache_extra_regs, glp_hw_cache_extra_regs,
+                      sizeof(hw_cache_extra_regs));
+
+               intel_pmu_lbr_init_skl();
+
+               x86_pmu.event_constraints = intel_slm_event_constraints;
+               x86_pmu.pebs_constraints = intel_glp_pebs_event_constraints;
+               x86_pmu.extra_regs = intel_glm_extra_regs;
+               /*
+                * It's recommended to use CPU_CLK_UNHALTED.CORE_P + NPEBS
+                * for precise cycles.
+                */
+               x86_pmu.pebs_aliases = NULL;
+               x86_pmu.pebs_prec_dist = true;
+               x86_pmu.lbr_pt_coexist = true;
+               x86_pmu.flags |= PMU_FL_HAS_RSP_1;
+               x86_pmu.get_event_constraints = glp_get_event_constraints;
+               x86_pmu.cpu_events = glm_events_attrs;
+               /* Goldmont Plus has 4-wide pipeline */
+               event_attr_td_total_slots_scale_glm.event_str = "4";
+               pr_cont("Goldmont plus events, ");
+               break;
+
        case INTEL_FAM6_WESTMERE:
        case INTEL_FAM6_WESTMERE_EP:
        case INTEL_FAM6_WESTMERE_EX:
index 238ae32..4cf100f 100644 (file)
  * Model specific counters:
  *     MSR_CORE_C1_RES: CORE C1 Residency Counter
  *                      perf code: 0x00
- *                      Available model: SLM,AMT
+ *                      Available model: SLM,AMT,GLM
  *                      Scope: Core (each processor core has a MSR)
  *     MSR_CORE_C3_RESIDENCY: CORE C3 Residency Counter
  *                            perf code: 0x01
- *                            Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL
+ *                            Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,GLM
  *                            Scope: Core
  *     MSR_CORE_C6_RESIDENCY: CORE C6 Residency Counter
  *                            perf code: 0x02
  *                            Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW
- *                                             SKL,KNL
+ *                                             SKL,KNL,GLM
  *                            Scope: Core
  *     MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter
  *                            perf code: 0x03
  *                            Scope: Core
  *     MSR_PKG_C2_RESIDENCY:  Package C2 Residency Counter.
  *                            perf code: 0x00
- *                            Available model: SNB,IVB,HSW,BDW,SKL,KNL
+ *                            Available model: SNB,IVB,HSW,BDW,SKL,KNL,GLM
  *                            Scope: Package (physical package)
  *     MSR_PKG_C3_RESIDENCY:  Package C3 Residency Counter.
  *                            perf code: 0x01
  *                            Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,KNL
+ *                                             GLM
  *                            Scope: Package (physical package)
  *     MSR_PKG_C6_RESIDENCY:  Package C6 Residency Counter.
  *                            perf code: 0x02
  *                            Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW
- *                                             SKL,KNL
+ *                                             SKL,KNL,GLM
  *                            Scope: Package (physical package)
  *     MSR_PKG_C7_RESIDENCY:  Package C7 Residency Counter.
  *                            perf code: 0x03
@@ -82,7 +83,7 @@
  *                            Scope: Package (physical package)
  *     MSR_PKG_C10_RESIDENCY: Package C10 Residency Counter.
  *                            perf code: 0x06
- *                            Available model: HSW ULT only
+ *                            Available model: HSW ULT, GLM
  *                            Scope: Package (physical package)
  *
  */
@@ -504,6 +505,17 @@ static const struct cstate_model knl_cstates __initconst = {
 };
 
 
+static const struct cstate_model glm_cstates __initconst = {
+       .core_events            = BIT(PERF_CSTATE_CORE_C1_RES) |
+                                 BIT(PERF_CSTATE_CORE_C3_RES) |
+                                 BIT(PERF_CSTATE_CORE_C6_RES),
+
+       .pkg_events             = BIT(PERF_CSTATE_PKG_C2_RES) |
+                                 BIT(PERF_CSTATE_PKG_C3_RES) |
+                                 BIT(PERF_CSTATE_PKG_C6_RES) |
+                                 BIT(PERF_CSTATE_PKG_C10_RES),
+};
+
 
 #define X86_CSTATES_MODEL(model, states)                               \
        { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long) &(states) }
@@ -546,6 +558,8 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
 
        X86_CSTATES_MODEL(INTEL_FAM6_XEON_PHI_KNL, knl_cstates),
        X86_CSTATES_MODEL(INTEL_FAM6_XEON_PHI_KNM, knl_cstates),
+
+       X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT, glm_cstates),
        { },
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
index c6d23ff..a322fed 100644 (file)
@@ -606,12 +606,6 @@ static inline void intel_pmu_drain_pebs_buffer(void)
        x86_pmu.drain_pebs(&regs);
 }
 
-void intel_pmu_pebs_sched_task(struct perf_event_context *ctx, bool sched_in)
-{
-       if (!sched_in)
-               intel_pmu_drain_pebs_buffer();
-}
-
 /*
  * PEBS
  */
@@ -651,6 +645,12 @@ struct event_constraint intel_glm_pebs_event_constraints[] = {
        EVENT_CONSTRAINT_END
 };
 
+struct event_constraint intel_glp_pebs_event_constraints[] = {
+       /* Allow all events as PEBS with no flags */
+       INTEL_ALL_EVENT_CONSTRAINT(0, 0xf),
+       EVENT_CONSTRAINT_END
+};
+
 struct event_constraint intel_nehalem_pebs_event_constraints[] = {
        INTEL_PLD_CONSTRAINT(0x100b, 0xf),      /* MEM_INST_RETIRED.* */
        INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf),    /* MEM_UNCORE_RETIRED.* */
@@ -816,6 +816,14 @@ static inline bool pebs_needs_sched_cb(struct cpu_hw_events *cpuc)
        return cpuc->n_pebs && (cpuc->n_pebs == cpuc->n_large_pebs);
 }
 
+void intel_pmu_pebs_sched_task(struct perf_event_context *ctx, bool sched_in)
+{
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+       if (!sched_in && pebs_needs_sched_cb(cpuc))
+               intel_pmu_drain_pebs_buffer();
+}
+
 static inline void pebs_update_threshold(struct cpu_hw_events *cpuc)
 {
        struct debug_store *ds = cpuc->ds;
@@ -889,6 +897,8 @@ void intel_pmu_pebs_enable(struct perf_event *event)
        if (hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) {
                ds->pebs_event_reset[hwc->idx] =
                        (u64)(-hwc->sample_period) & x86_pmu.cntval_mask;
+       } else {
+               ds->pebs_event_reset[hwc->idx] = 0;
        }
 }
 
index eb26165..955457a 100644 (file)
@@ -380,8 +380,12 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
 
 void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in)
 {
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct x86_perf_task_context *task_ctx;
 
+       if (!cpuc->lbr_users)
+               return;
+
        /*
         * If LBR callstack feature is enabled and the stack was saved when
         * the task was scheduled out, restore the stack. Otherwise flush
index dae2fed..4f91276 100644 (file)
 #define SKX_UPI_PCI_PMON_CTL0          0x350
 #define SKX_UPI_PCI_PMON_CTR0          0x318
 #define SKX_UPI_PCI_PMON_BOX_CTL       0x378
-#define SKX_PMON_CTL_UMASK_EXT         0xff
+#define SKX_UPI_CTL_UMASK_EXT          0xffefff
 
 /* SKX M2M */
 #define SKX_M2M_PCI_PMON_CTL0          0x228
@@ -328,7 +328,7 @@ DEFINE_UNCORE_FORMAT_ATTR(event2, event, "config:0-6");
 DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
 DEFINE_UNCORE_FORMAT_ATTR(use_occ_ctr, use_occ_ctr, "config:7");
 DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
-DEFINE_UNCORE_FORMAT_ATTR(umask_ext, umask, "config:8-15,32-39");
+DEFINE_UNCORE_FORMAT_ATTR(umask_ext, umask, "config:8-15,32-43,45-55");
 DEFINE_UNCORE_FORMAT_ATTR(qor, qor, "config:16");
 DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
 DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
@@ -351,7 +351,6 @@ DEFINE_UNCORE_FORMAT_ATTR(filter_cid, filter_cid, "config1:5");
 DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8");
 DEFINE_UNCORE_FORMAT_ATTR(filter_link2, filter_link, "config1:6-8");
 DEFINE_UNCORE_FORMAT_ATTR(filter_link3, filter_link, "config1:12");
-DEFINE_UNCORE_FORMAT_ATTR(filter_link4, filter_link, "config1:9-12");
 DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17");
 DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47");
 DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22");
@@ -3302,7 +3301,6 @@ static struct attribute *skx_uncore_cha_formats_attr[] = {
        &format_attr_inv.attr,
        &format_attr_thresh8.attr,
        &format_attr_filter_tid4.attr,
-       &format_attr_filter_link4.attr,
        &format_attr_filter_state5.attr,
        &format_attr_filter_rem.attr,
        &format_attr_filter_loc.attr,
@@ -3312,7 +3310,6 @@ static struct attribute *skx_uncore_cha_formats_attr[] = {
        &format_attr_filter_opc_0.attr,
        &format_attr_filter_opc_1.attr,
        &format_attr_filter_nc.attr,
-       &format_attr_filter_c6.attr,
        &format_attr_filter_isoc.attr,
        NULL,
 };
@@ -3333,8 +3330,11 @@ static struct extra_reg skx_uncore_cha_extra_regs[] = {
        SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
        SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x2134, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x8134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x3134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x9134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x35, 0xff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x36, 0xff, 0x8),
+       EVENT_EXTRA_END
 };
 
 static u64 skx_cha_filter_mask(int fields)
@@ -3347,6 +3347,17 @@ static u64 skx_cha_filter_mask(int fields)
                mask |= SKX_CHA_MSR_PMON_BOX_FILTER_LINK;
        if (fields & 0x4)
                mask |= SKX_CHA_MSR_PMON_BOX_FILTER_STATE;
+       if (fields & 0x8) {
+               mask |= SKX_CHA_MSR_PMON_BOX_FILTER_REM;
+               mask |= SKX_CHA_MSR_PMON_BOX_FILTER_LOC;
+               mask |= SKX_CHA_MSR_PMON_BOX_FILTER_ALL_OPC;
+               mask |= SKX_CHA_MSR_PMON_BOX_FILTER_NM;
+               mask |= SKX_CHA_MSR_PMON_BOX_FILTER_NOT_NM;
+               mask |= SKX_CHA_MSR_PMON_BOX_FILTER_OPC0;
+               mask |= SKX_CHA_MSR_PMON_BOX_FILTER_OPC1;
+               mask |= SKX_CHA_MSR_PMON_BOX_FILTER_NC;
+               mask |= SKX_CHA_MSR_PMON_BOX_FILTER_ISOC;
+       }
        return mask;
 }
 
@@ -3492,6 +3503,26 @@ static struct intel_uncore_type skx_uncore_irp = {
        .format_group           = &skx_uncore_format_group,
 };
 
+static struct attribute *skx_uncore_pcu_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_occ_invert.attr,
+       &format_attr_occ_edge_det.attr,
+       &format_attr_filter_band0.attr,
+       &format_attr_filter_band1.attr,
+       &format_attr_filter_band2.attr,
+       &format_attr_filter_band3.attr,
+       NULL,
+};
+
+static struct attribute_group skx_uncore_pcu_format_group = {
+       .name = "format",
+       .attrs = skx_uncore_pcu_formats_attr,
+};
+
 static struct intel_uncore_ops skx_uncore_pcu_ops = {
        IVBEP_UNCORE_MSR_OPS_COMMON_INIT(),
        .hw_config              = hswep_pcu_hw_config,
@@ -3510,7 +3541,7 @@ static struct intel_uncore_type skx_uncore_pcu = {
        .box_ctl                = HSWEP_PCU_MSR_PMON_BOX_CTL,
        .num_shared_regs        = 1,
        .ops                    = &skx_uncore_pcu_ops,
-       .format_group           = &snbep_uncore_pcu_format_group,
+       .format_group           = &skx_uncore_pcu_format_group,
 };
 
 static struct intel_uncore_type *skx_msr_uncores[] = {
@@ -3603,8 +3634,8 @@ static struct intel_uncore_type skx_uncore_upi = {
        .perf_ctr_bits  = 48,
        .perf_ctr       = SKX_UPI_PCI_PMON_CTR0,
        .event_ctl      = SKX_UPI_PCI_PMON_CTL0,
-       .event_mask     = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
-       .event_mask_ext = SKX_PMON_CTL_UMASK_EXT,
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,
+       .event_mask_ext = SKX_UPI_CTL_UMASK_EXT,
        .box_ctl        = SKX_UPI_PCI_PMON_BOX_CTL,
        .ops            = &skx_upi_uncore_pci_ops,
        .format_group   = &skx_upi_uncore_format_group,
index 53728ee..476aec3 100644 (file)
@@ -879,6 +879,8 @@ extern struct event_constraint intel_slm_pebs_event_constraints[];
 
 extern struct event_constraint intel_glm_pebs_event_constraints[];
 
+extern struct event_constraint intel_glp_pebs_event_constraints[];
+
 extern struct event_constraint intel_nehalem_pebs_event_constraints[];
 
 extern struct event_constraint intel_westmere_pebs_event_constraints[];
index 39e702d..aa6b202 100644 (file)
@@ -35,7 +35,7 @@
 #define _BUG_FLAGS(ins, flags)                                         \
 do {                                                                   \
        asm volatile("1:\t" ins "\n"                                    \
-                    ".pushsection __bug_table,\"a\"\n"                 \
+                    ".pushsection __bug_table,\"aw\"\n"                \
                     "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n"   \
                     "\t"  __BUG_REL(%c0) "\t# bug_entry::file\n"       \
                     "\t.word %c1"        "\t# bug_entry::line\n"       \
@@ -52,7 +52,7 @@ do {                                                                  \
 #define _BUG_FLAGS(ins, flags)                                         \
 do {                                                                   \
        asm volatile("1:\t" ins "\n"                                    \
-                    ".pushsection __bug_table,\"a\"\n"                 \
+                    ".pushsection __bug_table,\"aw\"\n"                \
                     "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n"   \
                     "\t.word %c0"        "\t# bug_entry::flags\n"      \
                     "\t.org 2b+%c1\n"                                  \
index 2701e5f..ca3c48c 100644 (file)
 #define X86_FEATURE_PAUSEFILTER (15*32+10) /* filtered pause intercept */
 #define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */
 #define X86_FEATURE_AVIC       (15*32+13) /* Virtual Interrupt Controller */
+#define X86_FEATURE_VIRTUAL_VMLOAD_VMSAVE (15*32+15) /* Virtual VMLOAD VMSAVE */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx), word 16 */
 #define X86_FEATURE_AVX512VBMI  (16*32+ 1) /* AVX512 Vector Bit Manipulation instructions*/
index d2ff779..796ff6c 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifdef CONFIG_X86_32
 
-extern unsigned long asmlinkage efi_call_phys(void *, ...);
+extern asmlinkage unsigned long efi_call_phys(void *, ...);
 
 #define arch_efi_call_virt_setup()     kernel_fpu_begin()
 #define arch_efi_call_virt_teardown()  kernel_fpu_end()
@@ -52,7 +52,7 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
 
 #define EFI_LOADER_SIGNATURE   "EL64"
 
-extern u64 asmlinkage efi_call(void *fp, ...);
+extern asmlinkage u64 efi_call(void *fp, ...);
 
 #define efi_call_phys(f, args...)              efi_call((f), args)
 
index df00299..07b0695 100644 (file)
@@ -25,6 +25,8 @@ BUILD_INTERRUPT3(kvm_posted_intr_ipi, POSTED_INTR_VECTOR,
                 smp_kvm_posted_intr_ipi)
 BUILD_INTERRUPT3(kvm_posted_intr_wakeup_ipi, POSTED_INTR_WAKEUP_VECTOR,
                 smp_kvm_posted_intr_wakeup_ipi)
+BUILD_INTERRUPT3(kvm_posted_intr_nested_ipi, POSTED_INTR_NESTED_VECTOR,
+                smp_kvm_posted_intr_nested_ipi)
 #endif
 
 /*
index 9b76cd3..ad1ed53 100644 (file)
@@ -15,6 +15,7 @@ typedef struct {
 #ifdef CONFIG_HAVE_KVM
        unsigned int kvm_posted_intr_ipis;
        unsigned int kvm_posted_intr_wakeup_ipis;
+       unsigned int kvm_posted_intr_nested_ipis;
 #endif
        unsigned int x86_platform_ipis; /* arch dependent */
        unsigned int apic_perf_irqs;
index b90e105..d6dbafb 100644 (file)
@@ -30,6 +30,7 @@ extern asmlinkage void apic_timer_interrupt(void);
 extern asmlinkage void x86_platform_ipi(void);
 extern asmlinkage void kvm_posted_intr_ipi(void);
 extern asmlinkage void kvm_posted_intr_wakeup_ipi(void);
+extern asmlinkage void kvm_posted_intr_nested_ipi(void);
 extern asmlinkage void error_interrupt(void);
 extern asmlinkage void irq_work_interrupt(void);
 
@@ -62,6 +63,7 @@ extern void trace_call_function_single_interrupt(void);
 #define trace_reboot_interrupt  reboot_interrupt
 #define trace_kvm_posted_intr_ipi kvm_posted_intr_ipi
 #define trace_kvm_posted_intr_wakeup_ipi kvm_posted_intr_wakeup_ipi
+#define trace_kvm_posted_intr_nested_ipi kvm_posted_intr_nested_ipi
 #endif /* CONFIG_TRACING */
 
 #ifdef CONFIG_X86_LOCAL_APIC
index 7afb0e2..48febf0 100644 (file)
@@ -328,13 +328,13 @@ static inline unsigned type in##bwl##_p(int port)                 \
 static inline void outs##bwl(int port, const void *addr, unsigned long count) \
 {                                                                      \
        asm volatile("rep; outs" #bwl                                   \
-                    : "+S"(addr), "+c"(count) : "d"(port));            \
+                    : "+S"(addr), "+c"(count) : "d"(port) : "memory"); \
 }                                                                      \
                                                                        \
 static inline void ins##bwl(int port, void *addr, unsigned long count) \
 {                                                                      \
        asm volatile("rep; ins" #bwl                                    \
-                    : "+D"(addr), "+c"(count) : "d"(port));            \
+                    : "+D"(addr), "+c"(count) : "d"(port) : "memory"); \
 }
 
 BUILDIO(b, b, char)
index 6ca9fd6..aaf8d28 100644 (file)
@@ -83,7 +83,6 @@
  */
 #define X86_PLATFORM_IPI_VECTOR                0xf7
 
-#define POSTED_INTR_WAKEUP_VECTOR      0xf1
 /*
  * IRQ work vector:
  */
@@ -98,6 +97,8 @@
 /* Vector for KVM to deliver posted interrupt IPI */
 #ifdef CONFIG_HAVE_KVM
 #define POSTED_INTR_VECTOR             0xf2
+#define POSTED_INTR_WAKEUP_VECTOR      0xf1
+#define POSTED_INTR_NESTED_VECTOR      0xf0
 #endif
 
 /*
index 34b984c..6cf6543 100644 (file)
@@ -52,10 +52,10 @@ typedef u8 kprobe_opcode_t;
 #define flush_insn_slot(p)     do { } while (0)
 
 /* optinsn template addresses */
-extern __visible kprobe_opcode_t optprobe_template_entry;
-extern __visible kprobe_opcode_t optprobe_template_val;
-extern __visible kprobe_opcode_t optprobe_template_call;
-extern __visible kprobe_opcode_t optprobe_template_end;
+extern __visible kprobe_opcode_t optprobe_template_entry[];
+extern __visible kprobe_opcode_t optprobe_template_val[];
+extern __visible kprobe_opcode_t optprobe_template_call[];
+extern __visible kprobe_opcode_t optprobe_template_end[];
 #define MAX_OPTIMIZED_LENGTH (MAX_INSN_SIZE + RELATIVE_ADDR_SIZE)
 #define MAX_OPTINSN_SIZE                               \
        (((unsigned long)&optprobe_template_end -       \
index 722d0e5..fde36f1 100644 (file)
@@ -23,6 +23,7 @@ struct x86_exception {
        u16 error_code;
        bool nested_page_fault;
        u64 address; /* cr2 or nested page fault gpa */
+       u8 async_page_fault;
 };
 
 /*
index 1588e9e..87ac4fb 100644 (file)
@@ -462,10 +462,12 @@ struct kvm_vcpu_hv_synic {
        DECLARE_BITMAP(auto_eoi_bitmap, 256);
        DECLARE_BITMAP(vec_bitmap, 256);
        bool active;
+       bool dont_zero_synic_pages;
 };
 
 /* Hyper-V per vcpu emulation context */
 struct kvm_vcpu_hv {
+       u32 vp_index;
        u64 hv_vapic;
        s64 runtime_offset;
        struct kvm_vcpu_hv_synic synic;
@@ -549,6 +551,7 @@ struct kvm_vcpu_arch {
                bool reinject;
                u8 nr;
                u32 error_code;
+               u8 nested_apf;
        } exception;
 
        struct kvm_queued_interrupt {
@@ -649,6 +652,9 @@ struct kvm_vcpu_arch {
                u64 msr_val;
                u32 id;
                bool send_user_only;
+               u32 host_apf_reason;
+               unsigned long nested_apf_token;
+               bool delivery_as_pf_vmexit;
        } apf;
 
        /* OSVW MSRs (AMD only) */
@@ -803,6 +809,7 @@ struct kvm_arch {
        int audit_point;
        #endif
 
+       bool backwards_tsc_observed;
        bool boot_vcpu_runs_old_kvmclock;
        u32 bsp_vcpu_id;
 
@@ -952,9 +959,7 @@ struct kvm_x86_ops {
                                unsigned char *hypercall_addr);
        void (*set_irq)(struct kvm_vcpu *vcpu);
        void (*set_nmi)(struct kvm_vcpu *vcpu);
-       void (*queue_exception)(struct kvm_vcpu *vcpu, unsigned nr,
-                               bool has_error_code, u32 error_code,
-                               bool reinject);
+       void (*queue_exception)(struct kvm_vcpu *vcpu);
        void (*cancel_injection)(struct kvm_vcpu *vcpu);
        int (*interrupt_allowed)(struct kvm_vcpu *vcpu);
        int (*nmi_allowed)(struct kvm_vcpu *vcpu);
index ecfcb66..265c907 100644 (file)
@@ -293,7 +293,7 @@ static inline unsigned long __get_current_cr3_fast(void)
        unsigned long cr3 = __pa(this_cpu_read(cpu_tlbstate.loaded_mm)->pgd);
 
        /* For now, be very restrictive about when this can be called. */
-       VM_WARN_ON(in_nmi() || !in_atomic());
+       VM_WARN_ON(in_nmi() || preemptible());
 
        VM_BUG_ON(cr3 != __read_cr3());
        return cr3;
index cb976ba..9ffc36b 100644 (file)
@@ -84,7 +84,7 @@ struct pv_init_ops {
         */
        unsigned (*patch)(u8 type, u16 clobber, void *insnbuf,
                          unsigned long addr, unsigned len);
-};
+} __no_randomize_layout;
 
 
 struct pv_lazy_ops {
@@ -92,12 +92,12 @@ struct pv_lazy_ops {
        void (*enter)(void);
        void (*leave)(void);
        void (*flush)(void);
-};
+} __no_randomize_layout;
 
 struct pv_time_ops {
        unsigned long long (*sched_clock)(void);
        unsigned long long (*steal_clock)(int cpu);
-};
+} __no_randomize_layout;
 
 struct pv_cpu_ops {
        /* hooks for various privileged instructions */
@@ -176,7 +176,7 @@ struct pv_cpu_ops {
 
        void (*start_context_switch)(struct task_struct *prev);
        void (*end_context_switch)(struct task_struct *next);
-};
+} __no_randomize_layout;
 
 struct pv_irq_ops {
        /*
@@ -199,7 +199,7 @@ struct pv_irq_ops {
 #ifdef CONFIG_X86_64
        void (*adjust_exception_frame)(void);
 #endif
-};
+} __no_randomize_layout;
 
 struct pv_mmu_ops {
        unsigned long (*read_cr2)(void);
@@ -305,7 +305,7 @@ struct pv_mmu_ops {
           an mfn.  We can tell which is which from the index. */
        void (*set_fixmap)(unsigned /* enum fixed_addresses */ idx,
                           phys_addr_t phys, pgprot_t flags);
-};
+} __no_randomize_layout;
 
 struct arch_spinlock;
 #ifdef CONFIG_SMP
@@ -322,7 +322,7 @@ struct pv_lock_ops {
        void (*kick)(int cpu);
 
        struct paravirt_callee_save vcpu_is_preempted;
-};
+} __no_randomize_layout;
 
 /* This contains all the paravirt structures: we get a convenient
  * number for each function using the offset which we use to indicate
@@ -334,7 +334,7 @@ struct paravirt_patch_template {
        struct pv_irq_ops pv_irq_ops;
        struct pv_mmu_ops pv_mmu_ops;
        struct pv_lock_ops pv_lock_ops;
-};
+} __no_randomize_layout;
 
 extern struct pv_info pv_info;
 extern struct pv_init_ops pv_init_ops;
index 6a79547..028245e 100644 (file)
@@ -129,7 +129,7 @@ struct cpuinfo_x86 {
        /* Index into per_cpu list: */
        u16                     cpu_index;
        u32                     microcode;
-};
+} __randomize_layout;
 
 struct cpuid_regs {
        u32 eax, ebx, ecx, edx;
index dcbd9bc..8abedf1 100644 (file)
@@ -74,6 +74,7 @@ static __always_inline void boot_init_stack_canary(void)
        get_random_bytes(&canary, sizeof(canary));
        tsc = rdtsc();
        canary += tsc + (tsc << 32UL);
+       canary &= CANARY_MASK;
 
        current->stack_canary = canary;
 #ifdef CONFIG_X86_64
index 3d3e835..e9ee848 100644 (file)
@@ -142,7 +142,9 @@ static __always_inline void *__constant_memcpy(void *to, const void *from,
 }
 
 #define __HAVE_ARCH_MEMCPY
+extern void *memcpy(void *, const void *, size_t);
 
+#ifndef CONFIG_FORTIFY_SOURCE
 #ifdef CONFIG_X86_USE_3DNOW
 
 #include <asm/mmx.h>
@@ -195,11 +197,15 @@ static inline void *__memcpy3d(void *to, const void *from, size_t len)
 #endif
 
 #endif
+#endif /* !CONFIG_FORTIFY_SOURCE */
 
 #define __HAVE_ARCH_MEMMOVE
 void *memmove(void *dest, const void *src, size_t n);
 
+extern int memcmp(const void *, const void *, size_t);
+#ifndef CONFIG_FORTIFY_SOURCE
 #define memcmp __builtin_memcmp
+#endif
 
 #define __HAVE_ARCH_MEMCHR
 extern void *memchr(const void *cs, int c, size_t count);
@@ -321,6 +327,8 @@ void *__constant_c_and_count_memset(void *s, unsigned long pattern,
         : __memset_generic((s), (c), (count)))
 
 #define __HAVE_ARCH_MEMSET
+extern void *memset(void *, int, size_t);
+#ifndef CONFIG_FORTIFY_SOURCE
 #if (__GNUC__ >= 4)
 #define memset(s, c, count) __builtin_memset(s, c, count)
 #else
@@ -330,6 +338,7 @@ void *__constant_c_and_count_memset(void *s, unsigned long pattern,
                                 (count))                               \
         : __memset((s), (c), (count)))
 #endif
+#endif /* !CONFIG_FORTIFY_SOURCE */
 
 /*
  * find the first occurrence of byte 'c', or 1 past the area if none
index 1f22bc2..2a8c822 100644 (file)
@@ -31,6 +31,7 @@ static __always_inline void *__inline_memcpy(void *to, const void *from, size_t
 extern void *memcpy(void *to, const void *from, size_t len);
 extern void *__memcpy(void *to, const void *from, size_t len);
 
+#ifndef CONFIG_FORTIFY_SOURCE
 #ifndef CONFIG_KMEMCHECK
 #if (__GNUC__ == 4 && __GNUC_MINOR__ < 3) || __GNUC__ < 4
 #define memcpy(dst, src, len)                                  \
@@ -51,6 +52,7 @@ extern void *__memcpy(void *to, const void *from, size_t len);
  */
 #define memcpy(dst, src, len) __inline_memcpy((dst), (src), (len))
 #endif
+#endif /* !CONFIG_FORTIFY_SOURCE */
 
 #define __HAVE_ARCH_MEMSET
 void *memset(void *s, int c, size_t n);
@@ -77,6 +79,11 @@ int strcmp(const char *cs, const char *ct);
 #define memcpy(dst, src, len) __memcpy(dst, src, len)
 #define memmove(dst, src, len) __memmove(dst, src, len)
 #define memset(s, c, n) __memset(s, c, n)
+
+#ifndef __NO_FORTIFY
+#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */
+#endif
+
 #endif
 
 #define __HAVE_ARCH_MEMCPY_MCSAFE 1
index 14824fc..58fffe7 100644 (file)
@@ -83,7 +83,7 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
        u32 event_inj;
        u32 event_inj_err;
        u64 nested_cr3;
-       u64 lbr_ctl;
+       u64 virt_ext;
        u32 clean;
        u32 reserved_5;
        u64 next_rip;
@@ -119,6 +119,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
 #define AVIC_ENABLE_SHIFT 31
 #define AVIC_ENABLE_MASK (1 << AVIC_ENABLE_SHIFT)
 
+#define LBR_CTL_ENABLE_MASK BIT_ULL(0)
+#define VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK BIT_ULL(1)
+
 #define SVM_INTERRUPT_SHADOW_MASK 1
 
 #define SVM_IOIO_STR_SHIFT 2
index 476ea27..30269da 100644 (file)
@@ -535,9 +535,6 @@ struct __large_struct { unsigned long buf[100]; };
 #define __put_user(x, ptr)                                             \
        __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
 
-#define __get_user_unaligned __get_user
-#define __put_user_unaligned __put_user
-
 /*
  * {get|put}_user_try and catch
  *
index cff0bb6..a965e5b 100644 (file)
@@ -67,6 +67,7 @@ struct kvm_clock_pairing {
 
 #define KVM_ASYNC_PF_ENABLED                   (1 << 0)
 #define KVM_ASYNC_PF_SEND_ALWAYS               (1 << 1)
+#define KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT     (1 << 2)
 
 /* Operations for KVM_HC_MMU_OP */
 #define KVM_MMU_OP_WRITE_PTE            1
index 6bb6806..7491e73 100644 (file)
@@ -347,6 +347,14 @@ static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
        struct mpc_intsrc mp_irq;
 
        /*
+        * Check bus_irq boundary.
+        */
+       if (bus_irq >= NR_IRQS_LEGACY) {
+               pr_warn("Invalid bus_irq %u for legacy override\n", bus_irq);
+               return;
+       }
+
+       /*
         * Convert 'gsi' to 'ioapic.pin'.
         */
        ioapic = mp_find_ioapic(gsi);
index c73c9fb..d6f3877 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 
-#ifdef CONFIG_HARDLOCKUP_DETECTOR
+#ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF
 u64 hw_nmi_get_sample_period(int watchdog_thresh)
 {
        return (u64)(cpu_khz) * 1000 * watchdog_thresh;
index b4f5f73..237e9c2 100644 (file)
@@ -2093,7 +2093,7 @@ static inline void __init check_timer(void)
                        int idx;
                        idx = find_irq_entry(apic1, pin1, mp_INT);
                        if (idx != -1 && irq_trigger(idx))
-                               unmask_ioapic_irq(irq_get_chip_data(0));
+                               unmask_ioapic_irq(irq_get_irq_data(0));
                }
                irq_domain_deactivate_irq(irq_data);
                irq_domain_activate_irq(irq_data);
index bb5abe8..3b9e220 100644 (file)
@@ -134,6 +134,7 @@ static void init_amd_k6(struct cpuinfo_x86 *c)
 
                n = K6_BUG_LOOP;
                f_vide = vide;
+               OPTIMIZER_HIDE_VAR(f_vide);
                d = rdtsc();
                while (n--)
                        f_vide();
index 22217ec..44404e2 100644 (file)
@@ -457,7 +457,7 @@ static int prepare_elf64_headers(struct crash_elf_data *ced,
        bufp += sizeof(Elf64_Phdr);
        phdr->p_type = PT_NOTE;
        phdr->p_offset = phdr->p_paddr = paddr_vmcoreinfo_note();
-       phdr->p_filesz = phdr->p_memsz = sizeof(vmcoreinfo_note);
+       phdr->p_filesz = phdr->p_memsz = VMCOREINFO_NOTE_SIZE;
        (ehdr->e_phnum)++;
 
 #ifdef CONFIG_X86_64
index 3fe45f8..cbf1f6b 100644 (file)
@@ -235,8 +235,7 @@ static void __init dtb_add_ioapic(struct device_node *dn)
 
        ret = of_address_to_resource(dn, 0, &r);
        if (ret) {
-               printk(KERN_ERR "Can't obtain address from node %s.\n",
-                               dn->full_name);
+               printk(KERN_ERR "Can't obtain address from device node %pOF.\n", dn);
                return;
        }
        mp_register_ioapic(++ioapic_id, r.start, gsi_top, &cfg);
index 4aa03c5..4ed0aba 100644 (file)
@@ -155,6 +155,12 @@ int arch_show_interrupts(struct seq_file *p, int prec)
                seq_printf(p, "%10u ", irq_stats(j)->kvm_posted_intr_ipis);
        seq_puts(p, "  Posted-interrupt notification event\n");
 
+       seq_printf(p, "%*s: ", prec, "NPI");
+       for_each_online_cpu(j)
+               seq_printf(p, "%10u ",
+                          irq_stats(j)->kvm_posted_intr_nested_ipis);
+       seq_puts(p, "  Nested posted-interrupt event\n");
+
        seq_printf(p, "%*s: ", prec, "PIW");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ",
@@ -313,6 +319,19 @@ __visible void smp_kvm_posted_intr_wakeup_ipi(struct pt_regs *regs)
        exiting_irq();
        set_irq_regs(old_regs);
 }
+
+/*
+ * Handler for POSTED_INTERRUPT_NESTED_VECTOR.
+ */
+__visible void smp_kvm_posted_intr_nested_ipi(struct pt_regs *regs)
+{
+       struct pt_regs *old_regs = set_irq_regs(regs);
+
+       entering_ack_irq();
+       inc_irq_stat(kvm_posted_intr_nested_ipis);
+       exiting_irq();
+       set_irq_regs(old_regs);
+}
 #endif
 
 __visible void __irq_entry smp_trace_x86_platform_ipi(struct pt_regs *regs)
index 7468c69..c7fd185 100644 (file)
@@ -150,6 +150,8 @@ static void __init apic_intr_init(void)
        alloc_intr_gate(POSTED_INTR_VECTOR, kvm_posted_intr_ipi);
        /* IPI for KVM to deliver interrupt to wake up tasks */
        alloc_intr_gate(POSTED_INTR_WAKEUP_VECTOR, kvm_posted_intr_wakeup_ipi);
+       /* IPI for KVM to deliver nested posted interrupt */
+       alloc_intr_gate(POSTED_INTR_NESTED_VECTOR, kvm_posted_intr_nested_ipi);
 #endif
 
        /* IPI vectors for APIC spurious and error interrupts */
index 6b87780..f015371 100644 (file)
@@ -457,6 +457,8 @@ static int arch_copy_kprobe(struct kprobe *p)
 
 int arch_prepare_kprobe(struct kprobe *p)
 {
+       int ret;
+
        if (alternatives_text_reserved(p->addr, p->addr))
                return -EINVAL;
 
@@ -467,7 +469,13 @@ int arch_prepare_kprobe(struct kprobe *p)
        if (!p->ainsn.insn)
                return -ENOMEM;
 
-       return arch_copy_kprobe(p);
+       ret = arch_copy_kprobe(p);
+       if (ret) {
+               free_insn_slot(p->ainsn.insn, 0);
+               p->ainsn.insn = NULL;
+       }
+
+       return ret;
 }
 
 void arch_arm_kprobe(struct kprobe *p)
index 43e10d6..71c17a5 100644 (file)
@@ -330,7 +330,12 @@ static void kvm_guest_cpu_init(void)
 #ifdef CONFIG_PREEMPT
                pa |= KVM_ASYNC_PF_SEND_ALWAYS;
 #endif
-               wrmsrl(MSR_KVM_ASYNC_PF_EN, pa | KVM_ASYNC_PF_ENABLED);
+               pa |= KVM_ASYNC_PF_ENABLED;
+
+               /* Async page fault support for L1 hypervisor is optional */
+               if (wrmsr_safe(MSR_KVM_ASYNC_PF_EN,
+                       (pa | KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT) & 0xffffffff, pa >> 32) < 0)
+                       wrmsrl(MSR_KVM_ASYNC_PF_EN, pa);
                __this_cpu_write(apf_reason.enabled, 1);
                printk(KERN_INFO"KVM setup async PF for cpu %d\n",
                       smp_processor_id());
index 67393fc..a56bf60 100644 (file)
@@ -471,12 +471,12 @@ static int __init reboot_init(void)
 
        /*
         * The DMI quirks table takes precedence. If no quirks entry
-        * matches and the ACPI Hardware Reduced bit is set, force EFI
-        * reboot.
+        * matches and the ACPI Hardware Reduced bit is set and EFI
+        * runtime services are enabled, force EFI reboot.
         */
        rv = dmi_check_system(reboot_dmi_table);
 
-       if (!rv && efi_reboot_required())
+       if (!rv && efi_reboot_required() && !efi_runtime_disabled())
                reboot_type = BOOT_EFI;
 
        return 0;
index 760433b..2688c7d 100644 (file)
@@ -22,7 +22,7 @@ config KVM
        depends on HAVE_KVM
        depends on HIGH_RES_TIMERS
        # for TASKSTATS/TASK_DELAY_ACCT:
-       depends on NET
+       depends on NET && MULTIUSER
        select PREEMPT_NOTIFIERS
        select MMU_NOTIFIER
        select ANON_INODES
index ebae57a..337b6d2 100644 (file)
@@ -106,14 +106,27 @@ static int synic_set_sint(struct kvm_vcpu_hv_synic *synic, int sint,
        return 0;
 }
 
-static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vcpu_id)
+static struct kvm_vcpu *get_vcpu_by_vpidx(struct kvm *kvm, u32 vpidx)
+{
+       struct kvm_vcpu *vcpu = NULL;
+       int i;
+
+       if (vpidx < KVM_MAX_VCPUS)
+               vcpu = kvm_get_vcpu(kvm, vpidx);
+       if (vcpu && vcpu_to_hv_vcpu(vcpu)->vp_index == vpidx)
+               return vcpu;
+       kvm_for_each_vcpu(i, vcpu, kvm)
+               if (vcpu_to_hv_vcpu(vcpu)->vp_index == vpidx)
+                       return vcpu;
+       return NULL;
+}
+
+static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vpidx)
 {
        struct kvm_vcpu *vcpu;
        struct kvm_vcpu_hv_synic *synic;
 
-       if (vcpu_id >= atomic_read(&kvm->online_vcpus))
-               return NULL;
-       vcpu = kvm_get_vcpu(kvm, vcpu_id);
+       vcpu = get_vcpu_by_vpidx(kvm, vpidx);
        if (!vcpu)
                return NULL;
        synic = vcpu_to_synic(vcpu);
@@ -221,7 +234,8 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic,
                synic->version = data;
                break;
        case HV_X64_MSR_SIEFP:
-               if (data & HV_SYNIC_SIEFP_ENABLE)
+               if ((data & HV_SYNIC_SIEFP_ENABLE) && !host &&
+                   !synic->dont_zero_synic_pages)
                        if (kvm_clear_guest(vcpu->kvm,
                                            data & PAGE_MASK, PAGE_SIZE)) {
                                ret = 1;
@@ -232,7 +246,8 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic,
                        synic_exit(synic, msr);
                break;
        case HV_X64_MSR_SIMP:
-               if (data & HV_SYNIC_SIMP_ENABLE)
+               if ((data & HV_SYNIC_SIMP_ENABLE) && !host &&
+                   !synic->dont_zero_synic_pages)
                        if (kvm_clear_guest(vcpu->kvm,
                                            data & PAGE_MASK, PAGE_SIZE)) {
                                ret = 1;
@@ -318,11 +333,11 @@ static int synic_set_irq(struct kvm_vcpu_hv_synic *synic, u32 sint)
        return ret;
 }
 
-int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint)
+int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vpidx, u32 sint)
 {
        struct kvm_vcpu_hv_synic *synic;
 
-       synic = synic_get(kvm, vcpu_id);
+       synic = synic_get(kvm, vpidx);
        if (!synic)
                return -EINVAL;
 
@@ -341,11 +356,11 @@ void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector)
                        kvm_hv_notify_acked_sint(vcpu, i);
 }
 
-static int kvm_hv_set_sint_gsi(struct kvm *kvm, u32 vcpu_id, u32 sint, int gsi)
+static int kvm_hv_set_sint_gsi(struct kvm *kvm, u32 vpidx, u32 sint, int gsi)
 {
        struct kvm_vcpu_hv_synic *synic;
 
-       synic = synic_get(kvm, vcpu_id);
+       synic = synic_get(kvm, vpidx);
        if (!synic)
                return -EINVAL;
 
@@ -634,9 +649,10 @@ void kvm_hv_process_stimers(struct kvm_vcpu *vcpu)
                                }
 
                                if ((stimer->config & HV_STIMER_ENABLE) &&
-                                   stimer->count)
-                                       stimer_start(stimer);
-                               else
+                                   stimer->count) {
+                                       if (!stimer->msg_pending)
+                                               stimer_start(stimer);
+                               } else
                                        stimer_cleanup(stimer);
                        }
                }
@@ -687,14 +703,24 @@ void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)
                stimer_init(&hv_vcpu->stimer[i], i);
 }
 
-int kvm_hv_activate_synic(struct kvm_vcpu *vcpu)
+void kvm_hv_vcpu_postcreate(struct kvm_vcpu *vcpu)
+{
+       struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+
+       hv_vcpu->vp_index = kvm_vcpu_get_idx(vcpu);
+}
+
+int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages)
 {
+       struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu);
+
        /*
         * Hyper-V SynIC auto EOI SINT's are
         * not compatible with APICV, so deactivate APICV
         */
        kvm_vcpu_deactivate_apicv(vcpu);
-       vcpu_to_synic(vcpu)->active = true;
+       synic->active = true;
+       synic->dont_zero_synic_pages = dont_zero_synic_pages;
        return 0;
 }
 
@@ -978,6 +1004,11 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host)
        struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv;
 
        switch (msr) {
+       case HV_X64_MSR_VP_INDEX:
+               if (!host)
+                       return 1;
+               hv->vp_index = (u32)data;
+               break;
        case HV_X64_MSR_APIC_ASSIST_PAGE: {
                u64 gfn;
                unsigned long addr;
@@ -1089,18 +1120,9 @@ static int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
        struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv;
 
        switch (msr) {
-       case HV_X64_MSR_VP_INDEX: {
-               int r;
-               struct kvm_vcpu *v;
-
-               kvm_for_each_vcpu(r, v, vcpu->kvm) {
-                       if (v == vcpu) {
-                               data = r;
-                               break;
-                       }
-               }
+       case HV_X64_MSR_VP_INDEX:
+               data = hv->vp_index;
                break;
-       }
        case HV_X64_MSR_EOI:
                return kvm_hv_vapic_msr_read(vcpu, APIC_EOI, pdata);
        case HV_X64_MSR_ICR:
index cd11195..e637631 100644 (file)
@@ -56,9 +56,10 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu);
 void kvm_hv_irq_routing_update(struct kvm *kvm);
 int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint);
 void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector);
-int kvm_hv_activate_synic(struct kvm_vcpu *vcpu);
+int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages);
 
 void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu);
+void kvm_hv_vcpu_postcreate(struct kvm_vcpu *vcpu);
 void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu);
 
 static inline struct kvm_vcpu_hv_stimer *vcpu_to_stimer(struct kvm_vcpu *vcpu,
index a78b445..af19289 100644 (file)
@@ -724,8 +724,10 @@ void kvm_free_pit(struct kvm *kvm)
        struct kvm_pit *pit = kvm->arch.vpit;
 
        if (pit) {
+               mutex_lock(&kvm->slots_lock);
                kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &pit->dev);
                kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &pit->speaker_dev);
+               mutex_unlock(&kvm->slots_lock);
                kvm_pit_set_reinject(pit, false);
                hrtimer_cancel(&pit->pit_state.timer);
                kthread_destroy_worker(pit->worker);
index 2819d4c..589dcc1 100644 (file)
@@ -1495,11 +1495,10 @@ EXPORT_SYMBOL_GPL(kvm_lapic_hv_timer_in_use);
 
 static void cancel_hv_timer(struct kvm_lapic *apic)
 {
+       WARN_ON(preemptible());
        WARN_ON(!apic->lapic_timer.hv_timer_in_use);
-       preempt_disable();
        kvm_x86_ops->cancel_hv_timer(apic->vcpu);
        apic->lapic_timer.hv_timer_in_use = false;
-       preempt_enable();
 }
 
 static bool start_hv_timer(struct kvm_lapic *apic)
@@ -1507,6 +1506,7 @@ static bool start_hv_timer(struct kvm_lapic *apic)
        struct kvm_timer *ktimer = &apic->lapic_timer;
        int r;
 
+       WARN_ON(preemptible());
        if (!kvm_x86_ops->set_hv_timer)
                return false;
 
@@ -1538,6 +1538,8 @@ static bool start_hv_timer(struct kvm_lapic *apic)
 static void start_sw_timer(struct kvm_lapic *apic)
 {
        struct kvm_timer *ktimer = &apic->lapic_timer;
+
+       WARN_ON(preemptible());
        if (apic->lapic_timer.hv_timer_in_use)
                cancel_hv_timer(apic);
        if (!apic_lvtt_period(apic) && atomic_read(&ktimer->pending))
@@ -1552,15 +1554,20 @@ static void start_sw_timer(struct kvm_lapic *apic)
 
 static void restart_apic_timer(struct kvm_lapic *apic)
 {
+       preempt_disable();
        if (!start_hv_timer(apic))
                start_sw_timer(apic);
+       preempt_enable();
 }
 
 void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
 
-       WARN_ON(!apic->lapic_timer.hv_timer_in_use);
+       preempt_disable();
+       /* If the preempt notifier has already run, it also called apic_timer_expired */
+       if (!apic->lapic_timer.hv_timer_in_use)
+               goto out;
        WARN_ON(swait_active(&vcpu->wq));
        cancel_hv_timer(apic);
        apic_timer_expired(apic);
@@ -1569,6 +1576,8 @@ void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu)
                advance_periodic_target_expiration(apic);
                restart_apic_timer(apic);
        }
+out:
+       preempt_enable();
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_expired_hv_timer);
 
@@ -1582,9 +1591,11 @@ void kvm_lapic_switch_to_sw_timer(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
 
+       preempt_disable();
        /* Possibly the TSC deadline timer is not enabled yet */
        if (apic->lapic_timer.hv_timer_in_use)
                start_sw_timer(apic);
+       preempt_enable();
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_switch_to_sw_timer);
 
index aafd399..9b1dd11 100644 (file)
@@ -46,6 +46,7 @@
 #include <asm/io.h>
 #include <asm/vmx.h>
 #include <asm/kvm_page_track.h>
+#include "trace.h"
 
 /*
  * When setting this variable to true it enables Two-Dimensional-Paging
@@ -3748,7 +3749,7 @@ bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu)
                     kvm_event_needs_reinjection(vcpu)))
                return false;
 
-       if (is_guest_mode(vcpu))
+       if (!vcpu->arch.apf.delivery_as_pf_vmexit && is_guest_mode(vcpu))
                return false;
 
        return kvm_x86_ops->interrupt_allowed(vcpu);
@@ -3780,6 +3781,38 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
        return false;
 }
 
+int kvm_handle_page_fault(struct kvm_vcpu *vcpu, u64 error_code,
+                               u64 fault_address, char *insn, int insn_len,
+                               bool need_unprotect)
+{
+       int r = 1;
+
+       switch (vcpu->arch.apf.host_apf_reason) {
+       default:
+               trace_kvm_page_fault(fault_address, error_code);
+
+               if (need_unprotect && kvm_event_needs_reinjection(vcpu))
+                       kvm_mmu_unprotect_page_virt(vcpu, fault_address);
+               r = kvm_mmu_page_fault(vcpu, fault_address, error_code, insn,
+                               insn_len);
+               break;
+       case KVM_PV_REASON_PAGE_NOT_PRESENT:
+               vcpu->arch.apf.host_apf_reason = 0;
+               local_irq_disable();
+               kvm_async_pf_task_wait(fault_address);
+               local_irq_enable();
+               break;
+       case KVM_PV_REASON_PAGE_READY:
+               vcpu->arch.apf.host_apf_reason = 0;
+               local_irq_disable();
+               kvm_async_pf_task_wake(fault_address);
+               local_irq_enable();
+               break;
+       }
+       return r;
+}
+EXPORT_SYMBOL_GPL(kvm_handle_page_fault);
+
 static bool
 check_hugepage_cache_consistency(struct kvm_vcpu *vcpu, gfn_t gfn, int level)
 {
index a276834..d7d248a 100644 (file)
@@ -77,6 +77,9 @@ void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu);
 void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly,
                             bool accessed_dirty);
 bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu);
+int kvm_handle_page_fault(struct kvm_vcpu *vcpu, u64 error_code,
+                               u64 fault_address, char *insn, int insn_len,
+                               bool need_unprotect);
 
 static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm)
 {
index 905ea60..4d8141e 100644 (file)
@@ -194,7 +194,6 @@ struct vcpu_svm {
 
        unsigned int3_injected;
        unsigned long int3_rip;
-       u32 apf_reason;
 
        /* cached guest cpuid flags for faster access */
        bool nrips_enabled      : 1;
@@ -277,6 +276,10 @@ static int avic;
 module_param(avic, int, S_IRUGO);
 #endif
 
+/* enable/disable Virtual VMLOAD VMSAVE */
+static int vls = true;
+module_param(vls, int, 0444);
+
 /* AVIC VM ID bit masks and lock */
 static DECLARE_BITMAP(avic_vm_id_bitmap, AVIC_VM_ID_NR);
 static DEFINE_SPINLOCK(avic_vm_id_lock);
@@ -633,11 +636,13 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
        svm_set_interrupt_shadow(vcpu, 0);
 }
 
-static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
-                               bool has_error_code, u32 error_code,
-                               bool reinject)
+static void svm_queue_exception(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
+       unsigned nr = vcpu->arch.exception.nr;
+       bool has_error_code = vcpu->arch.exception.has_error_code;
+       bool reinject = vcpu->arch.exception.reinject;
+       u32 error_code = vcpu->arch.exception.error_code;
 
        /*
         * If we are within a nested VM we'd better #VMEXIT and let the guest
@@ -947,7 +952,7 @@ static void svm_enable_lbrv(struct vcpu_svm *svm)
 {
        u32 *msrpm = svm->msrpm;
 
-       svm->vmcb->control.lbr_ctl = 1;
+       svm->vmcb->control.virt_ext |= LBR_CTL_ENABLE_MASK;
        set_msr_interception(msrpm, MSR_IA32_LASTBRANCHFROMIP, 1, 1);
        set_msr_interception(msrpm, MSR_IA32_LASTBRANCHTOIP, 1, 1);
        set_msr_interception(msrpm, MSR_IA32_LASTINTFROMIP, 1, 1);
@@ -958,7 +963,7 @@ static void svm_disable_lbrv(struct vcpu_svm *svm)
 {
        u32 *msrpm = svm->msrpm;
 
-       svm->vmcb->control.lbr_ctl = 0;
+       svm->vmcb->control.virt_ext &= ~LBR_CTL_ENABLE_MASK;
        set_msr_interception(msrpm, MSR_IA32_LASTBRANCHFROMIP, 0, 0);
        set_msr_interception(msrpm, MSR_IA32_LASTBRANCHTOIP, 0, 0);
        set_msr_interception(msrpm, MSR_IA32_LASTINTFROMIP, 0, 0);
@@ -1093,6 +1098,16 @@ static __init int svm_hardware_setup(void)
                }
        }
 
+       if (vls) {
+               if (!npt_enabled ||
+                   !boot_cpu_has(X86_FEATURE_VIRTUAL_VMLOAD_VMSAVE) ||
+                   !IS_ENABLED(CONFIG_X86_64)) {
+                       vls = false;
+               } else {
+                       pr_info("Virtual VMLOAD VMSAVE supported\n");
+               }
+       }
+
        return 0;
 
 err:
@@ -1280,6 +1295,16 @@ static void init_vmcb(struct vcpu_svm *svm)
        if (avic)
                avic_init_vmcb(svm);
 
+       /*
+        * If hardware supports Virtual VMLOAD VMSAVE then enable it
+        * in VMCB and clear intercepts to avoid #VMEXIT.
+        */
+       if (vls) {
+               clr_intercept(svm, INTERCEPT_VMLOAD);
+               clr_intercept(svm, INTERCEPT_VMSAVE);
+               svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
+       }
+
        mark_all_dirty(svm->vmcb);
 
        enable_gif(svm);
@@ -2096,34 +2121,11 @@ static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value)
 static int pf_interception(struct vcpu_svm *svm)
 {
        u64 fault_address = svm->vmcb->control.exit_info_2;
-       u64 error_code;
-       int r = 1;
+       u64 error_code = svm->vmcb->control.exit_info_1;
 
-       switch (svm->apf_reason) {
-       default:
-               error_code = svm->vmcb->control.exit_info_1;
-
-               trace_kvm_page_fault(fault_address, error_code);
-               if (!npt_enabled && kvm_event_needs_reinjection(&svm->vcpu))
-                       kvm_mmu_unprotect_page_virt(&svm->vcpu, fault_address);
-               r = kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code,
+       return kvm_handle_page_fault(&svm->vcpu, error_code, fault_address,
                        svm->vmcb->control.insn_bytes,
-                       svm->vmcb->control.insn_len);
-               break;
-       case KVM_PV_REASON_PAGE_NOT_PRESENT:
-               svm->apf_reason = 0;
-               local_irq_disable();
-               kvm_async_pf_task_wait(fault_address);
-               local_irq_enable();
-               break;
-       case KVM_PV_REASON_PAGE_READY:
-               svm->apf_reason = 0;
-               local_irq_disable();
-               kvm_async_pf_task_wake(fault_address);
-               local_irq_enable();
-               break;
-       }
-       return r;
+                       svm->vmcb->control.insn_len, !npt_enabled);
 }
 
 static int db_interception(struct vcpu_svm *svm)
@@ -2267,7 +2269,7 @@ static int io_interception(struct vcpu_svm *svm)
 {
        struct kvm_vcpu *vcpu = &svm->vcpu;
        u32 io_info = svm->vmcb->control.exit_info_1; /* address size bug? */
-       int size, in, string;
+       int size, in, string, ret;
        unsigned port;
 
        ++svm->vcpu.stat.io_exits;
@@ -2279,10 +2281,16 @@ static int io_interception(struct vcpu_svm *svm)
        port = io_info >> 16;
        size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
        svm->next_rip = svm->vmcb->control.exit_info_2;
-       skip_emulated_instruction(&svm->vcpu);
+       ret = kvm_skip_emulated_instruction(&svm->vcpu);
 
-       return in ? kvm_fast_pio_in(vcpu, size, port)
-                 : kvm_fast_pio_out(vcpu, size, port);
+       /*
+        * TODO: we might be squashing a KVM_GUESTDBG_SINGLESTEP-triggered
+        * KVM_EXIT_DEBUG here.
+        */
+       if (in)
+               return kvm_fast_pio_in(vcpu, size, port) && ret;
+       else
+               return kvm_fast_pio_out(vcpu, size, port) && ret;
 }
 
 static int nmi_interception(struct vcpu_svm *svm)
@@ -2415,15 +2423,19 @@ static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
        if (!is_guest_mode(&svm->vcpu))
                return 0;
 
+       vmexit = nested_svm_intercept(svm);
+       if (vmexit != NESTED_EXIT_DONE)
+               return 0;
+
        svm->vmcb->control.exit_code = SVM_EXIT_EXCP_BASE + nr;
        svm->vmcb->control.exit_code_hi = 0;
        svm->vmcb->control.exit_info_1 = error_code;
-       svm->vmcb->control.exit_info_2 = svm->vcpu.arch.cr2;
-
-       vmexit = nested_svm_intercept(svm);
-       if (vmexit == NESTED_EXIT_DONE)
-               svm->nested.exit_required = true;
+       if (svm->vcpu.arch.exception.nested_apf)
+               svm->vmcb->control.exit_info_2 = svm->vcpu.arch.apf.nested_apf_token;
+       else
+               svm->vmcb->control.exit_info_2 = svm->vcpu.arch.cr2;
 
+       svm->nested.exit_required = true;
        return vmexit;
 }
 
@@ -2598,7 +2610,7 @@ static int nested_svm_exit_special(struct vcpu_svm *svm)
                break;
        case SVM_EXIT_EXCP_BASE + PF_VECTOR:
                /* When we're shadowing, trap PFs, but not async PF */
-               if (!npt_enabled && svm->apf_reason == 0)
+               if (!npt_enabled && svm->vcpu.arch.apf.host_apf_reason == 0)
                        return NESTED_EXIT_HOST;
                break;
        default:
@@ -2645,7 +2657,7 @@ static int nested_svm_intercept(struct vcpu_svm *svm)
                }
                /* async page fault always cause vmexit */
                else if ((exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR) &&
-                        svm->apf_reason != 0)
+                        svm->vcpu.arch.exception.nested_apf != 0)
                        vmexit = NESTED_EXIT_DONE;
                break;
        }
@@ -2702,7 +2714,7 @@ static inline void copy_vmcb_control_area(struct vmcb *dst_vmcb, struct vmcb *fr
        dst->event_inj            = from->event_inj;
        dst->event_inj_err        = from->event_inj_err;
        dst->nested_cr3           = from->nested_cr3;
-       dst->lbr_ctl              = from->lbr_ctl;
+       dst->virt_ext              = from->virt_ext;
 }
 
 static int nested_svm_vmexit(struct vcpu_svm *svm)
@@ -3008,7 +3020,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
        /* We don't want to see VMMCALLs from a nested guest */
        clr_intercept(svm, INTERCEPT_VMMCALL);
 
-       svm->vmcb->control.lbr_ctl = nested_vmcb->control.lbr_ctl;
+       svm->vmcb->control.virt_ext = nested_vmcb->control.virt_ext;
        svm->vmcb->control.int_vector = nested_vmcb->control.int_vector;
        svm->vmcb->control.int_state = nested_vmcb->control.int_state;
        svm->vmcb->control.tsc_offset += nested_vmcb->control.tsc_offset;
@@ -3055,6 +3067,7 @@ static int vmload_interception(struct vcpu_svm *svm)
 {
        struct vmcb *nested_vmcb;
        struct page *page;
+       int ret;
 
        if (nested_svm_check_permissions(svm))
                return 1;
@@ -3064,18 +3077,19 @@ static int vmload_interception(struct vcpu_svm *svm)
                return 1;
 
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
-       skip_emulated_instruction(&svm->vcpu);
+       ret = kvm_skip_emulated_instruction(&svm->vcpu);
 
        nested_svm_vmloadsave(nested_vmcb, svm->vmcb);
        nested_svm_unmap(page);
 
-       return 1;
+       return ret;
 }
 
 static int vmsave_interception(struct vcpu_svm *svm)
 {
        struct vmcb *nested_vmcb;
        struct page *page;
+       int ret;
 
        if (nested_svm_check_permissions(svm))
                return 1;
@@ -3085,12 +3099,12 @@ static int vmsave_interception(struct vcpu_svm *svm)
                return 1;
 
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
-       skip_emulated_instruction(&svm->vcpu);
+       ret = kvm_skip_emulated_instruction(&svm->vcpu);
 
        nested_svm_vmloadsave(svm->vmcb, nested_vmcb);
        nested_svm_unmap(page);
 
-       return 1;
+       return ret;
 }
 
 static int vmrun_interception(struct vcpu_svm *svm)
@@ -3123,25 +3137,29 @@ failed:
 
 static int stgi_interception(struct vcpu_svm *svm)
 {
+       int ret;
+
        if (nested_svm_check_permissions(svm))
                return 1;
 
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
-       skip_emulated_instruction(&svm->vcpu);
+       ret = kvm_skip_emulated_instruction(&svm->vcpu);
        kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
 
        enable_gif(svm);
 
-       return 1;
+       return ret;
 }
 
 static int clgi_interception(struct vcpu_svm *svm)
 {
+       int ret;
+
        if (nested_svm_check_permissions(svm))
                return 1;
 
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
-       skip_emulated_instruction(&svm->vcpu);
+       ret = kvm_skip_emulated_instruction(&svm->vcpu);
 
        disable_gif(svm);
 
@@ -3152,7 +3170,7 @@ static int clgi_interception(struct vcpu_svm *svm)
                mark_dirty(svm->vmcb, VMCB_INTR);
        }
 
-       return 1;
+       return ret;
 }
 
 static int invlpga_interception(struct vcpu_svm *svm)
@@ -3166,8 +3184,7 @@ static int invlpga_interception(struct vcpu_svm *svm)
        kvm_mmu_invlpg(vcpu, kvm_register_read(&svm->vcpu, VCPU_REGS_RAX));
 
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
-       skip_emulated_instruction(&svm->vcpu);
-       return 1;
+       return kvm_skip_emulated_instruction(&svm->vcpu);
 }
 
 static int skinit_interception(struct vcpu_svm *svm)
@@ -3190,7 +3207,7 @@ static int xsetbv_interception(struct vcpu_svm *svm)
 
        if (kvm_set_xcr(&svm->vcpu, index, new_bv) == 0) {
                svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
-               skip_emulated_instruction(&svm->vcpu);
+               return kvm_skip_emulated_instruction(&svm->vcpu);
        }
 
        return 1;
@@ -3286,8 +3303,7 @@ static int invlpg_interception(struct vcpu_svm *svm)
                return emulate_instruction(&svm->vcpu, 0) == EMULATE_DONE;
 
        kvm_mmu_invlpg(&svm->vcpu, svm->vmcb->control.exit_info_1);
-       skip_emulated_instruction(&svm->vcpu);
-       return 1;
+       return kvm_skip_emulated_instruction(&svm->vcpu);
 }
 
 static int emulate_on_interception(struct vcpu_svm *svm)
@@ -3437,9 +3453,7 @@ static int dr_interception(struct vcpu_svm *svm)
                kvm_register_write(&svm->vcpu, reg, val);
        }
 
-       skip_emulated_instruction(&svm->vcpu);
-
-       return 1;
+       return kvm_skip_emulated_instruction(&svm->vcpu);
 }
 
 static int cr8_write_interception(struct vcpu_svm *svm)
@@ -3562,6 +3576,7 @@ static int rdmsr_interception(struct vcpu_svm *svm)
        if (svm_get_msr(&svm->vcpu, &msr_info)) {
                trace_kvm_msr_read_ex(ecx);
                kvm_inject_gp(&svm->vcpu, 0);
+               return 1;
        } else {
                trace_kvm_msr_read(ecx, msr_info.data);
 
@@ -3570,9 +3585,8 @@ static int rdmsr_interception(struct vcpu_svm *svm)
                kvm_register_write(&svm->vcpu, VCPU_REGS_RDX,
                                   msr_info.data >> 32);
                svm->next_rip = kvm_rip_read(&svm->vcpu) + 2;
-               skip_emulated_instruction(&svm->vcpu);
+               return kvm_skip_emulated_instruction(&svm->vcpu);
        }
-       return 1;
 }
 
 static int svm_set_vm_cr(struct kvm_vcpu *vcpu, u64 data)
@@ -3698,11 +3712,11 @@ static int wrmsr_interception(struct vcpu_svm *svm)
        if (kvm_set_msr(&svm->vcpu, &msr)) {
                trace_kvm_msr_write_ex(ecx, data);
                kvm_inject_gp(&svm->vcpu, 0);
+               return 1;
        } else {
                trace_kvm_msr_write(ecx, data);
-               skip_emulated_instruction(&svm->vcpu);
+               return kvm_skip_emulated_instruction(&svm->vcpu);
        }
-       return 1;
 }
 
 static int msr_interception(struct vcpu_svm *svm)
@@ -3731,8 +3745,7 @@ static int pause_interception(struct vcpu_svm *svm)
 
 static int nop_interception(struct vcpu_svm *svm)
 {
-       skip_emulated_instruction(&(svm->vcpu));
-       return 1;
+       return kvm_skip_emulated_instruction(&(svm->vcpu));
 }
 
 static int monitor_interception(struct vcpu_svm *svm)
@@ -4117,7 +4130,7 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
        pr_err("%-20s%016llx\n", "avic_vapic_bar:", control->avic_vapic_bar);
        pr_err("%-20s%08x\n", "event_inj:", control->event_inj);
        pr_err("%-20s%08x\n", "event_inj_err:", control->event_inj_err);
-       pr_err("%-20s%lld\n", "lbr_ctl:", control->lbr_ctl);
+       pr_err("%-20s%lld\n", "virt_ext:", control->virt_ext);
        pr_err("%-20s%016llx\n", "next_rip:", control->next_rip);
        pr_err("%-20s%016llx\n", "avic_backing_page:", control->avic_backing_page);
        pr_err("%-20s%016llx\n", "avic_logical_id:", control->avic_logical_id);
@@ -4965,7 +4978,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
 
        /* if exit due to PF check for async PF */
        if (svm->vmcb->control.exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR)
-               svm->apf_reason = kvm_read_and_reset_pf_reason();
+               svm->vcpu.arch.apf.host_apf_reason = kvm_read_and_reset_pf_reason();
 
        if (npt_enabled) {
                vcpu->arch.regs_avail &= ~(1 << VCPU_EXREG_PDPTR);
index f76efad..39a6222 100644 (file)
@@ -198,7 +198,8 @@ struct loaded_vmcs {
        struct vmcs *vmcs;
        struct vmcs *shadow_vmcs;
        int cpu;
-       int launched;
+       bool launched;
+       bool nmi_known_unmasked;
        struct list_head loaded_vmcss_on_cpu_link;
 };
 
@@ -562,7 +563,6 @@ struct vcpu_vmx {
        struct kvm_vcpu       vcpu;
        unsigned long         host_rsp;
        u8                    fail;
-       bool                  nmi_known_unmasked;
        u32                   exit_intr_info;
        u32                   idt_vectoring_info;
        ulong                 rflags;
@@ -2326,6 +2326,11 @@ static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
        __vmx_load_host_state(to_vmx(vcpu));
 }
 
+static bool emulation_required(struct kvm_vcpu *vcpu)
+{
+       return emulate_invalid_guest_state && !guest_state_valid(vcpu);
+}
+
 static void vmx_decache_cr0_guest_bits(struct kvm_vcpu *vcpu);
 
 /*
@@ -2363,6 +2368,8 @@ static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
 
 static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 {
+       unsigned long old_rflags = vmx_get_rflags(vcpu);
+
        __set_bit(VCPU_EXREG_RFLAGS, (ulong *)&vcpu->arch.regs_avail);
        to_vmx(vcpu)->rflags = rflags;
        if (to_vmx(vcpu)->rmode.vm86_active) {
@@ -2370,6 +2377,9 @@ static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
                rflags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
        }
        vmcs_writel(GUEST_RFLAGS, rflags);
+
+       if ((old_rflags ^ to_vmx(vcpu)->rflags) & X86_EFLAGS_VM)
+               to_vmx(vcpu)->emulation_required = emulation_required(vcpu);
 }
 
 static u32 vmx_get_pkru(struct kvm_vcpu *vcpu)
@@ -2422,28 +2432,41 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
  * KVM wants to inject page-faults which it got to the guest. This function
  * checks whether in a nested guest, we need to inject them to L1 or L2.
  */
-static int nested_vmx_check_exception(struct kvm_vcpu *vcpu, unsigned nr)
+static int nested_vmx_check_exception(struct kvm_vcpu *vcpu)
 {
        struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+       unsigned int nr = vcpu->arch.exception.nr;
 
-       if (!(vmcs12->exception_bitmap & (1u << nr)))
+       if (!((vmcs12->exception_bitmap & (1u << nr)) ||
+               (nr == PF_VECTOR && vcpu->arch.exception.nested_apf)))
                return 0;
 
+       if (vcpu->arch.exception.nested_apf) {
+               vmcs_write32(VM_EXIT_INTR_ERROR_CODE, vcpu->arch.exception.error_code);
+               nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI,
+                       PF_VECTOR | INTR_TYPE_HARD_EXCEPTION |
+                       INTR_INFO_DELIVER_CODE_MASK | INTR_INFO_VALID_MASK,
+                       vcpu->arch.apf.nested_apf_token);
+               return 1;
+       }
+
        nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI,
                          vmcs_read32(VM_EXIT_INTR_INFO),
                          vmcs_readl(EXIT_QUALIFICATION));
        return 1;
 }
 
-static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
-                               bool has_error_code, u32 error_code,
-                               bool reinject)
+static void vmx_queue_exception(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
+       unsigned nr = vcpu->arch.exception.nr;
+       bool has_error_code = vcpu->arch.exception.has_error_code;
+       bool reinject = vcpu->arch.exception.reinject;
+       u32 error_code = vcpu->arch.exception.error_code;
        u32 intr_info = nr | INTR_INFO_VALID_MASK;
 
        if (!reinject && is_guest_mode(vcpu) &&
-           nested_vmx_check_exception(vcpu, nr))
+           nested_vmx_check_exception(vcpu))
                return;
 
        if (has_error_code) {
@@ -3764,6 +3787,25 @@ static void free_kvm_area(void)
        }
 }
 
+enum vmcs_field_type {
+       VMCS_FIELD_TYPE_U16 = 0,
+       VMCS_FIELD_TYPE_U64 = 1,
+       VMCS_FIELD_TYPE_U32 = 2,
+       VMCS_FIELD_TYPE_NATURAL_WIDTH = 3
+};
+
+static inline int vmcs_field_type(unsigned long field)
+{
+       if (0x1 & field)        /* the *_HIGH fields are all 32 bit */
+               return VMCS_FIELD_TYPE_U32;
+       return (field >> 13) & 0x3 ;
+}
+
+static inline int vmcs_field_readonly(unsigned long field)
+{
+       return (((field >> 10) & 0x3) == 1);
+}
+
 static void init_vmcs_shadow_fields(void)
 {
        int i, j;
@@ -3789,14 +3831,22 @@ static void init_vmcs_shadow_fields(void)
 
        /* shadowed fields guest access without vmexit */
        for (i = 0; i < max_shadow_read_write_fields; i++) {
-               clear_bit(shadow_read_write_fields[i],
-                         vmx_vmwrite_bitmap);
-               clear_bit(shadow_read_write_fields[i],
-                         vmx_vmread_bitmap);
+               unsigned long field = shadow_read_write_fields[i];
+
+               clear_bit(field, vmx_vmwrite_bitmap);
+               clear_bit(field, vmx_vmread_bitmap);
+               if (vmcs_field_type(field) == VMCS_FIELD_TYPE_U64) {
+                       clear_bit(field + 1, vmx_vmwrite_bitmap);
+                       clear_bit(field + 1, vmx_vmread_bitmap);
+               }
+       }
+       for (i = 0; i < max_shadow_read_only_fields; i++) {
+               unsigned long field = shadow_read_only_fields[i];
+
+               clear_bit(field, vmx_vmread_bitmap);
+               if (vmcs_field_type(field) == VMCS_FIELD_TYPE_U64)
+                       clear_bit(field + 1, vmx_vmread_bitmap);
        }
-       for (i = 0; i < max_shadow_read_only_fields; i++)
-               clear_bit(shadow_read_only_fields[i],
-                         vmx_vmread_bitmap);
 }
 
 static __init int alloc_kvm_area(void)
@@ -3817,11 +3867,6 @@ static __init int alloc_kvm_area(void)
        return 0;
 }
 
-static bool emulation_required(struct kvm_vcpu *vcpu)
-{
-       return emulate_invalid_guest_state && !guest_state_valid(vcpu);
-}
-
 static void fix_pmode_seg(struct kvm_vcpu *vcpu, int seg,
                struct kvm_segment *save)
 {
@@ -4634,6 +4679,11 @@ static bool guest_state_valid(struct kvm_vcpu *vcpu)
        return true;
 }
 
+static bool page_address_valid(struct kvm_vcpu *vcpu, gpa_t gpa)
+{
+       return PAGE_ALIGNED(gpa) && !(gpa >> cpuid_maxphyaddr(vcpu));
+}
+
 static int init_rmode_tss(struct kvm *kvm)
 {
        gfn_t fn;
@@ -4937,9 +4987,12 @@ static void vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
        }
 }
 
-static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu)
+static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu,
+                                                    bool nested)
 {
 #ifdef CONFIG_SMP
+       int pi_vec = nested ? POSTED_INTR_NESTED_VECTOR : POSTED_INTR_VECTOR;
+
        if (vcpu->mode == IN_GUEST_MODE) {
                struct vcpu_vmx *vmx = to_vmx(vcpu);
 
@@ -4957,8 +5010,7 @@ static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu)
                 */
                WARN_ON_ONCE(pi_test_sn(&vmx->pi_desc));
 
-               apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
-                               POSTED_INTR_VECTOR);
+               apic->send_IPI_mask(get_cpu_mask(vcpu->cpu), pi_vec);
                return true;
        }
 #endif
@@ -4973,7 +5025,7 @@ static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
        if (is_guest_mode(vcpu) &&
            vector == vmx->nested.posted_intr_nv) {
                /* the PIR and ON have been set by L1. */
-               kvm_vcpu_trigger_posted_interrupt(vcpu);
+               kvm_vcpu_trigger_posted_interrupt(vcpu, true);
                /*
                 * If a posted intr is not recognized by hardware,
                 * we will accomplish it in the next vmentry.
@@ -5007,7 +5059,7 @@ static void vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
        if (pi_test_and_set_on(&vmx->pi_desc))
                return;
 
-       if (!kvm_vcpu_trigger_posted_interrupt(vcpu))
+       if (!kvm_vcpu_trigger_posted_interrupt(vcpu, false))
                kvm_vcpu_kick(vcpu);
 }
 
@@ -5465,10 +5517,8 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-       if (!is_guest_mode(vcpu)) {
-               ++vcpu->stat.nmi_injections;
-               vmx->nmi_known_unmasked = false;
-       }
+       ++vcpu->stat.nmi_injections;
+       vmx->loaded_vmcs->nmi_known_unmasked = false;
 
        if (vmx->rmode.vm86_active) {
                if (kvm_inject_realmode_interrupt(vcpu, NMI_VECTOR, 0) != EMULATE_DONE)
@@ -5482,16 +5532,21 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
 
 static bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu)
 {
-       if (to_vmx(vcpu)->nmi_known_unmasked)
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       bool masked;
+
+       if (vmx->loaded_vmcs->nmi_known_unmasked)
                return false;
-       return vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_NMI;
+       masked = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_NMI;
+       vmx->loaded_vmcs->nmi_known_unmasked = !masked;
+       return masked;
 }
 
 static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-       vmx->nmi_known_unmasked = !masked;
+       vmx->loaded_vmcs->nmi_known_unmasked = !masked;
        if (masked)
                vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
                              GUEST_INTR_STATE_NMI);
@@ -5664,14 +5719,11 @@ static int handle_exception(struct kvm_vcpu *vcpu)
        }
 
        if (is_page_fault(intr_info)) {
-               /* EPT won't cause page fault directly */
-               BUG_ON(enable_ept);
                cr2 = vmcs_readl(EXIT_QUALIFICATION);
-               trace_kvm_page_fault(cr2, error_code);
-
-               if (kvm_event_needs_reinjection(vcpu))
-                       kvm_mmu_unprotect_page_virt(vcpu, cr2);
-               return kvm_mmu_page_fault(vcpu, cr2, error_code, NULL, 0);
+               /* EPT won't cause page fault directly */
+               WARN_ON_ONCE(!vcpu->arch.apf.host_apf_reason && enable_ept);
+               return kvm_handle_page_fault(vcpu, error_code, cr2, NULL, 0,
+                               true);
        }
 
        ex_no = intr_info & INTR_INFO_VECTOR_MASK;
@@ -7214,25 +7266,6 @@ static int handle_vmresume(struct kvm_vcpu *vcpu)
        return nested_vmx_run(vcpu, false);
 }
 
-enum vmcs_field_type {
-       VMCS_FIELD_TYPE_U16 = 0,
-       VMCS_FIELD_TYPE_U64 = 1,
-       VMCS_FIELD_TYPE_U32 = 2,
-       VMCS_FIELD_TYPE_NATURAL_WIDTH = 3
-};
-
-static inline int vmcs_field_type(unsigned long field)
-{
-       if (0x1 & field)        /* the *_HIGH fields are all 32 bit */
-               return VMCS_FIELD_TYPE_U32;
-       return (field >> 13) & 0x3 ;
-}
-
-static inline int vmcs_field_readonly(unsigned long field)
-{
-       return (((field >> 10) & 0x3) == 1);
-}
-
 /*
  * Read a vmcs12 field. Since these can have varying lengths and we return
  * one type, we chose the biggest type (u64) and zero-extend the return value
@@ -8014,7 +8047,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
                if (is_nmi(intr_info))
                        return false;
                else if (is_page_fault(intr_info))
-                       return enable_ept;
+                       return !vmx->vcpu.arch.apf.host_apf_reason && enable_ept;
                else if (is_no_device(intr_info) &&
                         !(vmcs12->guest_cr0 & X86_CR0_TS))
                        return false;
@@ -8418,9 +8451,15 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
                        exit_reason != EXIT_REASON_TASK_SWITCH)) {
                vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_DELIVERY_EV;
-               vcpu->run->internal.ndata = 2;
+               vcpu->run->internal.ndata = 3;
                vcpu->run->internal.data[0] = vectoring_info;
                vcpu->run->internal.data[1] = exit_reason;
+               vcpu->run->internal.data[2] = vcpu->arch.exit_qualification;
+               if (exit_reason == EXIT_REASON_EPT_MISCONFIG) {
+                       vcpu->run->internal.ndata++;
+                       vcpu->run->internal.data[3] =
+                               vmcs_read64(GUEST_PHYSICAL_ADDRESS);
+               }
                return 0;
        }
 
@@ -8611,17 +8650,24 @@ static void vmx_apicv_post_state_restore(struct kvm_vcpu *vcpu)
 
 static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
 {
-       u32 exit_intr_info;
+       u32 exit_intr_info = 0;
+       u16 basic_exit_reason = (u16)vmx->exit_reason;
 
-       if (!(vmx->exit_reason == EXIT_REASON_MCE_DURING_VMENTRY
-             || vmx->exit_reason == EXIT_REASON_EXCEPTION_NMI))
+       if (!(basic_exit_reason == EXIT_REASON_MCE_DURING_VMENTRY
+             || basic_exit_reason == EXIT_REASON_EXCEPTION_NMI))
                return;
 
-       vmx->exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
-       exit_intr_info = vmx->exit_intr_info;
+       if (!(vmx->exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY))
+               exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
+       vmx->exit_intr_info = exit_intr_info;
+
+       /* if exit due to PF check for async PF */
+       if (is_page_fault(exit_intr_info))
+               vmx->vcpu.arch.apf.host_apf_reason = kvm_read_and_reset_pf_reason();
 
        /* Handle machine checks before interrupts are enabled */
-       if (is_machine_check(exit_intr_info))
+       if (basic_exit_reason == EXIT_REASON_MCE_DURING_VMENTRY ||
+           is_machine_check(exit_intr_info))
                kvm_machine_check();
 
        /* We need to handle NMIs before interrupts are enabled */
@@ -8700,7 +8746,7 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
 
        idtv_info_valid = vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK;
 
-       if (vmx->nmi_known_unmasked)
+       if (vmx->loaded_vmcs->nmi_known_unmasked)
                return;
        /*
         * Can't use vmx->exit_intr_info since we're not sure what
@@ -8724,7 +8770,7 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
                vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
                              GUEST_INTR_STATE_NMI);
        else
-               vmx->nmi_known_unmasked =
+               vmx->loaded_vmcs->nmi_known_unmasked =
                        !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO)
                          & GUEST_INTR_STATE_NMI);
 }
@@ -9589,23 +9635,26 @@ static void vmx_start_preemption_timer(struct kvm_vcpu *vcpu)
                      ns_to_ktime(preemption_timeout), HRTIMER_MODE_REL);
 }
 
+static int nested_vmx_check_io_bitmap_controls(struct kvm_vcpu *vcpu,
+                                              struct vmcs12 *vmcs12)
+{
+       if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
+               return 0;
+
+       if (!page_address_valid(vcpu, vmcs12->io_bitmap_a) ||
+           !page_address_valid(vcpu, vmcs12->io_bitmap_b))
+               return -EINVAL;
+
+       return 0;
+}
+
 static int nested_vmx_check_msr_bitmap_controls(struct kvm_vcpu *vcpu,
                                                struct vmcs12 *vmcs12)
 {
-       int maxphyaddr;
-       u64 addr;
-
        if (!nested_cpu_has(vmcs12, CPU_BASED_USE_MSR_BITMAPS))
                return 0;
 
-       if (vmcs12_read_any(vcpu, MSR_BITMAP, &addr)) {
-               WARN_ON(1);
-               return -EINVAL;
-       }
-       maxphyaddr = cpuid_maxphyaddr(vcpu);
-
-       if (!PAGE_ALIGNED(vmcs12->msr_bitmap) ||
-          ((addr + PAGE_SIZE) >> maxphyaddr))
+       if (!page_address_valid(vcpu, vmcs12->msr_bitmap))
                return -EINVAL;
 
        return 0;
@@ -9993,6 +10042,8 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
                             vmcs12->vm_entry_instruction_len);
                vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
                             vmcs12->guest_interruptibility_info);
+               vmx->loaded_vmcs->nmi_known_unmasked =
+                       !(vmcs12->guest_interruptibility_info & GUEST_INTR_STATE_NMI);
        } else {
                vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0);
        }
@@ -10017,13 +10068,9 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
 
        /* Posted interrupts setting is only taken from vmcs12.  */
        if (nested_cpu_has_posted_intr(vmcs12)) {
-               /*
-                * Note that we use L0's vector here and in
-                * vmx_deliver_nested_posted_interrupt.
-                */
                vmx->nested.posted_intr_nv = vmcs12->posted_intr_nv;
                vmx->nested.pi_pending = false;
-               vmcs_write16(POSTED_INTR_NV, POSTED_INTR_VECTOR);
+               vmcs_write16(POSTED_INTR_NV, POSTED_INTR_NESTED_VECTOR);
        } else {
                exec_control &= ~PIN_BASED_POSTED_INTR;
        }
@@ -10293,6 +10340,9 @@ static int check_vmentry_prereqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
            vmcs12->guest_activity_state != GUEST_ACTIVITY_HLT)
                return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
 
+       if (nested_vmx_check_io_bitmap_controls(vcpu, vmcs12))
+               return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
+
        if (nested_vmx_check_msr_bitmap_controls(vcpu, vmcs12))
                return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
 
@@ -10429,8 +10479,6 @@ static int enter_vmx_non_root_mode(struct kvm_vcpu *vcpu, bool from_vmentry)
                return 1;
        }
 
-       vmcs12->launch_state = 1;
-
        /*
         * Note no nested_vmx_succeed or nested_vmx_fail here. At this point
         * we are no longer running L1, and VMLAUNCH/VMRESUME has not yet
@@ -10448,6 +10496,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
 {
        struct vmcs12 *vmcs12;
        struct vcpu_vmx *vmx = to_vmx(vcpu);
+       u32 interrupt_shadow = vmx_get_interrupt_shadow(vcpu);
        u32 exit_qual;
        int ret;
 
@@ -10472,6 +10521,12 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
         * for misconfigurations which will anyway be caught by the processor
         * when using the merged vmcs02.
         */
+       if (interrupt_shadow & KVM_X86_SHADOW_INT_MOV_SS) {
+               nested_vmx_failValid(vcpu,
+                                    VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS);
+               goto out;
+       }
+
        if (vmcs12->launch_state == launch) {
                nested_vmx_failValid(vcpu,
                        launch ? VMXERR_VMLAUNCH_NONCLEAR_VMCS
@@ -10804,6 +10859,8 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
        vmcs12->vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
 
        if (!(vmcs12->vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) {
+               vmcs12->launch_state = 1;
+
                /* vm_entry_intr_info_field is cleared on exit. Emulate this
                 * instead of reading the real value. */
                vmcs12->vm_entry_intr_info_field &= ~INTR_INFO_VALID_MASK;
@@ -10884,7 +10941,9 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
                 */
                vmx_flush_tlb(vcpu);
        }
-
+       /* Restore posted intr vector. */
+       if (nested_cpu_has_posted_intr(vmcs12))
+               vmcs_write16(POSTED_INTR_NV, POSTED_INTR_VECTOR);
 
        vmcs_write32(GUEST_SYSENTER_CS, vmcs12->host_ia32_sysenter_cs);
        vmcs_writel(GUEST_SYSENTER_ESP, vmcs12->host_ia32_sysenter_esp);
index 6c7266f..6c97c82 100644 (file)
@@ -134,8 +134,6 @@ module_param(lapic_timer_advance_ns, uint, S_IRUGO | S_IWUSR);
 static bool __read_mostly vector_hashing = true;
 module_param(vector_hashing, bool, S_IRUGO);
 
-static bool __read_mostly backwards_tsc_observed = false;
-
 #define KVM_NR_SHARED_MSRS 16
 
 struct kvm_shared_msrs_global {
@@ -452,7 +450,12 @@ EXPORT_SYMBOL_GPL(kvm_complete_insn_gp);
 void kvm_inject_page_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault)
 {
        ++vcpu->stat.pf_guest;
-       vcpu->arch.cr2 = fault->address;
+       vcpu->arch.exception.nested_apf =
+               is_guest_mode(vcpu) && fault->async_page_fault;
+       if (vcpu->arch.exception.nested_apf)
+               vcpu->arch.apf.nested_apf_token = fault->address;
+       else
+               vcpu->arch.cr2 = fault->address;
        kvm_queue_exception_e(vcpu, PF_VECTOR, fault->error_code);
 }
 EXPORT_SYMBOL_GPL(kvm_inject_page_fault);
@@ -594,8 +597,8 @@ bool pdptrs_changed(struct kvm_vcpu *vcpu)
                      (unsigned long *)&vcpu->arch.regs_avail))
                return true;
 
-       gfn = (kvm_read_cr3(vcpu) & ~31u) >> PAGE_SHIFT;
-       offset = (kvm_read_cr3(vcpu) & ~31u) & (PAGE_SIZE - 1);
+       gfn = (kvm_read_cr3(vcpu) & 0xffffffe0ul) >> PAGE_SHIFT;
+       offset = (kvm_read_cr3(vcpu) & 0xffffffe0ul) & (PAGE_SIZE - 1);
        r = kvm_read_nested_guest_page(vcpu, gfn, pdpte, offset, sizeof(pdpte),
                                       PFERR_USER_MASK | PFERR_WRITE_MASK);
        if (r < 0)
@@ -1719,7 +1722,7 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)
                                        &ka->master_cycle_now);
 
        ka->use_master_clock = host_tsc_clocksource && vcpus_matched
-                               && !backwards_tsc_observed
+                               && !ka->backwards_tsc_observed
                                && !ka->boot_vcpu_runs_old_kvmclock;
 
        if (ka->use_master_clock)
@@ -2060,8 +2063,8 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
 {
        gpa_t gpa = data & ~0x3f;
 
-       /* Bits 2:5 are reserved, Should be zero */
-       if (data & 0x3c)
+       /* Bits 3:5 are reserved, Should be zero */
+       if (data & 0x38)
                return 1;
 
        vcpu->arch.apf.msr_val = data;
@@ -2077,6 +2080,7 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
                return 1;
 
        vcpu->arch.apf.send_user_only = !(data & KVM_ASYNC_PF_SEND_ALWAYS);
+       vcpu->arch.apf.delivery_as_pf_vmexit = data & KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT;
        kvm_async_pf_wakeup_all(vcpu);
        return 0;
 }
@@ -2661,6 +2665,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_HYPERV_VAPIC:
        case KVM_CAP_HYPERV_SPIN:
        case KVM_CAP_HYPERV_SYNIC:
+       case KVM_CAP_HYPERV_SYNIC2:
+       case KVM_CAP_HYPERV_VP_INDEX:
        case KVM_CAP_PCI_SEGMENT:
        case KVM_CAP_DEBUGREGS:
        case KVM_CAP_X86_ROBUST_SINGLESTEP:
@@ -3384,10 +3390,14 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
                return -EINVAL;
 
        switch (cap->cap) {
+       case KVM_CAP_HYPERV_SYNIC2:
+               if (cap->args[0])
+                       return -EINVAL;
        case KVM_CAP_HYPERV_SYNIC:
                if (!irqchip_in_kernel(vcpu->kvm))
                        return -EINVAL;
-               return kvm_hv_activate_synic(vcpu);
+               return kvm_hv_activate_synic(vcpu, cap->cap ==
+                                            KVM_CAP_HYPERV_SYNIC2);
        default:
                return -EINVAL;
        }
@@ -4188,9 +4198,15 @@ long kvm_arch_vm_ioctl(struct file *filp,
                        goto out;
 
                r = 0;
+               /*
+                * TODO: userspace has to take care of races with VCPU_RUN, so
+                * kvm_gen_update_masterclock() can be cut down to locked
+                * pvclock_update_vm_gtod_copy().
+                */
+               kvm_gen_update_masterclock(kvm);
                now_ns = get_kvmclock_ns(kvm);
                kvm->arch.kvmclock_offset += user_ns.clock - now_ns;
-               kvm_gen_update_masterclock(kvm);
+               kvm_make_all_cpus_request(kvm, KVM_REQ_CLOCK_UPDATE);
                break;
        }
        case KVM_GET_CLOCK: {
@@ -6347,10 +6363,7 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
                        kvm_update_dr7(vcpu);
                }
 
-               kvm_x86_ops->queue_exception(vcpu, vcpu->arch.exception.nr,
-                                         vcpu->arch.exception.has_error_code,
-                                         vcpu->arch.exception.error_code,
-                                         vcpu->arch.exception.reinject);
+               kvm_x86_ops->queue_exception(vcpu);
                return 0;
        }
 
@@ -7676,6 +7689,8 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
        struct msr_data msr;
        struct kvm *kvm = vcpu->kvm;
 
+       kvm_hv_vcpu_postcreate(vcpu);
+
        if (vcpu_load(vcpu))
                return;
        msr.data = 0x0;
@@ -7829,8 +7844,8 @@ int kvm_arch_hardware_enable(void)
         */
        if (backwards_tsc) {
                u64 delta_cyc = max_tsc - local_tsc;
-               backwards_tsc_observed = true;
                list_for_each_entry(kvm, &vm_list, vm_list) {
+                       kvm->arch.backwards_tsc_observed = true;
                        kvm_for_each_vcpu(i, vcpu, kvm) {
                                vcpu->arch.tsc_offset_adjustment += delta_cyc;
                                vcpu->arch.last_host_tsc = local_tsc;
@@ -8576,6 +8591,7 @@ void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
                fault.error_code = 0;
                fault.nested_page_fault = false;
                fault.address = work->arch.token;
+               fault.async_page_fault = true;
                kvm_inject_page_fault(vcpu, &fault);
        }
 }
@@ -8598,6 +8614,7 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
                fault.error_code = 0;
                fault.nested_page_fault = false;
                fault.address = work->arch.token;
+               fault.async_page_fault = true;
                kvm_inject_page_fault(vcpu, &fault);
        }
        vcpu->arch.apf.halted = false;
index cad1263..2eab7d0 100644 (file)
@@ -6,7 +6,7 @@
 
 __visible void *memcpy(void *to, const void *from, size_t n)
 {
-#ifdef CONFIG_X86_USE_3DNOW
+#if defined(CONFIG_X86_USE_3DNOW) && !defined(CONFIG_FORTIFY_SOURCE)
        return __memcpy3d(to, from, n);
 #else
        return __memcpy(to, from, n);
index 9b0c63b..1b2dac1 100644 (file)
@@ -5,8 +5,8 @@
 #DEBUG = -DDEBUGGING
 DEBUG  =
 PARANOID = -DPARANOID
-EXTRA_CFLAGS   := $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
-EXTRA_AFLAGS   := $(PARANOID)
+ccflags-y += $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
+asflags-y += $(PARANOID)
 
 # From 'C' language sources:
 C_OBJS =fpu_entry.o errors.o \
index afbc4d8..c9c320d 100644 (file)
@@ -157,7 +157,7 @@ extern u_char const data_sizes_16[32];
 
 #define signbyte(a) (((u_char *)(a))[9])
 #define getsign(a) (signbyte(a) & 0x80)
-#define setsign(a,b) { if (b) signbyte(a) |= 0x80; else signbyte(a) &= 0x7f; }
+#define setsign(a,b) { if ((b) != 0) signbyte(a) |= 0x80; else signbyte(a) &= 0x7f; }
 #define copysign(a,b) { if (getsign(a)) signbyte(b) |= 0x80; \
                         else signbyte(b) &= 0x7f; }
 #define changesign(a) { signbyte(a) ^= 0x80; }
index b77360f..19b33b5 100644 (file)
@@ -168,7 +168,7 @@ static int compare(FPU_REG const *b, int tagb)
 /* This function requires that st(0) is not empty */
 int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
 {
-       int f = 0, c;
+       int f, c;
 
        c = compare(loaded_data, loaded_tag);
 
@@ -189,12 +189,12 @@ int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
                case COMP_No_Comp:
                        f = SW_C3 | SW_C2 | SW_C0;
                        break;
-#ifdef PARANOID
                default:
+#ifdef PARANOID
                        EXCEPTION(EX_INTERNAL | 0x121);
+#endif /* PARANOID */
                        f = SW_C3 | SW_C2 | SW_C0;
                        break;
-#endif /* PARANOID */
                }
        setcc(f);
        if (c & COMP_Denormal) {
@@ -205,7 +205,7 @@ int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
 
 static int compare_st_st(int nr)
 {
-       int f = 0, c;
+       int f, c;
        FPU_REG *st_ptr;
 
        if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
@@ -235,12 +235,12 @@ static int compare_st_st(int nr)
                case COMP_No_Comp:
                        f = SW_C3 | SW_C2 | SW_C0;
                        break;
-#ifdef PARANOID
                default:
+#ifdef PARANOID
                        EXCEPTION(EX_INTERNAL | 0x122);
+#endif /* PARANOID */
                        f = SW_C3 | SW_C2 | SW_C0;
                        break;
-#endif /* PARANOID */
                }
        setcc(f);
        if (c & COMP_Denormal) {
@@ -283,12 +283,12 @@ static int compare_i_st_st(int nr)
        case COMP_No_Comp:
                f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF;
                break;
-#ifdef PARANOID
        default:
+#ifdef PARANOID
                EXCEPTION(EX_INTERNAL | 0x122);
+#endif /* PARANOID */
                f = 0;
                break;
-#endif /* PARANOID */
        }
        FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f;
        if (c & COMP_Denormal) {
index 797295e..229d04a 100644 (file)
@@ -92,13 +92,18 @@ unsigned long arch_mmap_rnd(void)
 static unsigned long mmap_base(unsigned long rnd, unsigned long task_size)
 {
        unsigned long gap = rlimit(RLIMIT_STACK);
+       unsigned long pad = stack_maxrandom_size(task_size) + stack_guard_gap;
        unsigned long gap_min, gap_max;
 
+       /* Values close to RLIM_INFINITY can overflow. */
+       if (gap + pad > gap)
+               gap += pad;
+
        /*
         * Top of mmap area (just below the process stack).
         * Leave an at least ~128 MB hole with possible stack randomization.
         */
-       gap_min = SIZE_128M + stack_maxrandom_size(task_size);
+       gap_min = SIZE_128M;
        gap_max = (task_size / 6) * 5;
 
        if (gap < gap_min)
index 6e075af..58337b2 100644 (file)
@@ -38,8 +38,10 @@ static void __init *max7315_platform_data(void *info)
         */
        strcpy(i2c_info->type, "max7315");
        if (nr++) {
-               sprintf(base_pin_name, "max7315_%d_base", nr);
-               sprintf(intr_pin_name, "max7315_%d_int", nr);
+               snprintf(base_pin_name, sizeof(base_pin_name),
+                        "max7315_%d_base", nr);
+               snprintf(intr_pin_name, sizeof(intr_pin_name),
+                        "max7315_%d_int", nr);
        } else {
                strcpy(base_pin_name, "max7315_base");
                strcpy(intr_pin_name, "max7315_int");
index d4a61dd..3e4bdb4 100644 (file)
@@ -40,7 +40,6 @@ static int timeout_base_ns[] = {
 static int timeout_us;
 static bool nobau = true;
 static int nobau_perm;
-static cycles_t congested_cycles;
 
 /* tunables: */
 static int max_concurr         = MAX_BAU_CONCURRENT;
@@ -829,10 +828,10 @@ static void record_send_stats(cycles_t time1, cycles_t time2,
                if ((completion_status == FLUSH_COMPLETE) && (try == 1)) {
                        bcp->period_requests++;
                        bcp->period_time += elapsed;
-                       if ((elapsed > congested_cycles) &&
+                       if ((elapsed > usec_2_cycles(bcp->cong_response_us)) &&
                            (bcp->period_requests > bcp->cong_reps) &&
                            ((bcp->period_time / bcp->period_requests) >
-                                                       congested_cycles)) {
+                                       usec_2_cycles(bcp->cong_response_us))) {
                                stat->s_congested++;
                                disable_for_period(bcp, stat);
                        }
@@ -2222,14 +2221,17 @@ static int __init uv_bau_init(void)
        else if (is_uv1_hub())
                ops = uv1_bau_ops;
 
+       nuvhubs = uv_num_possible_blades();
+       if (nuvhubs < 2) {
+               pr_crit("UV: BAU disabled - insufficient hub count\n");
+               goto err_bau_disable;
+       }
+
        for_each_possible_cpu(cur_cpu) {
                mask = &per_cpu(uv_flush_tlb_mask, cur_cpu);
                zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu));
        }
 
-       nuvhubs = uv_num_possible_blades();
-       congested_cycles = usec_2_cycles(congested_respns_us);
-
        uv_base_pnode = 0x7fffffff;
        for (uvhub = 0; uvhub < nuvhubs; uvhub++) {
                cpus = uv_blade_nr_possible_cpus(uvhub);
@@ -2242,9 +2244,8 @@ static int __init uv_bau_init(void)
                enable_timeouts();
 
        if (init_per_cpu(nuvhubs, uv_base_pnode)) {
-               set_bau_off();
-               nobau_perm = 1;
-               return 0;
+               pr_crit("UV: BAU disabled - per CPU init failed\n");
+               goto err_bau_disable;
        }
 
        vector = UV_BAU_MESSAGE;
@@ -2270,6 +2271,16 @@ static int __init uv_bau_init(void)
        }
 
        return 0;
+
+err_bau_disable:
+
+       for_each_possible_cpu(cur_cpu)
+               free_cpumask_var(per_cpu(uv_flush_tlb_mask, cur_cpu));
+
+       set_bau_off();
+       nobau_perm = 1;
+
+       return -EINVAL;
 }
 core_initcall(uv_bau_init);
 fs_initcall(uv_ptc_init);
index 00f54a9..28775f5 100644 (file)
@@ -26,6 +26,7 @@ int save_i387_registers(int pid, unsigned long *fp_regs)
 
 int save_fp_registers(int pid, unsigned long *fp_regs)
 {
+#ifdef PTRACE_GETREGSET
        struct iovec iov;
 
        if (have_xstate_support) {
@@ -34,9 +35,9 @@ int save_fp_registers(int pid, unsigned long *fp_regs)
                if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
                        return -errno;
                return 0;
-       } else {
+       } else
+#endif
                return save_i387_registers(pid, fp_regs);
-       }
 }
 
 int restore_i387_registers(int pid, unsigned long *fp_regs)
@@ -48,6 +49,7 @@ int restore_i387_registers(int pid, unsigned long *fp_regs)
 
 int restore_fp_registers(int pid, unsigned long *fp_regs)
 {
+#ifdef PTRACE_SETREGSET
        struct iovec iov;
 
        if (have_xstate_support) {
@@ -56,9 +58,9 @@ int restore_fp_registers(int pid, unsigned long *fp_regs)
                if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
                        return -errno;
                return 0;
-       } else {
+       } else
+#endif
                return restore_i387_registers(pid, fp_regs);
-       }
 }
 
 #ifdef __i386__
@@ -122,6 +124,7 @@ int put_fp_registers(int pid, unsigned long *regs)
 
 void arch_init_registers(int pid)
 {
+#ifdef PTRACE_GETREGSET
        struct _xstate fp_regs;
        struct iovec iov;
 
@@ -129,6 +132,7 @@ void arch_init_registers(int pid)
        iov.iov_len = sizeof(struct _xstate);
        if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0)
                have_xstate_support = 1;
+#endif
 }
 #endif
 
index b766792..3905319 100644 (file)
@@ -16,9 +16,9 @@
 
        .text
        .align 4
-       .globl setjmp
-       .type setjmp, @function
-setjmp:
+       .globl kernel_setjmp
+       .type kernel_setjmp, @function
+kernel_setjmp:
 #ifdef _REGPARM
        movl %eax,%edx
 #else
@@ -35,13 +35,13 @@ setjmp:
        movl %ecx,20(%edx)              # Return address
        ret
 
-       .size setjmp,.-setjmp
+       .size kernel_setjmp,.-kernel_setjmp
 
        .text
        .align 4
-       .globl longjmp
-       .type longjmp, @function
-longjmp:
+       .globl kernel_longjmp
+       .type kernel_longjmp, @function
+kernel_longjmp:
 #ifdef _REGPARM
        xchgl %eax,%edx
 #else
@@ -55,4 +55,4 @@ longjmp:
        movl 16(%edx),%edi
        jmp *20(%edx)
 
-       .size longjmp,.-longjmp
+       .size kernel_longjmp,.-kernel_longjmp
index 45f547b..c56942e 100644 (file)
@@ -18,9 +18,9 @@
 
        .text
        .align 4
-       .globl setjmp
-       .type setjmp, @function
-setjmp:
+       .globl kernel_setjmp
+       .type kernel_setjmp, @function
+kernel_setjmp:
        pop  %rsi                       # Return address, and adjust the stack
        xorl %eax,%eax                  # Return value
        movq %rbx,(%rdi)
@@ -34,13 +34,13 @@ setjmp:
        movq %rsi,56(%rdi)              # Return address
        ret
 
-       .size setjmp,.-setjmp
+       .size kernel_setjmp,.-kernel_setjmp
 
        .text
        .align 4
-       .globl longjmp
-       .type longjmp, @function
-longjmp:
+       .globl kernel_longjmp
+       .type kernel_longjmp, @function
+kernel_longjmp:
        movl %esi,%eax                  # Return value (int)
        movq (%rdi),%rbx
        movq 8(%rdi),%rsp
@@ -51,4 +51,4 @@ longjmp:
        movq 48(%rdi),%r15
        jmp *56(%rdi)
 
-       .size longjmp,.-longjmp
+       .size kernel_longjmp,.-kernel_longjmp
index cb3c223..ae4cd58 100644 (file)
@@ -5,7 +5,7 @@
 #include <sys/mman.h>
 #include <sys/user.h>
 #define __FRAME_OFFSETS
-#include <asm/ptrace.h>
+#include <linux/ptrace.h>
 #include <asm/types.h>
 
 #ifdef __i386__
@@ -50,7 +50,11 @@ void foo(void)
        DEFINE(HOST_GS, GS);
        DEFINE(HOST_ORIG_AX, ORIG_EAX);
 #else
+#if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET)
        DEFINE(HOST_FP_SIZE, sizeof(struct _xstate) / sizeof(unsigned long));
+#else
+       DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long));
+#endif
        DEFINE_LONGS(HOST_BX, RBX);
        DEFINE_LONGS(HOST_CX, RCX);
        DEFINE_LONGS(HOST_DI, RDI);
index 1d7a721..cab28cf 100644 (file)
@@ -2693,8 +2693,8 @@ EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region);
 phys_addr_t paddr_vmcoreinfo_note(void)
 {
        if (xen_pv_domain())
-               return virt_to_machine(&vmcoreinfo_note).maddr;
+               return virt_to_machine(vmcoreinfo_note).maddr;
        else
-               return __pa_symbol(&vmcoreinfo_note);
+               return __pa(vmcoreinfo_note);
 }
 #endif /* CONFIG_KEXEC_CORE */
index 1ea598e..5147140 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/irq_work.h>
 #include <linux/tick.h>
 #include <linux/nmi.h>
+#include <linux/cpuhotplug.h>
 
 #include <asm/paravirt.h>
 #include <asm/desc.h>
@@ -413,7 +414,7 @@ static void xen_pv_play_dead(void) /* used only with HOTPLUG_CPU */
         */
        tick_nohz_idle_enter();
 
-       cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
+       cpuhp_online_idle(CPUHP_AP_ONLINE_IDLE);
 }
 
 #else /* !CONFIG_HOTPLUG_CPU */
index a1895a8..1ecb05d 100644 (file)
@@ -309,7 +309,6 @@ static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
 void xen_teardown_timer(int cpu)
 {
        struct clock_event_device *evt;
-       BUG_ON(cpu == 0);
        evt = &per_cpu(xen_clock_events, cpu).evt;
 
        if (evt->irq >= 0) {
index 30f6290..2d716eb 100644 (file)
@@ -1,20 +1,17 @@
-generic-y += bitsperlong.h
 generic-y += bug.h
 generic-y += clkdev.h
 generic-y += div64.h
 generic-y += dma-contiguous.h
 generic-y += emergency-restart.h
-generic-y += errno.h
 generic-y += exec.h
 generic-y += extable.h
-generic-y += fcntl.h
+generic-y += fb.h
 generic-y += hardirq.h
-generic-y += ioctl.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
-generic-y += kvm_para.h
+generic-y += kprobes.h
 generic-y += linkage.h
 generic-y += local.h
 generic-y += local64.h
@@ -22,13 +19,9 @@ generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
 generic-y += percpu.h
 generic-y += preempt.h
-generic-y += resource.h
 generic-y += rwsem.h
 generic-y += sections.h
-generic-y += statfs.h
-generic-y += termios.h
 generic-y += topology.h
 generic-y += trace_clock.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += kprobes.h
diff --git a/arch/xtensa/include/asm/fb.h b/arch/xtensa/include/asm/fb.h
deleted file mode 100644 (file)
index c7df380..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _ASM_FB_H_
-#define _ASM_FB_H_
-#include <linux/fb.h>
-
-#define fb_pgprotect(...) do {} while (0)
-
-static inline int fb_is_primary_device(struct fb_info *info)
-{
-       return 0;
-}
-
-#endif /* _ASM_FB_H_ */
index 94c44ab..60e0d6a 100644 (file)
@@ -1,11 +1,22 @@
 #ifndef __ASM_XTENSA_FLAT_H
 #define __ASM_XTENSA_FLAT_H
 
+#include <asm/unaligned.h>
+
 #define flat_argvp_envp_on_stack()                     0
 #define flat_old_ram_flag(flags)                       (flags)
 #define flat_reloc_valid(reloc, size)                  ((reloc) <= (size))
-#define flat_get_addr_from_rp(rp, relval, flags, p)    get_unaligned(rp)
-#define flat_put_addr_at_rp(rp, val, relval    )       put_unaligned(val, rp)
+static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
+                                       u32 *addr, u32 *persistent)
+{
+       *addr = get_unaligned((__force u32 *)rp);
+       return 0;
+}
+static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel)
+{
+       put_unaligned(addr, (__force u32 *)rp);
+       return 0;
+}
 #define flat_get_relocate_addr(rel)                    (rel)
 #define flat_set_persistent(relval, p)                 0
 
index 4cb0d2f..a5bcdfb 100644 (file)
@@ -1,3 +1,12 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
+
+generic-y += bitsperlong.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += kvm_para.h
+generic-y += resource.h
 generic-y += siginfo.h
+generic-y += statfs.h
+generic-y += termios.h
index 98b004e..47d82c0 100644 (file)
 #define TIOCGPKT       _IOR('T', 0x38, int) /* Get packet mode state */
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
-#define TIOCGPTPEER    _IOR('T', 0x41, int) /* Safely open the slave */
+#define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
 
 #define TIOCSERCONFIG  _IO('T', 83)
 #define TIOCSERGWILD   _IOR('T', 84,  int)
index 60a6835..436b6ca 100644 (file)
@@ -4299,6 +4299,9 @@ static void bfq_completed_request(struct bfq_queue *bfqq, struct bfq_data *bfqd)
                        bfq_bfqq_expire(bfqd, bfqq, false,
                                        BFQQE_NO_MORE_REQUESTS);
        }
+
+       if (!bfqd->rq_in_driver)
+               bfq_schedule_dispatch(bfqd);
 }
 
 static void bfq_put_rq_priv_body(struct bfq_queue *bfqq)
index 8fd83b8..63e771a 100644 (file)
@@ -52,7 +52,7 @@ struct bfq_entity;
 struct bfq_service_tree {
        /* tree for active entities (i.e., those backlogged) */
        struct rb_root active;
-       /* tree for idle entities (i.e., not backlogged, with V <= F_i)*/
+       /* tree for idle entities (i.e., not backlogged, with V < F_i)*/
        struct rb_root idle;
 
        /* idle entity with minimum F_i */
index 5ec05cd..979f8f2 100644 (file)
@@ -1297,7 +1297,7 @@ static void bfq_update_vtime(struct bfq_service_tree *st, u64 new_value)
  *
  * This function searches the first schedulable entity, starting from the
  * root of the tree and going on the left every time on this side there is
- * a subtree with at least one eligible (start >= vtime) entity. The path on
+ * a subtree with at least one eligible (start <= vtime) entity. The path on
  * the right is followed only if a) the left subtree contains no eligible
  * entities and b) no eligible entity has been found yet.
  */
index 970b9c9..dbecbf4 100644 (file)
@@ -3421,6 +3421,10 @@ EXPORT_SYMBOL(blk_finish_plug);
  */
 void blk_pm_runtime_init(struct request_queue *q, struct device *dev)
 {
+       /* not support for RQF_PM and ->rpm_status in blk-mq yet */
+       if (q->mq_ops)
+               return;
+
        q->dev = dev;
        q->rpm_status = RPM_ACTIVE;
        pm_runtime_set_autosuspend_delay(q->dev, -1);
index 4891f04..9f8cffc 100644 (file)
@@ -17,9 +17,9 @@
 static int cpu_to_queue_index(unsigned int nr_queues, const int cpu)
 {
        /*
-        * Non online CPU will be mapped to queue index 0.
+        * Non present CPU will be mapped to queue index 0.
         */
-       if (!cpu_online(cpu))
+       if (!cpu_present(cpu))
                return 0;
        return cpu % nr_queues;
 }
index 4119bb3..847361c 100644 (file)
@@ -26,7 +26,7 @@ quiet_cmd_extract_certs  = EXTRACT_CERTS   $(patsubst "%",%,$(2))
 targets += x509_certificate_list
 $(obj)/x509_certificate_list: scripts/extract-cert $(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(SYSTEM_TRUSTED_KEYS_FILENAME) FORCE
        $(call if_changed,extract_certs,$(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_TRUSTED_KEYS))
-endif
+endif # CONFIG_SYSTEM_TRUSTED_KEYRING
 
 clean-files := x509_certificate_list .x509.list
 
@@ -87,7 +87,7 @@ $(obj)/x509.genkey:
        @echo >>$@ "keyUsage=digitalSignature"
        @echo >>$@ "subjectKeyIdentifier=hash"
        @echo >>$@ "authorityKeyIdentifier=keyid"
-endif
+endif # CONFIG_MODULE_SIG_KEY
 
 $(eval $(call config_filename,MODULE_SIG_KEY))
 
@@ -102,4 +102,4 @@ $(obj)/system_certificates.o: $(obj)/signing_key.x509
 targets += signing_key.x509
 $(obj)/signing_key.x509: scripts/extract-cert $(X509_DEP) FORCE
        $(call if_changed,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY))
-endif
+endif # CONFIG_MODULE_SIG
index 3556d8e..92a3d54 100644 (file)
@@ -287,7 +287,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern)
                goto unlock;
 
        sock_init_data(newsock, sk2);
-       sock_graft(sk2, newsock);
+       security_sock_graft(sk2, newsock);
        security_sk_clone(sk, sk2);
 
        err = type->accept(ask->private, sk2);
index 6f8f6b8..0cf5fef 100644 (file)
@@ -248,6 +248,9 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req,
        u8 *ihash = ohash + crypto_ahash_digestsize(auth);
        u32 tmp[2];
 
+       if (!authsize)
+               goto decrypt;
+
        /* Move high-order bits of sequence number back. */
        scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
        scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
@@ -256,6 +259,8 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req,
        if (crypto_memneq(ihash, ohash, authsize))
                return -EBADMSG;
 
+decrypt:
+
        sg_init_table(areq_ctx->dst, 2);
        dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen);
 
index 854d428..62068a5 100644 (file)
@@ -147,10 +147,14 @@ static unsigned int ec_storm_threshold  __read_mostly = 8;
 module_param(ec_storm_threshold, uint, 0644);
 MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm");
 
-static bool ec_freeze_events __read_mostly = true;
+static bool ec_freeze_events __read_mostly = false;
 module_param(ec_freeze_events, bool, 0644);
 MODULE_PARM_DESC(ec_freeze_events, "Disabling event handling during suspend/resume");
 
+static bool ec_no_wakeup __read_mostly;
+module_param(ec_no_wakeup, bool, 0644);
+MODULE_PARM_DESC(ec_no_wakeup, "Do not wake up from suspend-to-idle");
+
 struct acpi_ec_query_handler {
        struct list_head node;
        acpi_ec_query_func func;
@@ -535,6 +539,14 @@ static void acpi_ec_disable_event(struct acpi_ec *ec)
        spin_unlock_irqrestore(&ec->lock, flags);
        __acpi_ec_flush_event(ec);
 }
+
+void acpi_ec_flush_work(void)
+{
+       if (first_ec)
+               __acpi_ec_flush_event(first_ec);
+
+       flush_scheduled_work();
+}
 #endif /* CONFIG_PM_SLEEP */
 
 static bool acpi_ec_guard_event(struct acpi_ec *ec)
@@ -1870,31 +1882,39 @@ error:
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int acpi_ec_suspend_noirq(struct device *dev)
+static int acpi_ec_suspend(struct device *dev)
 {
        struct acpi_ec *ec =
                acpi_driver_data(to_acpi_device(dev));
 
-       acpi_ec_enter_noirq(ec);
+       if (acpi_sleep_no_ec_events() && ec_freeze_events)
+               acpi_ec_disable_event(ec);
        return 0;
 }
 
-static int acpi_ec_resume_noirq(struct device *dev)
+static int acpi_ec_suspend_noirq(struct device *dev)
 {
-       struct acpi_ec *ec =
-               acpi_driver_data(to_acpi_device(dev));
+       struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev));
+
+       /*
+        * The SCI handler doesn't run at this point, so the GPE can be
+        * masked at the low level without side effects.
+        */
+       if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
+           ec->reference_count >= 1)
+               acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
 
-       acpi_ec_leave_noirq(ec);
        return 0;
 }
 
-static int acpi_ec_suspend(struct device *dev)
+static int acpi_ec_resume_noirq(struct device *dev)
 {
-       struct acpi_ec *ec =
-               acpi_driver_data(to_acpi_device(dev));
+       struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev));
+
+       if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
+           ec->reference_count >= 1)
+               acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
 
-       if (acpi_sleep_no_ec_events() && ec_freeze_events)
-               acpi_ec_disable_event(ec);
        return 0;
 }
 
index 9531d32..58dd7ab 100644 (file)
@@ -193,6 +193,10 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
                              void *data);
 void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
 
+#ifdef CONFIG_PM_SLEEP
+void acpi_ec_flush_work(void);
+#endif
+
 
 /*--------------------------------------------------------------------------
                                   Suspend/Resume
index 830299a..7c352cb 100644 (file)
@@ -24,7 +24,7 @@ static struct fwnode_handle *acpi_gsi_domain_id;
  *
  * irq location updated with irq value [>0 on success, 0 on failure]
  *
- * Returns: linux IRQ number on success (>0)
+ * Returns: 0 on success
  *          -EINVAL on failure
  */
 int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
@@ -37,7 +37,7 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
         * *irq == 0 means no mapping, that should
         * be reported as a failure
         */
-       return (*irq > 0) ? *irq : -EINVAL;
+       return (*irq > 0) ? 0 : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
 
index b75b734..19182d0 100644 (file)
@@ -3160,6 +3160,8 @@ static struct acpi_driver acpi_nfit_driver = {
 
 static __init int nfit_init(void)
 {
+       int ret;
+
        BUILD_BUG_ON(sizeof(struct acpi_table_nfit) != 40);
        BUILD_BUG_ON(sizeof(struct acpi_nfit_system_address) != 56);
        BUILD_BUG_ON(sizeof(struct acpi_nfit_memory_map) != 48);
@@ -3187,8 +3189,14 @@ static __init int nfit_init(void)
                return -ENOMEM;
 
        nfit_mce_register();
+       ret = acpi_bus_register_driver(&acpi_nfit_driver);
+       if (ret) {
+               nfit_mce_unregister();
+               destroy_workqueue(nfit_wq);
+       }
+
+       return ret;
 
-       return acpi_bus_register_driver(&acpi_nfit_driver);
 }
 
 static __exit void nfit_exit(void)
index edb0c79..917f1cc 100644 (file)
@@ -443,7 +443,7 @@ int __init acpi_numa_init(void)
         * So go over all cpu entries in SRAT to get apicid to node mapping.
         */
 
-       /* SRAT: Static Resource Affinity Table */
+       /* SRAT: System Resource Affinity Table */
        if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
                struct acpi_subtable_proc srat_proc[3];
 
index be17664..fa8243c 100644 (file)
@@ -777,11 +777,11 @@ static void acpi_freeze_sync(void)
        /*
         * Process all pending events in case there are any wakeup ones.
         *
-        * The EC driver uses the system workqueue, so that one needs to be
-        * flushed too.
+        * The EC driver uses the system workqueue and an additional special
+        * one, so those need to be flushed too.
         */
+       acpi_ec_flush_work();
        acpi_os_wait_events_complete();
-       flush_scheduled_work();
        s2idle_wakeup = false;
 }
 
index bd86b80..b4fbb99 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
 #include "../internal.h"
  * Some ACPI devices are hidden (status == 0x0) in recent BIOS-es because
  * some recent Windows drivers bind to one device but poke at multiple
  * devices at the same time, so the others get hidden.
+ *
+ * Some BIOS-es (temporarily) hide specific APCI devices to work around Windows
+ * driver bugs. We use DMI matching to match known cases of this.
+ *
  * We work around this by always reporting ACPI_STA_DEFAULT for these
  * devices. Note this MUST only be done for devices where this is safe.
  *
 struct always_present_id {
        struct acpi_device_id hid[2];
        struct x86_cpu_id cpu_ids[2];
+       struct dmi_system_id dmi_ids[2]; /* Optional */
        const char *uid;
 };
 
 #define ICPU(model)    { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
 
-#define ENTRY(hid, uid, cpu_models) {                                  \
+#define ENTRY(hid, uid, cpu_models, dmi...) {                          \
        { { hid, }, {} },                                               \
        { cpu_models, {} },                                             \
+       { { .matches = dmi }, {} },                                     \
        uid,                                                            \
 }
 
@@ -47,13 +54,35 @@ static const struct always_present_id always_present_ids[] = {
         * Bay / Cherry Trail PWM directly poked by GPU driver in win10,
         * but Linux uses a separate PWM driver, harmless if not used.
         */
-       ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT1)),
-       ENTRY("80862288", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT)),
+       ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT1), {}),
+       ENTRY("80862288", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {}),
        /*
         * The INT0002 device is necessary to clear wakeup interrupt sources
         * on Cherry Trail devices, without it we get nobody cared IRQ msgs.
         */
-       ENTRY("INT0002", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT)),
+       ENTRY("INT0002", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {}),
+       /*
+        * On the Dell Venue 11 Pro 7130 the DSDT hides the touchscreen ACPI
+        * device until a certain time after _SB.PCI0.GFX0.LCD.LCD1._ON gets
+        * called has passed *and* _STA has been called at least 3 times since.
+        */
+       ENTRY("SYNA7500", "1", ICPU(INTEL_FAM6_HASWELL_ULT), {
+               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7130"),
+             }),
+       /*
+        * The GPD win BIOS dated 20170320 has disabled the accelerometer, the
+        * drivers sometimes cause crashes under Windows and this is how the
+        * manufacturer has solved this :| Note that the the DMI data is less
+        * generic then it seems, a board_vendor of "AMI Corporation" is quite
+        * rare and a board_name of "Default String" also is rare.
+        */
+       ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
+               DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+               DMI_MATCH(DMI_BOARD_NAME, "Default string"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
+               DMI_MATCH(DMI_BIOS_DATE, "03/20/2017")
+             }),
 };
 
 bool acpi_device_always_present(struct acpi_device *adev)
@@ -76,6 +105,10 @@ bool acpi_device_always_present(struct acpi_device *adev)
                if (!x86_match_cpu(always_present_ids[i].cpu_ids))
                        continue;
 
+               if (always_present_ids[i].dmi_ids[0].matches[0].slot &&
+                   !dmi_check_system(always_present_ids[i].dmi_ids))
+                       continue;
+
                if (old_status != ACPI_STA_DEFAULT) /* Log only once */
                        dev_info(&adev->dev,
                                 "Device [%s] is in always present list\n",
index aae4d8d..f7665c3 100644 (file)
@@ -2200,8 +2200,12 @@ static void binder_transaction(struct binder_proc *proc,
        list_add_tail(&t->work.entry, target_list);
        tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
        list_add_tail(&tcomplete->entry, &thread->todo);
-       if (target_wait)
-               wake_up_interruptible(target_wait);
+       if (target_wait) {
+               if (reply || !(t->flags & TF_ONE_WAY))
+                       wake_up_interruptible_sync(target_wait);
+               else
+                       wake_up_interruptible(target_wait);
+       }
        return;
 
 err_translate_failed:
@@ -3247,10 +3251,6 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        /*pr_info("binder_ioctl: %d:%d %x %lx\n",
                        proc->pid, current->pid, cmd, arg);*/
 
-       if (unlikely(current->mm != proc->vma_vm_mm)) {
-               pr_err("current mm mismatch proc mm\n");
-               return -EINVAL;
-       }
        trace_binder_ioctl(cmd, arg);
 
        ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
@@ -3464,9 +3464,8 @@ static int binder_open(struct inode *nodp, struct file *filp)
        proc = kzalloc(sizeof(*proc), GFP_KERNEL);
        if (proc == NULL)
                return -ENOMEM;
-       get_task_struct(current);
-       proc->tsk = current;
-       proc->vma_vm_mm = current->mm;
+       get_task_struct(current->group_leader);
+       proc->tsk = current->group_leader;
        INIT_LIST_HEAD(&proc->todo);
        init_waitqueue_head(&proc->wait);
        proc->default_priority = task_nice(current);
index 948fc86..363fc53 100644 (file)
@@ -215,7 +215,7 @@ config SATA_FSL
 
 config SATA_GEMINI
        tristate "Gemini SATA bridge support"
-       depends on PATA_FTIDE010
+       depends on ARCH_GEMINI || COMPILE_TEST
        default ARCH_GEMINI
        help
          This enabled support for the FTIDE010 to SATA bridge
@@ -613,7 +613,7 @@ config PATA_FTIDE010
        tristate "Faraday Technology FTIDE010 PATA support"
        depends on OF
        depends on ARM
-       default ARCH_GEMINI
+       depends on SATA_GEMINI
        help
          This option enables support for the Faraday FTIDE010
          PATA controller found in the Cortina Gemini SoCs.
index 8453f9a..fa7dd43 100644 (file)
@@ -2083,7 +2083,7 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
 retry:
        ata_tf_init(dev, &tf);
        if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) &&
-           !(dev->horkage & ATA_HORKAGE_NO_NCQ_LOG)) {
+           !(dev->horkage & ATA_HORKAGE_NO_DMA_LOG)) {
                tf.command = ATA_CMD_READ_LOG_DMA_EXT;
                tf.protocol = ATA_PROT_DMA;
                dma = true;
@@ -2102,8 +2102,8 @@ retry:
                                     buf, sectors * ATA_SECT_SIZE, 0);
 
        if (err_mask && dma) {
-               dev->horkage |= ATA_HORKAGE_NO_NCQ_LOG;
-               ata_dev_warn(dev, "READ LOG DMA EXT failed, trying unqueued\n");
+               dev->horkage |= ATA_HORKAGE_NO_DMA_LOG;
+               ata_dev_warn(dev, "READ LOG DMA EXT failed, trying PIO\n");
                goto retry;
        }
 
index b70bcf6..3dbd055 100644 (file)
@@ -1434,7 +1434,7 @@ void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
 
 /**
  *     ata_eh_done - EH action complete
-*      @ap: target ATA port
+ *     @link: ATA link for which EH actions are complete
  *     @dev: target ATA dev for per-dev action (can be NULL)
  *     @action: action just completed
  *
@@ -1576,7 +1576,7 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
 
 /**
  *     ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT
- *     @dev: device to perform REQUEST_SENSE_SENSE_DATA_EXT to
+ *     @qc: qc to perform REQUEST_SENSE_SENSE_DATA_EXT to
  *     @cmd: scsi command for which the sense code should be set
  *
  *     Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK
@@ -4175,7 +4175,6 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
        struct ata_link *link;
        struct ata_device *dev;
        unsigned long flags;
-       int rc = 0;
 
        /* are we resuming? */
        spin_lock_irqsave(ap->lock, flags);
@@ -4202,7 +4201,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
        ata_acpi_set_state(ap, ap->pm_mesg);
 
        if (ap->ops->port_resume)
-               rc = ap->ops->port_resume(ap);
+               ap->ops->port_resume(ap);
 
        /* tell ACPI that we're resuming */
        ata_acpi_on_resume(ap);
index d462c5a..44ba292 100644 (file)
@@ -3030,10 +3030,12 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
 static struct ata_device *ata_find_dev(struct ata_port *ap, int devno)
 {
        if (!sata_pmp_attached(ap)) {
-               if (likely(devno < ata_link_max_devices(&ap->link)))
+               if (likely(devno >= 0 &&
+                          devno < ata_link_max_devices(&ap->link)))
                        return &ap->link.device[devno];
        } else {
-               if (likely(devno < ap->nr_pmp_links))
+               if (likely(devno >= 0 &&
+                          devno < ap->nr_pmp_links))
                        return &ap->pmp_link[devno].device[0];
        }
 
index ee98447..537d118 100644 (file)
@@ -858,6 +858,14 @@ static const struct of_device_id sata_rcar_match[] = {
                .compatible = "renesas,sata-r8a7795",
                .data = (void *)RCAR_GEN2_SATA
        },
+       {
+               .compatible = "renesas,rcar-gen2-sata",
+               .data = (void *)RCAR_GEN2_SATA
+       },
+       {
+               .compatible = "renesas,rcar-gen3-sata",
+               .data = (void *)RCAR_GEN2_SATA
+       },
        { },
 };
 MODULE_DEVICE_TABLE(of, sata_rcar_match);
index d3aa748..1ef67db 100644 (file)
@@ -1613,7 +1613,7 @@ static int zatm_init_one(struct pci_dev *pci_dev,
 
        ret = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32));
        if (ret < 0)
-               goto out_disable;
+               goto out_release;
 
        zatm_dev->pci_dev = pci_dev;
        dev->dev_data = zatm_dev;
index 2ae24c2..1c152ae 100644 (file)
@@ -25,7 +25,7 @@ static inline struct dma_coherent_mem *dev_get_coherent_memory(struct device *de
 {
        if (dev && dev->dma_mem)
                return dev->dma_mem;
-       return dma_coherent_default_memory;
+       return NULL;
 }
 
 static inline dma_addr_t dma_get_device_base(struct device *dev,
@@ -165,34 +165,15 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
 }
 EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
 
-/**
- * dma_alloc_from_coherent() - try to allocate memory from the per-device coherent area
- *
- * @dev:       device from which we allocate memory
- * @size:      size of requested memory area
- * @dma_handle:        This will be filled with the correct dma handle
- * @ret:       This pointer will be filled with the virtual address
- *             to allocated area.
- *
- * This function should be only called from per-arch dma_alloc_coherent()
- * to support allocation from per-device coherent memory pools.
- *
- * Returns 0 if dma_alloc_coherent should continue with allocating from
- * generic memory areas, or !0 if dma_alloc_coherent should return @ret.
- */
-int dma_alloc_from_coherent(struct device *dev, ssize_t size,
-                                      dma_addr_t *dma_handle, void **ret)
+static void *__dma_alloc_from_coherent(struct dma_coherent_mem *mem,
+               ssize_t size, dma_addr_t *dma_handle)
 {
-       struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
        int order = get_order(size);
        unsigned long flags;
        int pageno;
        int dma_memory_map;
+       void *ret;
 
-       if (!mem)
-               return 0;
-
-       *ret = NULL;
        spin_lock_irqsave(&mem->spinlock, flags);
 
        if (unlikely(size > (mem->size << PAGE_SHIFT)))
@@ -203,21 +184,50 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
                goto err;
 
        /*
-        * Memory was found in the per-device area.
+        * Memory was found in the coherent area.
         */
-       *dma_handle = dma_get_device_base(dev, mem) + (pageno << PAGE_SHIFT);
-       *ret = mem->virt_base + (pageno << PAGE_SHIFT);
+       *dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
+       ret = mem->virt_base + (pageno << PAGE_SHIFT);
        dma_memory_map = (mem->flags & DMA_MEMORY_MAP);
        spin_unlock_irqrestore(&mem->spinlock, flags);
        if (dma_memory_map)
-               memset(*ret, 0, size);
+               memset(ret, 0, size);
        else
-               memset_io(*ret, 0, size);
+               memset_io(ret, 0, size);
 
-       return 1;
+       return ret;
 
 err:
        spin_unlock_irqrestore(&mem->spinlock, flags);
+       return NULL;
+}
+
+/**
+ * dma_alloc_from_dev_coherent() - allocate memory from device coherent pool
+ * @dev:       device from which we allocate memory
+ * @size:      size of requested memory area
+ * @dma_handle:        This will be filled with the correct dma handle
+ * @ret:       This pointer will be filled with the virtual address
+ *             to allocated area.
+ *
+ * This function should be only called from per-arch dma_alloc_coherent()
+ * to support allocation from per-device coherent memory pools.
+ *
+ * Returns 0 if dma_alloc_coherent should continue with allocating from
+ * generic memory areas, or !0 if dma_alloc_coherent should return @ret.
+ */
+int dma_alloc_from_dev_coherent(struct device *dev, ssize_t size,
+               dma_addr_t *dma_handle, void **ret)
+{
+       struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
+
+       if (!mem)
+               return 0;
+
+       *ret = __dma_alloc_from_coherent(mem, size, dma_handle);
+       if (*ret)
+               return 1;
+
        /*
         * In the case where the allocation can not be satisfied from the
         * per-device area, try to fall back to generic memory if the
@@ -225,25 +235,20 @@ err:
         */
        return mem->flags & DMA_MEMORY_EXCLUSIVE;
 }
-EXPORT_SYMBOL(dma_alloc_from_coherent);
+EXPORT_SYMBOL(dma_alloc_from_dev_coherent);
 
-/**
- * dma_release_from_coherent() - try to free the memory allocated from per-device coherent memory pool
- * @dev:       device from which the memory was allocated
- * @order:     the order of pages allocated
- * @vaddr:     virtual address of allocated pages
- *
- * This checks whether the memory was allocated from the per-device
- * coherent memory pool and if so, releases that memory.
- *
- * Returns 1 if we correctly released the memory, or 0 if
- * dma_release_coherent() should proceed with releasing memory from
- * generic pools.
- */
-int dma_release_from_coherent(struct device *dev, int order, void *vaddr)
+void *dma_alloc_from_global_coherent(ssize_t size, dma_addr_t *dma_handle)
 {
-       struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
+       if (!dma_coherent_default_memory)
+               return NULL;
+
+       return __dma_alloc_from_coherent(dma_coherent_default_memory, size,
+                       dma_handle);
+}
 
+static int __dma_release_from_coherent(struct dma_coherent_mem *mem,
+                                      int order, void *vaddr)
+{
        if (mem && vaddr >= mem->virt_base && vaddr <
                   (mem->virt_base + (mem->size << PAGE_SHIFT))) {
                int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
@@ -256,28 +261,39 @@ int dma_release_from_coherent(struct device *dev, int order, void *vaddr)
        }
        return 0;
 }
-EXPORT_SYMBOL(dma_release_from_coherent);
 
 /**
- * dma_mmap_from_coherent() - try to mmap the memory allocated from
- * per-device coherent memory pool to userspace
+ * dma_release_from_dev_coherent() - free memory to device coherent memory pool
  * @dev:       device from which the memory was allocated
- * @vma:       vm_area for the userspace memory
- * @vaddr:     cpu address returned by dma_alloc_from_coherent
- * @size:      size of the memory buffer allocated by dma_alloc_from_coherent
- * @ret:       result from remap_pfn_range()
+ * @order:     the order of pages allocated
+ * @vaddr:     virtual address of allocated pages
  *
  * This checks whether the memory was allocated from the per-device
- * coherent memory pool and if so, maps that memory to the provided vma.
+ * coherent memory pool and if so, releases that memory.
  *
- * Returns 1 if we correctly mapped the memory, or 0 if the caller should
- * proceed with mapping memory from generic pools.
+ * Returns 1 if we correctly released the memory, or 0 if the caller should
+ * proceed with releasing memory from generic pools.
  */
-int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
-                          void *vaddr, size_t size, int *ret)
+int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr)
 {
        struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
 
+       return __dma_release_from_coherent(mem, order, vaddr);
+}
+EXPORT_SYMBOL(dma_release_from_dev_coherent);
+
+int dma_release_from_global_coherent(int order, void *vaddr)
+{
+       if (!dma_coherent_default_memory)
+               return 0;
+
+       return __dma_release_from_coherent(dma_coherent_default_memory, order,
+                       vaddr);
+}
+
+static int __dma_mmap_from_coherent(struct dma_coherent_mem *mem,
+               struct vm_area_struct *vma, void *vaddr, size_t size, int *ret)
+{
        if (mem && vaddr >= mem->virt_base && vaddr + size <=
                   (mem->virt_base + (mem->size << PAGE_SHIFT))) {
                unsigned long off = vma->vm_pgoff;
@@ -296,7 +312,39 @@ int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
        }
        return 0;
 }
-EXPORT_SYMBOL(dma_mmap_from_coherent);
+
+/**
+ * dma_mmap_from_dev_coherent() - mmap memory from the device coherent pool
+ * @dev:       device from which the memory was allocated
+ * @vma:       vm_area for the userspace memory
+ * @vaddr:     cpu address returned by dma_alloc_from_dev_coherent
+ * @size:      size of the memory buffer allocated
+ * @ret:       result from remap_pfn_range()
+ *
+ * This checks whether the memory was allocated from the per-device
+ * coherent memory pool and if so, maps that memory to the provided vma.
+ *
+ * Returns 1 if we correctly mapped the memory, or 0 if the caller should
+ * proceed with mapping memory from generic pools.
+ */
+int dma_mmap_from_dev_coherent(struct device *dev, struct vm_area_struct *vma,
+                          void *vaddr, size_t size, int *ret)
+{
+       struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
+
+       return __dma_mmap_from_coherent(mem, vma, vaddr, size, ret);
+}
+EXPORT_SYMBOL(dma_mmap_from_dev_coherent);
+
+int dma_mmap_from_global_coherent(struct vm_area_struct *vma, void *vaddr,
+                                  size_t size, int *ret)
+{
+       if (!dma_coherent_default_memory)
+               return 0;
+
+       return __dma_mmap_from_coherent(dma_coherent_default_memory, vma,
+                                       vaddr, size, ret);
+}
 
 /*
  * Support for reserved memory regions defined in device tree
index 5096755..b555ff9 100644 (file)
@@ -235,7 +235,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
 
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-       if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+       if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;
 
        if (off < count && user_count <= (count - off)) {
index 3b8210e..60303aa 100644 (file)
@@ -1222,8 +1222,6 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
 
        spin_unlock_irq(&dev->power.lock);
 
-       dev_pm_domain_set(dev, &genpd->domain);
-
        return gpd_data;
 
  err_free:
@@ -1237,8 +1235,6 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
 static void genpd_free_dev_data(struct device *dev,
                                struct generic_pm_domain_data *gpd_data)
 {
-       dev_pm_domain_set(dev, NULL);
-
        spin_lock_irq(&dev->power.lock);
 
        dev->power.subsys_data->domain_data = NULL;
@@ -1275,6 +1271,8 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
        if (ret)
                goto out;
 
+       dev_pm_domain_set(dev, &genpd->domain);
+
        genpd->device_count++;
        genpd->max_off_time_changed = true;
 
@@ -1336,6 +1334,8 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
        if (genpd->detach_dev)
                genpd->detach_dev(genpd, dev);
 
+       dev_pm_domain_set(dev, NULL);
+
        list_del_init(&pdd->list_node);
 
        genpd_unlock(genpd);
index 185a525..156ab57 100644 (file)
@@ -272,6 +272,8 @@ static ssize_t pm_qos_latency_tolerance_store(struct device *dev,
                        value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
                else if (!strcmp(buf, "any") || !strcmp(buf, "any\n"))
                        value = PM_QOS_LATENCY_ANY;
+               else
+                       return -EINVAL;
        }
        ret = dev_pm_qos_update_user_latency_tolerance(dev, value);
        return ret < 0 ? ret : n;
index 692007e..edf02c1 100644 (file)
@@ -253,10 +253,10 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
 {
        bool ret;
 
-       ret = fwnode_call_int_op(fwnode, property_present, propname);
+       ret = fwnode_call_bool_op(fwnode, property_present, propname);
        if (ret == false && !IS_ERR_OR_NULL(fwnode) &&
            !IS_ERR_OR_NULL(fwnode->secondary))
-               ret = fwnode_call_int_op(fwnode->secondary, property_present,
+               ret = fwnode_call_bool_op(fwnode->secondary, property_present,
                                         propname);
        return ret;
 }
@@ -1027,7 +1027,7 @@ EXPORT_SYMBOL_GPL(fwnode_handle_put);
  */
 bool fwnode_device_is_available(struct fwnode_handle *fwnode)
 {
-       return fwnode_call_int_op(fwnode, device_is_available);
+       return fwnode_call_bool_op(fwnode, device_is_available);
 }
 EXPORT_SYMBOL_GPL(fwnode_device_is_available);
 
index 5f04e7b..e6c64b0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Register map access API - W1 (1-Wire) support
  *
- * Copyright (C) 2017 OAO Radioavionica
+ * Copyright (c) 2017 Radioavionica Corporation
  * Author: Alex A. Mihaylov <minimumlaw@rambler.ru>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -11,7 +11,7 @@
 
 #include <linux/regmap.h>
 #include <linux/module.h>
-#include "../../w1/w1.h"
+#include <linux/w1.h>
 
 #include "internal.h"
 
index dea7d85..5bdf923 100644 (file)
@@ -626,7 +626,6 @@ static void recv_work(struct work_struct *work)
        struct nbd_device *nbd = args->nbd;
        struct nbd_config *config = nbd->config;
        struct nbd_cmd *cmd;
-       int ret = 0;
 
        while (1) {
                cmd = nbd_read_stat(nbd, args->index);
@@ -636,7 +635,6 @@ static void recv_work(struct work_struct *work)
                        mutex_lock(&nsock->tx_lock);
                        nbd_mark_nsock_dead(nbd, nsock, 1);
                        mutex_unlock(&nsock->tx_lock);
-                       ret = PTR_ERR(cmd);
                        break;
                }
 
@@ -910,7 +908,8 @@ static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg)
                        continue;
                }
                sk_set_memalloc(sock->sk);
-               sock->sk->sk_sndtimeo = nbd->tag_set.timeout;
+               if (nbd->tag_set.timeout)
+                       sock->sk->sk_sndtimeo = nbd->tag_set.timeout;
                atomic_inc(&config->recv_threads);
                refcount_inc(&nbd->config_refs);
                old = nsock->sock;
@@ -924,6 +923,8 @@ static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg)
                mutex_unlock(&nsock->tx_lock);
                sockfd_put(old);
 
+               clear_bit(NBD_DISCONNECTED, &config->runtime_flags);
+
                /* We take the tx_mutex in an error path in the recv_work, so we
                 * need to queue_work outside of the tx_mutex.
                 */
@@ -980,11 +981,15 @@ static void send_disconnects(struct nbd_device *nbd)
        int i, ret;
 
        for (i = 0; i < config->num_connections; i++) {
+               struct nbd_sock *nsock = config->socks[i];
+
                iov_iter_kvec(&from, WRITE | ITER_KVEC, &iov, 1, sizeof(request));
+               mutex_lock(&nsock->tx_lock);
                ret = sock_xmit(nbd, i, 1, &from, 0, NULL);
                if (ret <= 0)
                        dev_err(disk_to_dev(nbd->disk),
                                "Send disconnect failed %d\n", ret);
+               mutex_unlock(&nsock->tx_lock);
        }
 }
 
@@ -993,9 +998,8 @@ static int nbd_disconnect(struct nbd_device *nbd)
        struct nbd_config *config = nbd->config;
 
        dev_info(disk_to_dev(nbd->disk), "NBD_DISCONNECT\n");
-       if (!test_and_set_bit(NBD_DISCONNECT_REQUESTED,
-                             &config->runtime_flags))
-               send_disconnects(nbd);
+       set_bit(NBD_DISCONNECT_REQUESTED, &config->runtime_flags);
+       send_disconnects(nbd);
        return 0;
 }
 
@@ -1076,7 +1080,9 @@ static int nbd_start_device(struct nbd_device *nbd)
                        return -ENOMEM;
                }
                sk_set_memalloc(config->socks[i]->sock->sk);
-               config->socks[i]->sock->sk->sk_sndtimeo = nbd->tag_set.timeout;
+               if (nbd->tag_set.timeout)
+                       config->socks[i]->sock->sk->sk_sndtimeo =
+                               nbd->tag_set.timeout;
                atomic_inc(&config->recv_threads);
                refcount_inc(&nbd->config_refs);
                INIT_WORK(&args->work, recv_work);
index 4e02aa5..1498b89 100644 (file)
@@ -541,12 +541,9 @@ virtblk_cache_type_store(struct device *dev, struct device_attribute *attr,
        int i;
 
        BUG_ON(!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_CONFIG_WCE));
-       for (i = ARRAY_SIZE(virtblk_cache_types); --i >= 0; )
-               if (sysfs_streq(buf, virtblk_cache_types[i]))
-                       break;
-
+       i = sysfs_match_string(virtblk_cache_types, buf);
        if (i < 0)
-               return -EINVAL;
+               return i;
 
        virtio_cwrite8(vdev, offsetof(struct virtio_blk_config, wce), i);
        virtblk_update_cache_mode(vdev);
index c852ed3..98e34e4 100644 (file)
@@ -111,7 +111,7 @@ struct blk_shadow {
 };
 
 struct blkif_req {
-       int     error;
+       blk_status_t    error;
 };
 
 static inline struct blkif_req *blkif_req(struct request *rq)
@@ -708,6 +708,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri
         * existing persistent grants, or if we have to get new grants,
         * as there are not sufficiently many free.
         */
+       bool new_persistent_gnts = false;
        struct scatterlist *sg;
        int num_sg, max_grefs, num_grant;
 
@@ -719,19 +720,21 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri
                 */
                max_grefs += INDIRECT_GREFS(max_grefs);
 
-       /*
-        * We have to reserve 'max_grefs' grants because persistent
-        * grants are shared by all rings.
-        */
-       if (max_grefs > 0)
-               if (gnttab_alloc_grant_references(max_grefs, &setup.gref_head) < 0) {
+       /* Check if we have enough persistent grants to allocate a requests */
+       if (rinfo->persistent_gnts_c < max_grefs) {
+               new_persistent_gnts = true;
+
+               if (gnttab_alloc_grant_references(
+                   max_grefs - rinfo->persistent_gnts_c,
+                   &setup.gref_head) < 0) {
                        gnttab_request_free_callback(
                                &rinfo->callback,
                                blkif_restart_queue_callback,
                                rinfo,
-                               max_grefs);
+                               max_grefs - rinfo->persistent_gnts_c);
                        return 1;
                }
+       }
 
        /* Fill out a communications ring structure. */
        id = blkif_ring_get_request(rinfo, req, &ring_req);
@@ -832,7 +835,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri
        if (unlikely(require_extra_req))
                rinfo->shadow[extra_id].req = *extra_ring_req;
 
-       if (max_grefs > 0)
+       if (new_persistent_gnts)
                gnttab_free_grant_references(setup.gref_head);
 
        return 0;
@@ -906,8 +909,8 @@ out_err:
        return BLK_STS_IOERR;
 
 out_busy:
-       spin_unlock_irqrestore(&rinfo->ring_lock, flags);
        blk_mq_stop_hw_queue(hctx);
+       spin_unlock_irqrestore(&rinfo->ring_lock, flags);
        return BLK_STS_RESOURCE;
 }
 
@@ -1616,7 +1619,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
                        if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
                                printk(KERN_WARNING "blkfront: %s: %s op failed\n",
                                       info->gd->disk_name, op_name(bret->operation));
-                               blkif_req(req)->error = -EOPNOTSUPP;
+                               blkif_req(req)->error = BLK_STS_NOTSUPP;
                        }
                        if (unlikely(bret->status == BLKIF_RSP_ERROR &&
                                     rinfo->shadow[id].req.u.rw.nr_segments == 0)) {
index 01a260f..afa3ce7 100644 (file)
 #define SEC_XFER_SIZE          512
 #define EXTRACT_SIZE           10
 
-#define DEBUG_RANDOM_BOOT 0
 
 #define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long))
 
@@ -437,6 +436,7 @@ static void _extract_crng(struct crng_state *crng,
 static void _crng_backtrack_protect(struct crng_state *crng,
                                    __u8 tmp[CHACHA20_BLOCK_SIZE], int used);
 static void process_random_ready_list(void);
+static void _get_random_bytes(void *buf, int nbytes);
 
 /**********************************************************************
  *
@@ -777,7 +777,7 @@ static void crng_initialize(struct crng_state *crng)
                _extract_entropy(&input_pool, &crng->state[4],
                                 sizeof(__u32) * 12, 0);
        else
-               get_random_bytes(&crng->state[4], sizeof(__u32) * 12);
+               _get_random_bytes(&crng->state[4], sizeof(__u32) * 12);
        for (i = 4; i < 16; i++) {
                if (!arch_get_random_seed_long(&rv) &&
                    !arch_get_random_long(&rv))
@@ -851,11 +851,6 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
        }
 }
 
-static inline void crng_wait_ready(void)
-{
-       wait_event_interruptible(crng_init_wait, crng_ready());
-}
-
 static void _extract_crng(struct crng_state *crng,
                          __u8 out[CHACHA20_BLOCK_SIZE])
 {
@@ -987,6 +982,11 @@ void add_device_randomness(const void *buf, unsigned int size)
        unsigned long time = random_get_entropy() ^ jiffies;
        unsigned long flags;
 
+       if (!crng_ready()) {
+               crng_fast_load(buf, size);
+               return;
+       }
+
        trace_add_device_randomness(size, _RET_IP_);
        spin_lock_irqsave(&input_pool.lock, flags);
        _mix_pool_bytes(&input_pool, buf, size);
@@ -1472,22 +1472,44 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
        return ret;
 }
 
+#define warn_unseeded_randomness(previous) \
+       _warn_unseeded_randomness(__func__, (void *) _RET_IP_, (previous))
+
+static void _warn_unseeded_randomness(const char *func_name, void *caller,
+                                     void **previous)
+{
+#ifdef CONFIG_WARN_ALL_UNSEEDED_RANDOM
+       const bool print_once = false;
+#else
+       static bool print_once __read_mostly;
+#endif
+
+       if (print_once ||
+           crng_ready() ||
+           (previous && (caller == READ_ONCE(*previous))))
+               return;
+       WRITE_ONCE(*previous, caller);
+#ifndef CONFIG_WARN_ALL_UNSEEDED_RANDOM
+       print_once = true;
+#endif
+       pr_notice("random: %s called from %pF with crng_init=%d\n",
+                 func_name, caller, crng_init);
+}
+
 /*
  * This function is the exported kernel interface.  It returns some
  * number of good random numbers, suitable for key generation, seeding
  * TCP sequence numbers, etc.  It does not rely on the hardware random
  * number generator.  For random bytes direct from the hardware RNG
- * (when available), use get_random_bytes_arch().
+ * (when available), use get_random_bytes_arch(). In order to ensure
+ * that the randomness provided by this function is okay, the function
+ * wait_for_random_bytes() should be called and return 0 at least once
+ * at any point prior.
  */
-void get_random_bytes(void *buf, int nbytes)
+static void _get_random_bytes(void *buf, int nbytes)
 {
        __u8 tmp[CHACHA20_BLOCK_SIZE];
 
-#if DEBUG_RANDOM_BOOT > 0
-       if (!crng_ready())
-               printk(KERN_NOTICE "random: %pF get_random_bytes called "
-                      "with crng_init = %d\n", (void *) _RET_IP_, crng_init);
-#endif
        trace_get_random_bytes(nbytes, _RET_IP_);
 
        while (nbytes >= CHACHA20_BLOCK_SIZE) {
@@ -1504,9 +1526,35 @@ void get_random_bytes(void *buf, int nbytes)
                crng_backtrack_protect(tmp, CHACHA20_BLOCK_SIZE);
        memzero_explicit(tmp, sizeof(tmp));
 }
+
+void get_random_bytes(void *buf, int nbytes)
+{
+       static void *previous;
+
+       warn_unseeded_randomness(&previous);
+       _get_random_bytes(buf, nbytes);
+}
 EXPORT_SYMBOL(get_random_bytes);
 
 /*
+ * Wait for the urandom pool to be seeded and thus guaranteed to supply
+ * cryptographically secure random numbers. This applies to: the /dev/urandom
+ * device, the get_random_bytes function, and the get_random_{u32,u64,int,long}
+ * family of functions. Using any of these functions without first calling
+ * this function forfeits the guarantee of security.
+ *
+ * Returns: 0 if the urandom pool has been seeded.
+ *          -ERESTARTSYS if the function was interrupted by a signal.
+ */
+int wait_for_random_bytes(void)
+{
+       if (likely(crng_ready()))
+               return 0;
+       return wait_event_interruptible(crng_init_wait, crng_ready());
+}
+EXPORT_SYMBOL(wait_for_random_bytes);
+
+/*
  * Add a callback function that will be invoked when the nonblocking
  * pool is initialised.
  *
@@ -1860,6 +1908,8 @@ const struct file_operations urandom_fops = {
 SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
                unsigned int, flags)
 {
+       int ret;
+
        if (flags & ~(GRND_NONBLOCK|GRND_RANDOM))
                return -EINVAL;
 
@@ -1872,9 +1922,9 @@ SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
        if (!crng_ready()) {
                if (flags & GRND_NONBLOCK)
                        return -EAGAIN;
-               crng_wait_ready();
-               if (signal_pending(current))
-                       return -ERESTARTSYS;
+               ret = wait_for_random_bytes();
+               if (unlikely(ret))
+                       return ret;
        }
        return urandom_read(NULL, buf, count, NULL);
 }
@@ -2035,15 +2085,19 @@ static rwlock_t batched_entropy_reset_lock = __RW_LOCK_UNLOCKED(batched_entropy_
 /*
  * Get a random word for internal kernel use only. The quality of the random
  * number is either as good as RDRAND or as good as /dev/urandom, with the
- * goal of being quite fast and not depleting entropy.
+ * goal of being quite fast and not depleting entropy. In order to ensure
+ * that the randomness provided by this function is okay, the function
+ * wait_for_random_bytes() should be called and return 0 at least once
+ * at any point prior.
  */
 static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64);
 u64 get_random_u64(void)
 {
        u64 ret;
-       bool use_lock = READ_ONCE(crng_init) < 2;
+       bool use_lock;
        unsigned long flags = 0;
        struct batched_entropy *batch;
+       static void *previous;
 
 #if BITS_PER_LONG == 64
        if (arch_get_random_long((unsigned long *)&ret))
@@ -2054,6 +2108,9 @@ u64 get_random_u64(void)
            return ret;
 #endif
 
+       warn_unseeded_randomness(&previous);
+
+       use_lock = READ_ONCE(crng_init) < 2;
        batch = &get_cpu_var(batched_entropy_u64);
        if (use_lock)
                read_lock_irqsave(&batched_entropy_reset_lock, flags);
@@ -2073,13 +2130,17 @@ static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32);
 u32 get_random_u32(void)
 {
        u32 ret;
-       bool use_lock = READ_ONCE(crng_init) < 2;
+       bool use_lock;
        unsigned long flags = 0;
        struct batched_entropy *batch;
+       static void *previous;
 
        if (arch_get_random_int(&ret))
                return ret;
 
+       warn_unseeded_randomness(&previous);
+
+       use_lock = READ_ONCE(crng_init) < 2;
        batch = &get_cpu_var(batched_entropy_u32);
        if (use_lock)
                read_lock_irqsave(&batched_entropy_reset_lock, flags);
index d406b08..68ca2d9 100644 (file)
@@ -221,6 +221,7 @@ config COMMON_CLK_VC5
 
 source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/hisilicon/Kconfig"
+source "drivers/clk/imgtec/Kconfig"
 source "drivers/clk/keystone/Kconfig"
 source "drivers/clk/mediatek/Kconfig"
 source "drivers/clk/meson/Kconfig"
index 4f6a812..cd376b3 100644 (file)
@@ -60,6 +60,7 @@ obj-y                                 += bcm/
 obj-$(CONFIG_ARCH_BERLIN)              += berlin/
 obj-$(CONFIG_H8300)                    += h8300/
 obj-$(CONFIG_ARCH_HISI)                        += hisilicon/
+obj-y                                  += imgtec/
 obj-$(CONFIG_ARCH_MXC)                 += imx/
 obj-$(CONFIG_MACH_INGENIC)             += ingenic/
 obj-$(CONFIG_ARCH_KEYSTONE)            += keystone/
diff --git a/drivers/clk/imgtec/Kconfig b/drivers/clk/imgtec/Kconfig
new file mode 100644 (file)
index 0000000..f6dcb74
--- /dev/null
@@ -0,0 +1,9 @@
+config COMMON_CLK_BOSTON
+       bool "Clock driver for MIPS Boston boards"
+       depends on MIPS || COMPILE_TEST
+       select MFD_SYSCON
+       ---help---
+         Enable this to support the system & CPU clocks on the MIPS Boston
+         development board from Imagination Technologies. These are simple
+         fixed rate clocks whose rate is determined by reading a platform
+         provided register.
diff --git a/drivers/clk/imgtec/Makefile b/drivers/clk/imgtec/Makefile
new file mode 100644 (file)
index 0000000..ac779b8
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_COMMON_CLK_BOSTON)                += clk-boston.o
diff --git a/drivers/clk/imgtec/clk-boston.c b/drivers/clk/imgtec/clk-boston.c
new file mode 100644 (file)
index 0000000..f18f103
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016-2017 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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.
+ */
+
+#define pr_fmt(fmt) "clk-boston: " fmt
+
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/mfd/syscon.h>
+
+#include <dt-bindings/clock/boston-clock.h>
+
+#define BOSTON_PLAT_MMCMDIV            0x30
+# define BOSTON_PLAT_MMCMDIV_CLK0DIV   (0xff << 0)
+# define BOSTON_PLAT_MMCMDIV_INPUT     (0xff << 8)
+# define BOSTON_PLAT_MMCMDIV_MUL       (0xff << 16)
+# define BOSTON_PLAT_MMCMDIV_CLK1DIV   (0xff << 24)
+
+#define BOSTON_CLK_COUNT 3
+
+static u32 ext_field(u32 val, u32 mask)
+{
+       return (val & mask) >> (ffs(mask) - 1);
+}
+
+static void __init clk_boston_setup(struct device_node *np)
+{
+       unsigned long in_freq, cpu_freq, sys_freq;
+       uint mmcmdiv, mul, cpu_div, sys_div;
+       struct clk_hw_onecell_data *onecell;
+       struct regmap *regmap;
+       struct clk_hw *hw;
+       int err;
+
+       regmap = syscon_node_to_regmap(np->parent);
+       if (IS_ERR(regmap)) {
+               pr_err("failed to find regmap\n");
+               return;
+       }
+
+       err = regmap_read(regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv);
+       if (err) {
+               pr_err("failed to read mmcm_div register: %d\n", err);
+               return;
+       }
+
+       in_freq = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_INPUT) * 1000000;
+       mul = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_MUL);
+
+       sys_div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK0DIV);
+       sys_freq = mult_frac(in_freq, mul, sys_div);
+
+       cpu_div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK1DIV);
+       cpu_freq = mult_frac(in_freq, mul, cpu_div);
+
+       onecell = kzalloc(sizeof(*onecell) +
+                         (BOSTON_CLK_COUNT * sizeof(struct clk_hw *)),
+                         GFP_KERNEL);
+       if (!onecell)
+               return;
+
+       onecell->num = BOSTON_CLK_COUNT;
+
+       hw = clk_hw_register_fixed_rate(NULL, "input", NULL, 0, in_freq);
+       if (IS_ERR(hw)) {
+               pr_err("failed to register input clock: %ld\n", PTR_ERR(hw));
+               return;
+       }
+       onecell->hws[BOSTON_CLK_INPUT] = hw;
+
+       hw = clk_hw_register_fixed_rate(NULL, "sys", "input", 0, sys_freq);
+       if (IS_ERR(hw)) {
+               pr_err("failed to register sys clock: %ld\n", PTR_ERR(hw));
+               return;
+       }
+       onecell->hws[BOSTON_CLK_SYS] = hw;
+
+       hw = clk_hw_register_fixed_rate(NULL, "cpu", "input", 0, cpu_freq);
+       if (IS_ERR(hw)) {
+               pr_err("failed to register cpu clock: %ld\n", PTR_ERR(hw));
+               return;
+       }
+       onecell->hws[BOSTON_CLK_CPU] = hw;
+
+       err = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, onecell);
+       if (err)
+               pr_err("failed to add DT provider: %d\n", err);
+}
+
+/*
+ * Use CLK_OF_DECLARE so that this driver is probed early enough to provide the
+ * CPU frequency for use with the GIC or cop0 counters/timers.
+ */
+CLK_OF_DECLARE(clk_boston, "img,boston-clock", clk_boston_setup);
index f6e7491..d509b50 100644 (file)
@@ -41,8 +41,16 @@ static __init int timer_irq_init(struct device_node *np,
        struct timer_of *to = container_of(of_irq, struct timer_of, of_irq);
        struct clock_event_device *clkevt = &to->clkevt;
 
-       of_irq->irq = of_irq->name ? of_irq_get_byname(np, of_irq->name):
-               irq_of_parse_and_map(np, of_irq->index);
+       if (of_irq->name) {
+               of_irq->irq = ret = of_irq_get_byname(np, of_irq->name);
+               if (ret < 0) {
+                       pr_err("Failed to get interrupt %s for %s\n",
+                              of_irq->name, np->full_name);
+                       return ret;
+               }
+       } else  {
+               of_irq->irq = irq_of_parse_and_map(np, of_irq->index);
+       }
        if (!of_irq->irq) {
                pr_err("Failed to map interrupt for %s\n", np->full_name);
                return -EINVAL;
index 4180422..ea6d625 100644 (file)
@@ -540,7 +540,7 @@ static void bL_cpufreq_ready(struct cpufreq_policy *policy)
                                     &power_coefficient);
 
                cdev[cur_cluster] = of_cpufreq_power_cooling_register(np,
-                               policy->related_cpus, power_coefficient, NULL);
+                               policy, power_coefficient, NULL);
                if (IS_ERR(cdev[cur_cluster])) {
                        dev_err(cpu_dev,
                                "running cpufreq without cooling device: %ld\n",
index c943787..fef3c21 100644 (file)
@@ -326,7 +326,7 @@ static void cpufreq_ready(struct cpufreq_policy *policy)
                                     &power_coefficient);
 
                priv->cdev = of_cpufreq_power_cooling_register(np,
-                               policy->related_cpus, power_coefficient, NULL);
+                               policy, power_coefficient, NULL);
                if (IS_ERR(priv->cdev)) {
                        dev_err(priv->cpu_dev,
                                "running cpufreq without cooling device: %ld\n",
index d362739..e75880e 100644 (file)
@@ -170,11 +170,10 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy)
        unsigned int i = 0, count = 0, ret = -ENOMEM;
        struct cpufreq_stats *stats;
        unsigned int alloc_size;
-       struct cpufreq_frequency_table *pos, *table;
+       struct cpufreq_frequency_table *pos;
 
-       /* We need cpufreq table for creating stats table */
-       table = policy->freq_table;
-       if (unlikely(!table))
+       count = cpufreq_table_count_valid_entries(policy);
+       if (!count)
                return;
 
        /* stats already initialized */
@@ -185,10 +184,6 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy)
        if (!stats)
                return;
 
-       /* Find total allocation size */
-       cpufreq_for_each_valid_entry(pos, table)
-               count++;
-
        alloc_size = count * sizeof(int) + count * sizeof(u64);
 
        alloc_size += count * count * sizeof(int);
@@ -205,7 +200,7 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy)
        stats->max_state = count;
 
        /* Find valid-unique entries */
-       cpufreq_for_each_valid_entry(pos, table)
+       cpufreq_for_each_valid_entry(pos, policy->freq_table)
                if (freq_table_get_index(stats, pos->frequency) == -1)
                        stats->freq_table[i++] = pos->frequency;
 
index 3575b82..4ee0431 100644 (file)
@@ -43,7 +43,7 @@ static int dbx500_cpufreq_exit(struct cpufreq_policy *policy)
 
 static void dbx500_cpufreq_ready(struct cpufreq_policy *policy)
 {
-       cdev = cpufreq_cooling_register(policy->cpus);
+       cdev = cpufreq_cooling_register(policy);
        if (IS_ERR(cdev))
                pr_err("Failed to register cooling device %ld\n", PTR_ERR(cdev));
        else
index d6f3235..6cd5035 100644 (file)
@@ -225,6 +225,9 @@ struct global_params {
  * @vid:               Stores VID limits for this CPU
  * @pid:               Stores PID parameters for this CPU
  * @last_sample_time:  Last Sample time
+ * @aperf_mperf_shift: Number of clock cycles after aperf, merf is incremented
+ *                     This shift is a multiplier to mperf delta to
+ *                     calculate CPU busy.
  * @prev_aperf:                Last APERF value read from APERF MSR
  * @prev_mperf:                Last MPERF value read from MPERF MSR
  * @prev_tsc:          Last timestamp counter (TSC) value
@@ -259,6 +262,7 @@ struct cpudata {
 
        u64     last_update;
        u64     last_sample_time;
+       u64     aperf_mperf_shift;
        u64     prev_aperf;
        u64     prev_mperf;
        u64     prev_tsc;
@@ -321,6 +325,7 @@ struct pstate_funcs {
        int (*get_min)(void);
        int (*get_turbo)(void);
        int (*get_scaling)(void);
+       int (*get_aperf_mperf_shift)(void);
        u64 (*get_val)(struct cpudata*, int pstate);
        void (*get_vid)(struct cpudata *);
        void (*update_util)(struct update_util_data *data, u64 time,
@@ -572,7 +577,7 @@ static int min_perf_pct_min(void)
        int turbo_pstate = cpu->pstate.turbo_pstate;
 
        return turbo_pstate ?
-               DIV_ROUND_UP(cpu->pstate.min_pstate * 100, turbo_pstate) : 0;
+               (cpu->pstate.min_pstate * 100 / turbo_pstate) : 0;
 }
 
 static s16 intel_pstate_get_epb(struct cpudata *cpu_data)
@@ -1486,6 +1491,11 @@ static u64 core_get_val(struct cpudata *cpudata, int pstate)
        return val;
 }
 
+static int knl_get_aperf_mperf_shift(void)
+{
+       return 10;
+}
+
 static int knl_get_turbo_pstate(void)
 {
        u64 value;
@@ -1543,6 +1553,9 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
        cpu->pstate.max_freq = cpu->pstate.max_pstate * cpu->pstate.scaling;
        cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling;
 
+       if (pstate_funcs.get_aperf_mperf_shift)
+               cpu->aperf_mperf_shift = pstate_funcs.get_aperf_mperf_shift();
+
        if (pstate_funcs.get_vid)
                pstate_funcs.get_vid(cpu);
 
@@ -1616,7 +1629,8 @@ static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
        int32_t busy_frac, boost;
        int target, avg_pstate;
 
-       busy_frac = div_fp(sample->mperf, sample->tsc);
+       busy_frac = div_fp(sample->mperf << cpu->aperf_mperf_shift,
+                          sample->tsc);
 
        boost = cpu->iowait_boost;
        cpu->iowait_boost >>= 1;
@@ -1675,7 +1689,8 @@ static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu)
                sample_ratio = div_fp(pid_params.sample_rate_ns, duration_ns);
                perf_scaled = mul_fp(perf_scaled, sample_ratio);
        } else {
-               sample_ratio = div_fp(100 * cpu->sample.mperf, cpu->sample.tsc);
+               sample_ratio = div_fp(100 * (cpu->sample.mperf << cpu->aperf_mperf_shift),
+                                     cpu->sample.tsc);
                if (sample_ratio < int_tofp(1))
                        perf_scaled = 0;
        }
@@ -1807,6 +1822,7 @@ static const struct pstate_funcs knl_funcs = {
        .get_max_physical = core_get_max_pstate_physical,
        .get_min = core_get_min_pstate,
        .get_turbo = knl_get_turbo_pstate,
+       .get_aperf_mperf_shift = knl_get_aperf_mperf_shift,
        .get_scaling = core_get_scaling,
        .get_val = core_get_val,
        .update_util = intel_pstate_update_util_pid,
@@ -2403,6 +2419,7 @@ static void __init copy_cpu_funcs(struct pstate_funcs *funcs)
        pstate_funcs.get_val   = funcs->get_val;
        pstate_funcs.get_vid   = funcs->get_vid;
        pstate_funcs.update_util = funcs->update_util;
+       pstate_funcs.get_aperf_mperf_shift = funcs->get_aperf_mperf_shift;
 
        intel_pstate_use_acpi_profile();
 }
index fd1886f..f9f00fb 100644 (file)
@@ -320,9 +320,7 @@ static void mtk_cpufreq_ready(struct cpufreq_policy *policy)
                of_property_read_u32(np, DYNAMIC_POWER, &capacitance);
 
                info->cdev = of_cpufreq_power_cooling_register(np,
-                                               policy->related_cpus,
-                                               capacitance,
-                                               NULL);
+                                               policy, capacitance, NULL);
 
                if (IS_ERR(info->cdev)) {
                        dev_err(info->cpu_dev,
index e2ea433..4ada55b 100644 (file)
@@ -278,8 +278,7 @@ static void qoriq_cpufreq_ready(struct cpufreq_policy *policy)
        struct device_node *np = of_get_cpu_node(policy->cpu, NULL);
 
        if (of_find_property(np, "#cooling-cells", NULL)) {
-               cpud->cdev = of_cpufreq_cooling_register(np,
-                                                        policy->related_cpus);
+               cpud->cdev = of_cpufreq_cooling_register(np, policy);
 
                if (IS_ERR(cpud->cdev) && PTR_ERR(cpud->cdev) != -ENOSYS) {
                        pr_err("cpu%d is not running as cooling device: %ld\n",
index 193204d..4b75084 100644 (file)
@@ -655,7 +655,7 @@ source "drivers/crypto/virtio/Kconfig"
 config CRYPTO_DEV_BCM_SPU
        tristate "Broadcom symmetric crypto/hash acceleration support"
        depends on ARCH_BCM_IPROC
-       depends on BCM_PDC_MBOX
+       depends on MAILBOX
        default m
        select CRYPTO_DES
        select CRYPTO_MD5
index a948202..dad4e5b 100644 (file)
@@ -1204,7 +1204,9 @@ static int atmel_sha_finup(struct ahash_request *req)
        ctx->flags |= SHA_FLAGS_FINUP;
 
        err1 = atmel_sha_update(req);
-       if (err1 == -EINPROGRESS || err1 == -EBUSY)
+       if (err1 == -EINPROGRESS ||
+           (err1 == -EBUSY && (ahash_request_flags(req) &
+                               CRYPTO_TFM_REQ_MAY_BACKLOG)))
                return err1;
 
        /*
index ef04c97..bf7ac62 100644 (file)
@@ -302,6 +302,7 @@ spu2_hash_xlate(enum hash_alg hash_alg, enum hash_mode hash_mode,
                break;
        case HASH_ALG_SHA3_512:
                *spu2_type = SPU2_HASH_TYPE_SHA3_512;
+               break;
        case HASH_ALG_LAST:
        default:
                err = -EINVAL;
index fde399c..0488b7f 100644 (file)
@@ -882,10 +882,10 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
 {
        struct ablkcipher_request *req = context;
        struct ablkcipher_edesc *edesc;
-#ifdef DEBUG
        struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
        int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
 
+#ifdef DEBUG
        dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
 #endif
 
@@ -904,6 +904,14 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
 #endif
 
        ablkcipher_unmap(jrdev, edesc, req);
+
+       /*
+        * The crypto API expects us to set the IV (req->info) to the last
+        * ciphertext block. This is used e.g. by the CTS mode.
+        */
+       scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize,
+                                ivsize, 0);
+
        kfree(edesc);
 
        ablkcipher_request_complete(req, err);
@@ -914,10 +922,10 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
 {
        struct ablkcipher_request *req = context;
        struct ablkcipher_edesc *edesc;
-#ifdef DEBUG
        struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
        int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
 
+#ifdef DEBUG
        dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
 #endif
 
@@ -935,6 +943,14 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
 #endif
 
        ablkcipher_unmap(jrdev, edesc, req);
+
+       /*
+        * The crypto API expects us to set the IV (req->info) to the last
+        * ciphertext block.
+        */
+       scatterwalk_map_and_copy(req->info, req->src, req->nbytes - ivsize,
+                                ivsize, 0);
+
        kfree(edesc);
 
        ablkcipher_request_complete(req, err);
index 7c44c90..910ec61 100644 (file)
@@ -396,7 +396,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in,
        ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result);
        if (!ret) {
                /* in progress */
-               wait_for_completion_interruptible(&result.completion);
+               wait_for_completion(&result.completion);
                ret = result.err;
 #ifdef DEBUG
                print_hex_dump(KERN_ERR,
index 1bb2816..c425d4a 100644 (file)
@@ -149,7 +149,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out,
        ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result);
        if (!ret) {
                /* in progress */
-               wait_for_completion_interruptible(&result.completion);
+               wait_for_completion(&result.completion);
                ret = result.err;
 #ifdef DEBUG
                print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
index 1b220f3..df21d99 100644 (file)
@@ -222,17 +222,17 @@ static inline int cvm_enc_dec(struct ablkcipher_request *req, u32 enc)
                return -EINPROGRESS;
 }
 
-int cvm_encrypt(struct ablkcipher_request *req)
+static int cvm_encrypt(struct ablkcipher_request *req)
 {
        return cvm_enc_dec(req, true);
 }
 
-int cvm_decrypt(struct ablkcipher_request *req)
+static int cvm_decrypt(struct ablkcipher_request *req)
 {
        return cvm_enc_dec(req, false);
 }
 
-int cvm_xts_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
+static int cvm_xts_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
                   u32 keylen)
 {
        struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
@@ -336,7 +336,7 @@ static int cvm_ecb_des3_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
        return cvm_setkey(cipher, key, keylen, DES3_ECB);
 }
 
-int cvm_enc_dec_init(struct crypto_tfm *tfm)
+static int cvm_enc_dec_init(struct crypto_tfm *tfm)
 {
        struct cvm_enc_ctx *ctx = crypto_tfm_ctx(tfm);
 
index ae44a46..9ccefb9 100644 (file)
@@ -18,8 +18,9 @@
 #define SE_GROUP 0
 
 #define DRIVER_VERSION "1.0"
+#define FW_DIR "cavium/"
 /* SE microcode */
-#define SE_FW  "cnn55xx_se.fw"
+#define SE_FW  FW_DIR "cnn55xx_se.fw"
 
 static const char nitrox_driver_name[] = "CNN55XX";
 
index cfc723a..0e81607 100644 (file)
@@ -898,26 +898,20 @@ static int chcr_update_tweak(struct ablkcipher_request *req, u8 *iv)
        u8 *key;
        unsigned int keylen;
 
-       cipher = crypto_alloc_cipher("aes-generic", 0, 0);
+       cipher = ablkctx->aes_generic;
        memcpy(iv, req->info, AES_BLOCK_SIZE);
 
-       if (IS_ERR(cipher)) {
-               ret = -ENOMEM;
-               goto out;
-       }
        keylen = ablkctx->enckey_len / 2;
        key = ablkctx->key + keylen;
        ret = crypto_cipher_setkey(cipher, key, keylen);
        if (ret)
-               goto out1;
+               goto out;
 
        crypto_cipher_encrypt_one(cipher, iv, iv);
        for (i = 0; i < (reqctx->processed / AES_BLOCK_SIZE); i++)
                gf128mul_x_ble((le128 *)iv, (le128 *)iv);
 
        crypto_cipher_decrypt_one(cipher, iv, iv);
-out1:
-       crypto_free_cipher(cipher);
 out:
        return ret;
 }
@@ -1261,6 +1255,17 @@ static int chcr_cra_init(struct crypto_tfm *tfm)
                pr_err("failed to allocate fallback for %s\n", alg->cra_name);
                return PTR_ERR(ablkctx->sw_cipher);
        }
+
+       if (get_cryptoalg_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_XTS) {
+               /* To update tweak*/
+               ablkctx->aes_generic = crypto_alloc_cipher("aes-generic", 0, 0);
+               if (IS_ERR(ablkctx->aes_generic)) {
+                       pr_err("failed to allocate aes cipher for tweak\n");
+                       return PTR_ERR(ablkctx->aes_generic);
+               }
+       } else
+               ablkctx->aes_generic = NULL;
+
        tfm->crt_ablkcipher.reqsize =  sizeof(struct chcr_blkcipher_req_ctx);
        return chcr_device_init(crypto_tfm_ctx(tfm));
 }
@@ -1291,6 +1296,8 @@ static void chcr_cra_exit(struct crypto_tfm *tfm)
        struct ablk_ctx *ablkctx = ABLK_CTX(ctx);
 
        crypto_free_skcipher(ablkctx->sw_cipher);
+       if (ablkctx->aes_generic)
+               crypto_free_cipher(ablkctx->aes_generic);
 }
 
 static int get_alg_config(struct algo_param *params,
index a4f95b0..30af1ee 100644 (file)
 
 struct ablk_ctx {
        struct crypto_skcipher *sw_cipher;
+       struct crypto_cipher *aes_generic;
        __be32 key_ctx_hdr;
        unsigned int enckey_len;
        unsigned char ciph_mode;
index e7f87ac..1fabd4a 100644 (file)
@@ -773,7 +773,6 @@ static int safexcel_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct resource *res;
        struct safexcel_crypto_priv *priv;
-       u64 dma_mask;
        int i, ret;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -802,9 +801,7 @@ static int safexcel_probe(struct platform_device *pdev)
                        return -EPROBE_DEFER;
        }
 
-       if (of_property_read_u64(dev->of_node, "dma-mask", &dma_mask))
-               dma_mask = DMA_BIT_MASK(64);
-       ret = dma_set_mask_and_coherent(dev, dma_mask);
+       ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
        if (ret)
                goto err_clk;
 
index fdcd976..688b051 100644 (file)
@@ -21,5 +21,5 @@ struct dax_region *alloc_dax_region(struct device *parent,
                int region_id, struct resource *res, unsigned int align,
                void *addr, unsigned long flags);
 struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region,
-               struct resource *res, int count);
+               int id, struct resource *res, int count);
 #endif /* __DEVICE_DAX_H__ */
index 12943d1..e9f3b3e 100644 (file)
@@ -529,7 +529,8 @@ static void dev_dax_release(struct device *dev)
        struct dax_region *dax_region = dev_dax->region;
        struct dax_device *dax_dev = dev_dax->dax_dev;
 
-       ida_simple_remove(&dax_region->ida, dev_dax->id);
+       if (dev_dax->id >= 0)
+               ida_simple_remove(&dax_region->ida, dev_dax->id);
        dax_region_put(dax_region);
        put_dax(dax_dev);
        kfree(dev_dax);
@@ -559,7 +560,7 @@ static void unregister_dev_dax(void *dev)
 }
 
 struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region,
-               struct resource *res, int count)
+               int id, struct resource *res, int count)
 {
        struct device *parent = dax_region->dev;
        struct dax_device *dax_dev;
@@ -567,7 +568,10 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region,
        struct inode *inode;
        struct device *dev;
        struct cdev *cdev;
-       int rc = 0, i;
+       int rc, i;
+
+       if (!count)
+               return ERR_PTR(-EINVAL);
 
        dev_dax = kzalloc(sizeof(*dev_dax) + sizeof(*res) * count, GFP_KERNEL);
        if (!dev_dax)
@@ -587,10 +591,16 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region,
        if (i < count)
                goto err_id;
 
-       dev_dax->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL);
-       if (dev_dax->id < 0) {
-               rc = dev_dax->id;
-               goto err_id;
+       if (id < 0) {
+               id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL);
+               dev_dax->id = id;
+               if (id < 0) {
+                       rc = id;
+                       goto err_id;
+               }
+       } else {
+               /* region provider owns @id lifetime */
+               dev_dax->id = -1;
        }
 
        /*
@@ -598,8 +608,10 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region,
         * device outside of mmap of the resulting character device.
         */
        dax_dev = alloc_dax(dev_dax, NULL, NULL);
-       if (!dax_dev)
+       if (!dax_dev) {
+               rc = -ENOMEM;
                goto err_dax;
+       }
 
        /* from here on we're committed to teardown via dax_dev_release() */
        dev = &dev_dax->dev;
@@ -620,7 +632,7 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region,
        dev->parent = parent;
        dev->groups = dax_attribute_groups;
        dev->release = dev_dax_release;
-       dev_set_name(dev, "dax%d.%d", dax_region->id, dev_dax->id);
+       dev_set_name(dev, "dax%d.%d", dax_region->id, id);
 
        rc = cdev_device_add(cdev, dev);
        if (rc) {
@@ -636,7 +648,8 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region,
        return dev_dax;
 
  err_dax:
-       ida_simple_remove(&dax_region->ida, dev_dax->id);
+       if (dev_dax->id >= 0)
+               ida_simple_remove(&dax_region->ida, dev_dax->id);
  err_id:
        kfree(dev_dax);
 
index 9f2a0b4..8d8c852 100644 (file)
@@ -58,13 +58,12 @@ static void dax_pmem_percpu_kill(void *data)
 
 static int dax_pmem_probe(struct device *dev)
 {
-       int rc;
        void *addr;
        struct resource res;
+       int rc, id, region_id;
        struct nd_pfn_sb *pfn_sb;
        struct dev_dax *dev_dax;
        struct dax_pmem *dax_pmem;
-       struct nd_region *nd_region;
        struct nd_namespace_io *nsio;
        struct dax_region *dax_region;
        struct nd_namespace_common *ndns;
@@ -123,14 +122,17 @@ static int dax_pmem_probe(struct device *dev)
        /* adjust the dax_region resource to the start of data */
        res.start += le64_to_cpu(pfn_sb->dataoff);
 
-       nd_region = to_nd_region(dev->parent);
-       dax_region = alloc_dax_region(dev, nd_region->id, &res,
+       rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", &region_id, &id);
+       if (rc != 2)
+               return -EINVAL;
+
+       dax_region = alloc_dax_region(dev, region_id, &res,
                        le32_to_cpu(pfn_sb->align), addr, PFN_DEV|PFN_MAP);
        if (!dax_region)
                return -ENOMEM;
 
        /* TODO: support for subdividing a dax region... */
-       dev_dax = devm_create_dev_dax(dax_region, &res, 1);
+       dev_dax = devm_create_dev_dax(dax_region, id, &res, 1);
 
        /* child dev_dax instances now own the lifetime of the dax_region */
        dax_region_put(dax_region);
index ce9e563..938eb48 100644 (file)
@@ -278,6 +278,12 @@ void dax_write_cache(struct dax_device *dax_dev, bool wc)
 }
 EXPORT_SYMBOL_GPL(dax_write_cache);
 
+bool dax_write_cache_enabled(struct dax_device *dax_dev)
+{
+       return test_bit(DAXDEV_WRITE_CACHE, &dax_dev->flags);
+}
+EXPORT_SYMBOL_GPL(dax_write_cache_enabled);
+
 bool dax_alive(struct dax_device *dax_dev)
 {
        lockdep_assert_held(&dax_srcu);
index 1769760..77028c2 100644 (file)
@@ -86,7 +86,7 @@ static struct attribute *dev_entries[] = {
        &dev_attr_set_freq.attr,
        NULL,
 };
-static struct attribute_group dev_attr_group = {
+static const struct attribute_group dev_attr_group = {
        .name   = "userspace",
        .attrs  = dev_entries,
 };
index 40a2499..1b89ebb 100644 (file)
@@ -336,8 +336,9 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "Cannot get the dmc interrupt resource\n");
-               return -EINVAL;
+               dev_err(&pdev->dev,
+                       "Cannot get the dmc interrupt resource: %d\n", irq);
+               return irq;
        }
        data = devm_kzalloc(dev, sizeof(struct rk3399_dmcfreq), GFP_KERNEL);
        if (!data)
index 214fff9..ae71215 100644 (file)
@@ -688,9 +688,9 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (irq <= 0) {
-               dev_err(&pdev->dev, "Failed to get IRQ\n");
-               return -ENODEV;
+       if (irq < 0) {
+               dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq);
+               return irq;
        }
 
        platform_set_drvdata(pdev, tegra);
index 57da14c..56e0a0e 100644 (file)
@@ -75,11 +75,6 @@ int dma_fence_signal_locked(struct dma_fence *fence)
        if (WARN_ON(!fence))
                return -EINVAL;
 
-       if (!ktime_to_ns(fence->timestamp)) {
-               fence->timestamp = ktime_get();
-               smp_mb__before_atomic();
-       }
-
        if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
                ret = -EINVAL;
 
@@ -87,8 +82,11 @@ int dma_fence_signal_locked(struct dma_fence *fence)
                 * we might have raced with the unlocked dma_fence_signal,
                 * still run through all callbacks
                 */
-       } else
+       } else {
+               fence->timestamp = ktime_get();
+               set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
                trace_dma_fence_signaled(fence);
+       }
 
        list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) {
                list_del_init(&cur->node);
@@ -115,14 +113,11 @@ int dma_fence_signal(struct dma_fence *fence)
        if (!fence)
                return -EINVAL;
 
-       if (!ktime_to_ns(fence->timestamp)) {
-               fence->timestamp = ktime_get();
-               smp_mb__before_atomic();
-       }
-
        if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
                return -EINVAL;
 
+       fence->timestamp = ktime_get();
+       set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
        trace_dma_fence_signaled(fence);
 
        if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags)) {
index 82a6e7f..59a3b2f 100644 (file)
@@ -84,7 +84,7 @@ static void sync_print_fence(struct seq_file *s,
                   show ? "_" : "",
                   sync_status_str(status));
 
-       if (status) {
+       if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags)) {
                struct timespec64 ts64 =
                        ktime_to_timespec64(fence->timestamp);
 
index 545e2c5..d7e219d 100644 (file)
@@ -391,7 +391,13 @@ static void sync_fill_fence_info(struct dma_fence *fence,
                sizeof(info->driver_name));
 
        info->status = dma_fence_get_status(fence);
-       info->timestamp_ns = ktime_to_ns(fence->timestamp);
+       while (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) &&
+              !test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags))
+               cpu_relax();
+       info->timestamp_ns =
+               test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags) ?
+               ktime_to_ns(fence->timestamp) :
+               ktime_set(0, 0);
 }
 
 static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
index f742596..37e24f5 100644 (file)
@@ -17,6 +17,7 @@ cflags-$(CONFIG_ARM)          := $(subst -pg,,$(KBUILD_CFLAGS)) \
 cflags-$(CONFIG_EFI_ARMSTUB)   += -I$(srctree)/scripts/dtc/libfdt
 
 KBUILD_CFLAGS                  := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
+                                  -D__NO_FORTIFY \
                                   $(call cc-option,-ffreestanding) \
                                   $(call cc-option,-fno-stack-protector)
 
index a485864..06432d8 100644 (file)
@@ -532,7 +532,7 @@ static inline uint32_t fsi_smode_sid(int x)
        return (x & FSI_SMODE_SID_MASK) << FSI_SMODE_SID_SHIFT;
 }
 
-static const uint32_t fsi_slave_smode(int id)
+static uint32_t fsi_slave_smode(int id)
 {
        return FSI_SMODE_WSC | FSI_SMODE_ECRC
                | fsi_smode_sid(id)
@@ -883,17 +883,16 @@ struct bus_type fsi_bus_type = {
 };
 EXPORT_SYMBOL_GPL(fsi_bus_type);
 
-static int fsi_init(void)
+static int __init fsi_init(void)
 {
        return bus_register(&fsi_bus_type);
 }
+postcore_initcall(fsi_init);
 
 static void fsi_exit(void)
 {
        bus_unregister(&fsi_bus_type);
 }
-
-module_init(fsi_init);
 module_exit(fsi_exit);
 module_param(discard_errors, int, 0664);
 MODULE_LICENSE("GPL");
index 5f8ada1..37971d9 100644 (file)
@@ -101,7 +101,6 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
        if (adev->kfd) {
                struct kgd2kfd_shared_resources gpu_resources = {
                        .compute_vmid_bitmap = 0xFF00,
-                       .num_mec = adev->gfx.mec.num_mec,
                        .num_pipe_per_mec = adev->gfx.mec.num_pipe_per_mec,
                        .num_queue_per_pipe = adev->gfx.mec.num_queue_per_pipe
                };
@@ -122,7 +121,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
 
                /* According to linux/bitmap.h we shouldn't use bitmap_clear if
                 * nbits is not compile time constant */
-               last_valid_bit = adev->gfx.mec.num_mec
+               last_valid_bit = 1 /* only first MEC can have compute queues */
                                * adev->gfx.mec.num_pipe_per_mec
                                * adev->gfx.mec.num_queue_per_pipe;
                for (i = last_valid_bit; i < KGD_MAX_QUEUES; ++i)
index f621ee1..5e771bc 100644 (file)
@@ -198,12 +198,16 @@ amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id)
        result = idr_find(&fpriv->bo_list_handles, id);
 
        if (result) {
-               if (kref_get_unless_zero(&result->refcount))
+               if (kref_get_unless_zero(&result->refcount)) {
+                       rcu_read_unlock();
                        mutex_lock(&result->lock);
-               else
+               } else {
+                       rcu_read_unlock();
                        result = NULL;
+               }
+       } else {
+               rcu_read_unlock();
        }
-       rcu_read_unlock();
 
        return result;
 }
index 3a0b69b..c9b9c88 100644 (file)
@@ -1475,21 +1475,23 @@ static void gfx_v9_0_tiling_mode_table_init(struct amdgpu_device *adev)
 
 static void gfx_v9_0_select_se_sh(struct amdgpu_device *adev, u32 se_num, u32 sh_num, u32 instance)
 {
-       u32 data = REG_SET_FIELD(0, GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES, 1);
+       u32 data;
 
-       if ((se_num == 0xffffffff) && (sh_num == 0xffffffff)) {
-               data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_BROADCAST_WRITES, 1);
-               data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_BROADCAST_WRITES, 1);
-       } else if (se_num == 0xffffffff) {
-               data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_INDEX, sh_num);
+       if (instance == 0xffffffff)
+               data = REG_SET_FIELD(0, GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES, 1);
+       else
+               data = REG_SET_FIELD(0, GRBM_GFX_INDEX, INSTANCE_INDEX, instance);
+
+       if (se_num == 0xffffffff)
                data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_BROADCAST_WRITES, 1);
-       } else if (sh_num == 0xffffffff) {
-               data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_BROADCAST_WRITES, 1);
+       else
                data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_INDEX, se_num);
-       } else {
+
+       if (sh_num == 0xffffffff)
+               data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_BROADCAST_WRITES, 1);
+       else
                data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_INDEX, sh_num);
-               data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_INDEX, se_num);
-       }
+
        WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, data);
 }
 
index 88187bf..3f95f7c 100644 (file)
@@ -226,10 +226,6 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
 
        kfd->shared_resources = *gpu_resources;
 
-       /* We only use the first MEC */
-       if (kfd->shared_resources.num_mec > 1)
-               kfd->shared_resources.num_mec = 1;
-
        /* calculate max size of mqds needed for queues */
        size = max_num_of_queues_per_device *
                        kfd->device_info->mqd_size_aligned;
index 955aa30..602769c 100644 (file)
@@ -77,13 +77,6 @@ static bool is_pipe_enabled(struct device_queue_manager *dqm, int mec, int pipe)
        return false;
 }
 
-unsigned int get_mec_num(struct device_queue_manager *dqm)
-{
-       BUG_ON(!dqm || !dqm->dev);
-
-       return dqm->dev->shared_resources.num_mec;
-}
-
 unsigned int get_queues_num(struct device_queue_manager *dqm)
 {
        BUG_ON(!dqm || !dqm->dev);
index 66b9615..faf820a 100644 (file)
@@ -180,7 +180,6 @@ void device_queue_manager_init_cik(struct device_queue_manager_asic_ops *ops);
 void device_queue_manager_init_vi(struct device_queue_manager_asic_ops *ops);
 void program_sh_mem_settings(struct device_queue_manager *dqm,
                                        struct qcm_process_device *qpd);
-unsigned int get_mec_num(struct device_queue_manager *dqm);
 unsigned int get_queues_num(struct device_queue_manager *dqm);
 unsigned int get_queues_per_pipe(struct device_queue_manager *dqm);
 unsigned int get_pipes_per_mec(struct device_queue_manager *dqm);
index 91ef148..36f3766 100644 (file)
@@ -63,9 +63,6 @@ struct kgd2kfd_shared_resources {
        /* Bit n == 1 means VMID n is available for KFD. */
        unsigned int compute_vmid_bitmap;
 
-       /* number of mec available from the hardware */
-       uint32_t num_mec;
-
        /* number of pipes per mec */
        uint32_t num_pipe_per_mec;
 
index d6f097f..197174e 100644 (file)
@@ -2128,15 +2128,9 @@ static int vega10_populate_avfs_parameters(struct pp_hwmgr *hwmgr)
                        pp_table->AvfsGbCksOff.m2_shift = 12;
                        pp_table->AvfsGbCksOff.b_shift = 0;
 
-                       for (i = 0; i < dep_table->count; i++) {
-                               if (dep_table->entries[i].sclk_offset == 0)
-                                       pp_table->StaticVoltageOffsetVid[i] = 248;
-                               else
-                                       pp_table->StaticVoltageOffsetVid[i] =
-                                               (uint8_t)(dep_table->entries[i].sclk_offset *
-                                                               VOLTAGE_VID_OFFSET_SCALE2 /
-                                                               VOLTAGE_VID_OFFSET_SCALE1);
-                       }
+                       for (i = 0; i < dep_table->count; i++)
+                               pp_table->StaticVoltageOffsetVid[i] =
+                                               convert_to_vid((uint8_t)(dep_table->entries[i].sclk_offset));
 
                        if ((PPREGKEY_VEGA10QUADRATICEQUATION_DFLT !=
                                        data->disp_clk_quad_eqn_a) &&
index 99f9a4b..67fe19e 100644 (file)
@@ -161,7 +161,7 @@ struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
        int ret;
 
        if (!panel)
-               return ERR_PTR(EINVAL);
+               return ERR_PTR(-EINVAL);
 
        panel_bridge = devm_kzalloc(panel->dev, sizeof(*panel_bridge),
                                    GFP_KERNEL);
index ec1ed94..d34e509 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
+#include <linux/uio.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drmP.h>
@@ -140,101 +141,83 @@ static loff_t auxdev_llseek(struct file *file, loff_t offset, int whence)
        return fixed_size_llseek(file, offset, whence, AUX_MAX_OFFSET);
 }
 
-static ssize_t auxdev_read(struct file *file, char __user *buf, size_t count,
-                          loff_t *offset)
+static ssize_t auxdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
-       size_t bytes_pending, num_bytes_processed = 0;
-       struct drm_dp_aux_dev *aux_dev = file->private_data;
+       struct drm_dp_aux_dev *aux_dev = iocb->ki_filp->private_data;
+       loff_t pos = iocb->ki_pos;
        ssize_t res = 0;
 
        if (!atomic_inc_not_zero(&aux_dev->usecount))
                return -ENODEV;
 
-       bytes_pending = min((loff_t)count, AUX_MAX_OFFSET - (*offset));
-
-       if (!access_ok(VERIFY_WRITE, buf, bytes_pending)) {
-               res = -EFAULT;
-               goto out;
-       }
+       iov_iter_truncate(to, AUX_MAX_OFFSET - pos);
 
-       while (bytes_pending > 0) {
-               uint8_t localbuf[DP_AUX_MAX_PAYLOAD_BYTES];
-               ssize_t todo = min_t(size_t, bytes_pending, sizeof(localbuf));
+       while (iov_iter_count(to)) {
+               uint8_t buf[DP_AUX_MAX_PAYLOAD_BYTES];
+               ssize_t todo = min(iov_iter_count(to), sizeof(buf));
 
                if (signal_pending(current)) {
-                       res = num_bytes_processed ?
-                               num_bytes_processed : -ERESTARTSYS;
-                       goto out;
+                       res = -ERESTARTSYS;
+                       break;
                }
 
-               res = drm_dp_dpcd_read(aux_dev->aux, *offset, localbuf, todo);
-               if (res <= 0) {
-                       res = num_bytes_processed ? num_bytes_processed : res;
-                       goto out;
-               }
-               if (__copy_to_user(buf + num_bytes_processed, localbuf, res)) {
-                       res = num_bytes_processed ?
-                               num_bytes_processed : -EFAULT;
-                       goto out;
+               res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo);
+               if (res <= 0)
+                       break;
+
+               if (copy_to_iter(buf, res, to) != res) {
+                       res = -EFAULT;
+                       break;
                }
-               bytes_pending -= res;
-               *offset += res;
-               num_bytes_processed += res;
-               res = num_bytes_processed;
+
+               pos += res;
        }
 
-out:
+       if (pos != iocb->ki_pos)
+               res = pos - iocb->ki_pos;
+       iocb->ki_pos = pos;
+
        atomic_dec(&aux_dev->usecount);
        wake_up_atomic_t(&aux_dev->usecount);
        return res;
 }
 
-static ssize_t auxdev_write(struct file *file, const char __user *buf,
-                           size_t count, loff_t *offset)
+static ssize_t auxdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
-       size_t bytes_pending, num_bytes_processed = 0;
-       struct drm_dp_aux_dev *aux_dev = file->private_data;
+       struct drm_dp_aux_dev *aux_dev = iocb->ki_filp->private_data;
+       loff_t pos = iocb->ki_pos;
        ssize_t res = 0;
 
        if (!atomic_inc_not_zero(&aux_dev->usecount))
                return -ENODEV;
 
-       bytes_pending = min((loff_t)count, AUX_MAX_OFFSET - *offset);
-
-       if (!access_ok(VERIFY_READ, buf, bytes_pending)) {
-               res = -EFAULT;
-               goto out;
-       }
+       iov_iter_truncate(from, AUX_MAX_OFFSET - pos);
 
-       while (bytes_pending > 0) {
-               uint8_t localbuf[DP_AUX_MAX_PAYLOAD_BYTES];
-               ssize_t todo = min_t(size_t, bytes_pending, sizeof(localbuf));
+       while (iov_iter_count(from)) {
+               uint8_t buf[DP_AUX_MAX_PAYLOAD_BYTES];
+               ssize_t todo = min(iov_iter_count(from), sizeof(buf));
 
                if (signal_pending(current)) {
-                       res = num_bytes_processed ?
-                               num_bytes_processed : -ERESTARTSYS;
-                       goto out;
+                       res = -ERESTARTSYS;
+                       break;
                }
 
-               if (__copy_from_user(localbuf,
-                                    buf + num_bytes_processed, todo)) {
-                       res = num_bytes_processed ?
-                               num_bytes_processed : -EFAULT;
-                       goto out;
+               if (!copy_from_iter_full(buf, todo, from)) {
+                       res = -EFAULT;
+                       break;
                }
 
-               res = drm_dp_dpcd_write(aux_dev->aux, *offset, localbuf, todo);
-               if (res <= 0) {
-                       res = num_bytes_processed ? num_bytes_processed : res;
-                       goto out;
-               }
-               bytes_pending -= res;
-               *offset += res;
-               num_bytes_processed += res;
-               res = num_bytes_processed;
+               res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo);
+               if (res <= 0)
+                       break;
+
+               pos += res;
        }
 
-out:
+       if (pos != iocb->ki_pos)
+               res = pos - iocb->ki_pos;
+       iocb->ki_pos = pos;
+
        atomic_dec(&aux_dev->usecount);
        wake_up_atomic_t(&aux_dev->usecount);
        return res;
@@ -251,8 +234,8 @@ static int auxdev_release(struct inode *inode, struct file *file)
 static const struct file_operations auxdev_fops = {
        .owner          = THIS_MODULE,
        .llseek         = auxdev_llseek,
-       .read           = auxdev_read,
-       .write          = auxdev_write,
+       .read_iter      = auxdev_read_iter,
+       .write_iter     = auxdev_write_iter,
        .open           = auxdev_open,
        .release        = auxdev_release,
 };
index 213fb83..08af8d6 100644 (file)
@@ -544,7 +544,7 @@ void drm_dp_downstream_debug(struct seq_file *m,
                                 DP_DETAILED_CAP_INFO_AVAILABLE;
        int clk;
        int bpc;
-       char id[6];
+       char id[7];
        int len;
        uint8_t rev[2];
        int type = port_cap[0] & DP_DS_PORT_TYPE_MASK;
@@ -583,6 +583,7 @@ void drm_dp_downstream_debug(struct seq_file *m,
                seq_puts(m, "\t\tType: N/A\n");
        }
 
+       memset(id, 0, sizeof(id));
        drm_dp_downstream_id(aux, id);
        seq_printf(m, "\t\tID: %s\n", id);
 
@@ -591,7 +592,7 @@ void drm_dp_downstream_debug(struct seq_file *m,
                seq_printf(m, "\t\tHW: %d.%d\n",
                           (rev[0] & 0xf0) >> 4, rev[0] & 0xf);
 
-       len = drm_dp_dpcd_read(aux, DP_BRANCH_SW_REV, &rev, 2);
+       len = drm_dp_dpcd_read(aux, DP_BRANCH_SW_REV, rev, 2);
        if (len > 0)
                seq_printf(m, "\t\tSW: %d.%d\n", rev[0], rev[1]);
 
index bfd237c..ae5f068 100644 (file)
@@ -330,6 +330,13 @@ static bool drm_dp_sideband_msg_build(struct drm_dp_sideband_msg_rx *msg,
                        return false;
                }
 
+               /*
+                * ignore out-of-order messages or messages that are part of a
+                * failed transaction
+                */
+               if (!recv_hdr.somt && !msg->have_somt)
+                       return false;
+
                /* get length contained in this portion */
                msg->curchunk_len = recv_hdr.msg_len;
                msg->curchunk_hdrlen = hdrlen;
@@ -2164,7 +2171,7 @@ out_unlock:
 }
 EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume);
 
-static void drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
+static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
 {
        int len;
        u8 replyblock[32];
@@ -2179,12 +2186,12 @@ static void drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
                               replyblock, len);
        if (ret != len) {
                DRM_DEBUG_KMS("failed to read DPCD down rep %d %d\n", len, ret);
-               return;
+               return false;
        }
        ret = drm_dp_sideband_msg_build(msg, replyblock, len, true);
        if (!ret) {
                DRM_DEBUG_KMS("sideband msg build failed %d\n", replyblock[0]);
-               return;
+               return false;
        }
        replylen = msg->curchunk_len + msg->curchunk_hdrlen;
 
@@ -2196,21 +2203,32 @@ static void drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
                ret = drm_dp_dpcd_read(mgr->aux, basereg + curreply,
                                    replyblock, len);
                if (ret != len) {
-                       DRM_DEBUG_KMS("failed to read a chunk\n");
+                       DRM_DEBUG_KMS("failed to read a chunk (len %d, ret %d)\n",
+                                     len, ret);
+                       return false;
                }
+
                ret = drm_dp_sideband_msg_build(msg, replyblock, len, false);
-               if (ret == false)
+               if (!ret) {
                        DRM_DEBUG_KMS("failed to build sideband msg\n");
+                       return false;
+               }
+
                curreply += len;
                replylen -= len;
        }
+       return true;
 }
 
 static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
 {
        int ret = 0;
 
-       drm_dp_get_one_sb_msg(mgr, false);
+       if (!drm_dp_get_one_sb_msg(mgr, false)) {
+               memset(&mgr->down_rep_recv, 0,
+                      sizeof(struct drm_dp_sideband_msg_rx));
+               return 0;
+       }
 
        if (mgr->down_rep_recv.have_eomt) {
                struct drm_dp_sideband_msg_tx *txmsg;
@@ -2266,7 +2284,12 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
 static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
 {
        int ret = 0;
-       drm_dp_get_one_sb_msg(mgr, true);
+
+       if (!drm_dp_get_one_sb_msg(mgr, true)) {
+               memset(&mgr->up_req_recv, 0,
+                      sizeof(struct drm_dp_sideband_msg_rx));
+               return 0;
+       }
 
        if (mgr->up_req_recv.have_eomt) {
                struct drm_dp_sideband_msg_req_body msg;
@@ -2318,7 +2341,9 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
                        DRM_DEBUG_KMS("Got RSN: pn: %d avail_pbn %d\n", msg.u.resource_stat.port_number, msg.u.resource_stat.available_pbn);
                }
 
-               drm_dp_put_mst_branch_device(mstb);
+               if (mstb)
+                       drm_dp_put_mst_branch_device(mstb);
+
                memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
        }
        return ret;
index fc8ef42..b3ef4f1 100644 (file)
@@ -832,6 +832,7 @@ unlock:
                drm_atomic_clean_old_fb(dev, plane_mask, ret);
 
        if (ret == -EDEADLK) {
+               drm_atomic_state_clear(state);
                drm_modeset_backoff(&ctx);
                goto retry;
        }
index 0b2d8c4..d1f2028 100644 (file)
@@ -112,6 +112,9 @@ static int compat_drm_version(struct file *file, unsigned int cmd,
        v32.version_major = v.version_major;
        v32.version_minor = v.version_minor;
        v32.version_patchlevel = v.version_patchlevel;
+       v32.name_len = v.name_len;
+       v32.date_len = v.date_len;
+       v32.desc_len = v.desc_len;
        if (copy_to_user((void __user *)arg, &v32, sizeof(v32)))
                return -EFAULT;
        return 0;
index 463e4d8..e9f33cd 100644 (file)
@@ -242,7 +242,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
         * Otherwise reinitialize delayed at next vblank interrupt and assign 0
         * for now, to mark the vblanktimestamp as invalid.
         */
-       if (!rc && in_vblank_irq)
+       if (!rc && !in_vblank_irq)
                t_vblank = (struct timeval) {0, 0};
 
        store_vblank(dev, pipe, diff, &t_vblank, cur_vblank);
index 1d18534..305dc3d 100644 (file)
@@ -75,6 +75,7 @@ config DRM_EXYNOS_DP
 config DRM_EXYNOS_HDMI
        bool "HDMI"
        depends on DRM_EXYNOS_MIXER || DRM_EXYNOS5433_DECON
+       select CEC_CORE if CEC_NOTIFIER
        help
          Choose this option if you want to use Exynos HDMI for DRM.
 
index 35a8dfc..242bd50 100644 (file)
@@ -453,7 +453,6 @@ static int exynos_drm_platform_probe(struct platform_device *pdev)
        struct component_match *match;
 
        pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-       exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);
 
        match = exynos_drm_match_add(&pdev->dev);
        if (IS_ERR(match))
index a11b795..b6a46d9 100644 (file)
@@ -1651,8 +1651,6 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
                return ret;
 
        dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
-       if (!dsi->bridge_node)
-               return -EINVAL;
 
        return 0;
 }
@@ -1687,9 +1685,11 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
                return ret;
        }
 
-       bridge = of_drm_find_bridge(dsi->bridge_node);
-       if (bridge)
-               drm_bridge_attach(encoder, bridge, NULL);
+       if (dsi->bridge_node) {
+               bridge = of_drm_find_bridge(dsi->bridge_node);
+               if (bridge)
+                       drm_bridge_attach(encoder, bridge, NULL);
+       }
 
        return mipi_dsi_host_register(&dsi->dsi_host);
 }
index e457205..16bbee8 100644 (file)
@@ -340,16 +340,10 @@ static int exynos_mic_bind(struct device *dev, struct device *master,
                           void *data)
 {
        struct exynos_mic *mic = dev_get_drvdata(dev);
-       int ret;
 
-       mic->bridge.funcs = &mic_bridge_funcs;
-       mic->bridge.of_node = dev->of_node;
        mic->bridge.driver_private = mic;
-       ret = drm_bridge_add(&mic->bridge);
-       if (ret)
-               DRM_ERROR("mic: Failed to add MIC to the global bridge list\n");
 
-       return ret;
+       return 0;
 }
 
 static void exynos_mic_unbind(struct device *dev, struct device *master,
@@ -365,8 +359,6 @@ static void exynos_mic_unbind(struct device *dev, struct device *master,
 
 already_disabled:
        mutex_unlock(&mic_mutex);
-
-       drm_bridge_remove(&mic->bridge);
 }
 
 static const struct component_ops exynos_mic_component_ops = {
@@ -461,6 +453,15 @@ static int exynos_mic_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, mic);
 
+       mic->bridge.funcs = &mic_bridge_funcs;
+       mic->bridge.of_node = dev->of_node;
+
+       ret = drm_bridge_add(&mic->bridge);
+       if (ret) {
+               DRM_ERROR("mic: Failed to add MIC to the global bridge list\n");
+               return ret;
+       }
+
        pm_runtime_enable(dev);
 
        ret = component_add(dev, &exynos_mic_component_ops);
@@ -479,8 +480,13 @@ err:
 
 static int exynos_mic_remove(struct platform_device *pdev)
 {
+       struct exynos_mic *mic = platform_get_drvdata(pdev);
+
        component_del(&pdev->dev, &exynos_mic_component_ops);
        pm_runtime_disable(&pdev->dev);
+
+       drm_bridge_remove(&mic->bridge);
+
        return 0;
 }
 
index 06bfbe4..d3b69d6 100644 (file)
@@ -1501,8 +1501,6 @@ static void hdmi_disable(struct drm_encoder *encoder)
         */
        cancel_delayed_work(&hdata->hotplug_work);
        cec_notifier_set_phys_addr(hdata->notifier, CEC_PHYS_ADDR_INVALID);
-
-       hdmiphy_disable(hdata);
 }
 
 static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
@@ -1676,7 +1674,7 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
        return hdmi_bridge_init(hdata);
 }
 
-static struct of_device_id hdmi_match_types[] = {
+static const struct of_device_id hdmi_match_types[] = {
        {
                .compatible = "samsung,exynos4210-hdmi",
                .data = &exynos4210_hdmi_driver_data,
@@ -1934,8 +1932,7 @@ static int hdmi_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int exynos_hdmi_suspend(struct device *dev)
+static int __maybe_unused exynos_hdmi_suspend(struct device *dev)
 {
        struct hdmi_context *hdata = dev_get_drvdata(dev);
 
@@ -1944,7 +1941,7 @@ static int exynos_hdmi_suspend(struct device *dev)
        return 0;
 }
 
-static int exynos_hdmi_resume(struct device *dev)
+static int __maybe_unused exynos_hdmi_resume(struct device *dev)
 {
        struct hdmi_context *hdata = dev_get_drvdata(dev);
        int ret;
@@ -1955,7 +1952,6 @@ static int exynos_hdmi_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
 static const struct dev_pm_ops exynos_hdmi_pm_ops = {
        SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL)
index 6bed4f3..a998a8d 100644 (file)
@@ -1094,28 +1094,28 @@ static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
        .atomic_check           = mixer_atomic_check,
 };
 
-static struct mixer_drv_data exynos5420_mxr_drv_data = {
+static const struct mixer_drv_data exynos5420_mxr_drv_data = {
        .version = MXR_VER_128_0_0_184,
        .is_vp_enabled = 0,
 };
 
-static struct mixer_drv_data exynos5250_mxr_drv_data = {
+static const struct mixer_drv_data exynos5250_mxr_drv_data = {
        .version = MXR_VER_16_0_33_0,
        .is_vp_enabled = 0,
 };
 
-static struct mixer_drv_data exynos4212_mxr_drv_data = {
+static const struct mixer_drv_data exynos4212_mxr_drv_data = {
        .version = MXR_VER_0_0_0_16,
        .is_vp_enabled = 1,
 };
 
-static struct mixer_drv_data exynos4210_mxr_drv_data = {
+static const struct mixer_drv_data exynos4210_mxr_drv_data = {
        .version = MXR_VER_0_0_0_16,
        .is_vp_enabled = 1,
        .has_sclk = 1,
 };
 
-static struct of_device_id mixer_match_types[] = {
+static const struct of_device_id mixer_match_types[] = {
        {
                .compatible = "samsung,exynos4210-mixer",
                .data   = &exynos4210_mxr_drv_data,
index 51241de..713848c 100644 (file)
@@ -2536,6 +2536,11 @@ static int scan_workload(struct intel_vgpu_workload *workload)
                gma_head == gma_tail)
                return 0;
 
+       if (!intel_gvt_ggtt_validate_range(s.vgpu, s.ring_start, s.ring_size)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        ret = ip_gma_set(&s, gma_head);
        if (ret)
                goto out;
@@ -2579,6 +2584,11 @@ static int scan_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
        s.rb_va = wa_ctx->indirect_ctx.shadow_va;
        s.workload = workload;
 
+       if (!intel_gvt_ggtt_validate_range(s.vgpu, s.ring_start, s.ring_size)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        ret = ip_gma_set(&s, gma_head);
        if (ret)
                goto out;
index e0261fc..7cb0818 100644 (file)
@@ -197,6 +197,12 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
                        (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
                        (PORT_B << TRANS_DDI_PORT_SHIFT) |
                        TRANS_DDI_FUNC_ENABLE);
+               if (IS_BROADWELL(dev_priv)) {
+                       vgpu_vreg(vgpu, PORT_CLK_SEL(PORT_B)) &=
+                               ~PORT_CLK_SEL_MASK;
+                       vgpu_vreg(vgpu, PORT_CLK_SEL(PORT_B)) |=
+                               PORT_CLK_SEL_LCPLL_810;
+               }
                vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_B)) |= DDI_BUF_CTL_ENABLE;
                vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_B)) &= ~DDI_BUF_IS_IDLE;
                vgpu_vreg(vgpu, SDEISR) |= SDE_PORTB_HOTPLUG_CPT;
@@ -211,6 +217,12 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
                        (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
                        (PORT_C << TRANS_DDI_PORT_SHIFT) |
                        TRANS_DDI_FUNC_ENABLE);
+               if (IS_BROADWELL(dev_priv)) {
+                       vgpu_vreg(vgpu, PORT_CLK_SEL(PORT_C)) &=
+                               ~PORT_CLK_SEL_MASK;
+                       vgpu_vreg(vgpu, PORT_CLK_SEL(PORT_C)) |=
+                               PORT_CLK_SEL_LCPLL_810;
+               }
                vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_C)) |= DDI_BUF_CTL_ENABLE;
                vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_C)) &= ~DDI_BUF_IS_IDLE;
                vgpu_vreg(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIC_DETECTED;
@@ -225,6 +237,12 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
                        (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
                        (PORT_D << TRANS_DDI_PORT_SHIFT) |
                        TRANS_DDI_FUNC_ENABLE);
+               if (IS_BROADWELL(dev_priv)) {
+                       vgpu_vreg(vgpu, PORT_CLK_SEL(PORT_D)) &=
+                               ~PORT_CLK_SEL_MASK;
+                       vgpu_vreg(vgpu, PORT_CLK_SEL(PORT_D)) |=
+                               PORT_CLK_SEL_LCPLL_810;
+               }
                vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_D)) |= DDI_BUF_CTL_ENABLE;
                vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_D)) &= ~DDI_BUF_IS_IDLE;
                vgpu_vreg(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDID_DETECTED;
@@ -244,6 +262,10 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
 
                vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_A)) |= DDI_INIT_DISPLAY_DETECTED;
        }
+
+       /* Clear host CRT status, so guest couldn't detect this host CRT. */
+       if (IS_BROADWELL(dev_priv))
+               vgpu_vreg(vgpu, PCH_ADPA) &= ~ADPA_CRT_HOTPLUG_MONITOR_MASK;
 }
 
 static void clean_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num)
@@ -301,27 +323,27 @@ void intel_gvt_check_vblank_emulation(struct intel_gvt *gvt)
 {
        struct intel_gvt_irq *irq = &gvt->irq;
        struct intel_vgpu *vgpu;
-       bool have_enabled_pipe = false;
        int pipe, id;
 
        if (WARN_ON(!mutex_is_locked(&gvt->lock)))
                return;
 
-       hrtimer_cancel(&irq->vblank_timer.timer);
-
        for_each_active_vgpu(gvt, vgpu, id) {
                for (pipe = 0; pipe < I915_MAX_PIPES; pipe++) {
-                       have_enabled_pipe =
-                               pipe_is_enabled(vgpu, pipe);
-                       if (have_enabled_pipe)
-                               break;
+                       if (pipe_is_enabled(vgpu, pipe))
+                               goto out;
                }
        }
 
-       if (have_enabled_pipe)
-               hrtimer_start(&irq->vblank_timer.timer,
-                       ktime_add_ns(ktime_get(), irq->vblank_timer.period),
-                       HRTIMER_MODE_ABS);
+       /* all the pipes are disabled */
+       hrtimer_cancel(&irq->vblank_timer.timer);
+       return;
+
+out:
+       hrtimer_start(&irq->vblank_timer.timer,
+               ktime_add_ns(ktime_get(), irq->vblank_timer.period),
+               HRTIMER_MODE_ABS);
+
 }
 
 static void emulate_vblank_on_pipe(struct intel_vgpu *vgpu, int pipe)
index 66374db..6166e34 100644 (file)
@@ -2259,6 +2259,8 @@ int intel_gvt_init_gtt(struct intel_gvt *gvt)
                ret = setup_spt_oos(gvt);
                if (ret) {
                        gvt_err("fail to initialize SPT oos\n");
+                       dma_unmap_page(dev, daddr, 4096, PCI_DMA_BIDIRECTIONAL);
+                       __free_page(gvt->gtt.scratch_ggtt_page);
                        return ret;
                }
        }
index 1414d7e..17febe8 100644 (file)
@@ -367,21 +367,24 @@ static int lcpll_ctl_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
 static int dpy_reg_mmio_read(struct intel_vgpu *vgpu, unsigned int offset,
                void *p_data, unsigned int bytes)
 {
-       *(u32 *)p_data = (1 << 17);
-       return 0;
-}
-
-static int dpy_reg_mmio_read_2(struct intel_vgpu *vgpu, unsigned int offset,
-               void *p_data, unsigned int bytes)
-{
-       *(u32 *)p_data = 3;
-       return 0;
-}
+       switch (offset) {
+       case 0xe651c:
+       case 0xe661c:
+       case 0xe671c:
+       case 0xe681c:
+               vgpu_vreg(vgpu, offset) = 1 << 17;
+               break;
+       case 0xe6c04:
+               vgpu_vreg(vgpu, offset) = 0x3;
+               break;
+       case 0xe6e1c:
+               vgpu_vreg(vgpu, offset) = 0x2f << 16;
+               break;
+       default:
+               return -EINVAL;
+       }
 
-static int dpy_reg_mmio_read_3(struct intel_vgpu *vgpu, unsigned int offset,
-               void *p_data, unsigned int bytes)
-{
-       *(u32 *)p_data = (0x2f << 16);
+       read_vreg(vgpu, offset, p_data, bytes);
        return 0;
 }
 
@@ -1925,7 +1928,7 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
        MMIO_F(_PCH_DPD_AUX_CH_CTL, 6 * 4, 0, 0, 0, D_PRE_SKL, NULL,
                dp_aux_ch_ctl_mmio_write);
 
-       MMIO_RO(PCH_ADPA, D_ALL, 0, ADPA_CRT_HOTPLUG_MONITOR_MASK, NULL, pch_adpa_mmio_write);
+       MMIO_DH(PCH_ADPA, D_PRE_SKL, NULL, pch_adpa_mmio_write);
 
        MMIO_DH(_PCH_TRANSACONF, D_ALL, NULL, transconf_mmio_write);
        MMIO_DH(_PCH_TRANSBCONF, D_ALL, NULL, transconf_mmio_write);
@@ -2011,8 +2014,8 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
        MMIO_DH(0xe661c, D_ALL, dpy_reg_mmio_read, NULL);
        MMIO_DH(0xe671c, D_ALL, dpy_reg_mmio_read, NULL);
        MMIO_DH(0xe681c, D_ALL, dpy_reg_mmio_read, NULL);
-       MMIO_DH(0xe6c04, D_ALL, dpy_reg_mmio_read_2, NULL);
-       MMIO_DH(0xe6e1c, D_ALL, dpy_reg_mmio_read_3, NULL);
+       MMIO_DH(0xe6c04, D_ALL, dpy_reg_mmio_read, NULL);
+       MMIO_DH(0xe6e1c, D_ALL, dpy_reg_mmio_read, NULL);
 
        MMIO_RO(PCH_PORT_HOTPLUG, D_ALL, 0,
                PORTA_HOTPLUG_STATUS_MASK
index 1ae0b40..fd0c85f 100644 (file)
@@ -232,16 +232,20 @@ static void gvt_cache_destroy(struct intel_vgpu *vgpu)
        struct device *dev = mdev_dev(vgpu->vdev.mdev);
        unsigned long gfn;
 
-       mutex_lock(&vgpu->vdev.cache_lock);
-       while ((node = rb_first(&vgpu->vdev.cache))) {
+       for (;;) {
+               mutex_lock(&vgpu->vdev.cache_lock);
+               node = rb_first(&vgpu->vdev.cache);
+               if (!node) {
+                       mutex_unlock(&vgpu->vdev.cache_lock);
+                       break;
+               }
                dma = rb_entry(node, struct gvt_dma, node);
                gvt_dma_unmap_iova(vgpu, dma->iova);
                gfn = dma->gfn;
-
-               vfio_unpin_pages(dev, &gfn, 1);
                __gvt_cache_remove_entry(vgpu, dma);
+               mutex_unlock(&vgpu->vdev.cache_lock);
+               vfio_unpin_pages(dev, &gfn, 1);
        }
-       mutex_unlock(&vgpu->vdev.cache_lock);
 }
 
 static struct intel_vgpu_type *intel_gvt_find_vgpu_type(struct intel_gvt *gvt,
index 488fdea..4f7057d 100644 (file)
@@ -174,15 +174,6 @@ static int shadow_context_status_change(struct notifier_block *nb,
                atomic_set(&workload->shadow_ctx_active, 1);
                break;
        case INTEL_CONTEXT_SCHEDULE_OUT:
-               /* If the status is -EINPROGRESS means this workload
-                * doesn't meet any issue during dispatching so when
-                * get the SCHEDULE_OUT set the status to be zero for
-                * good. If the status is NOT -EINPROGRESS means there
-                * is something wrong happened during dispatching and
-                * the status should not be set to zero
-                */
-               if (workload->status == -EINPROGRESS)
-                       workload->status = 0;
                atomic_set(&workload->shadow_ctx_active, 0);
                break;
        default:
@@ -427,6 +418,18 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
                wait_event(workload->shadow_ctx_status_wq,
                           !atomic_read(&workload->shadow_ctx_active));
 
+               /* If this request caused GPU hang, req->fence.error will
+                * be set to -EIO. Use -EIO to set workload status so
+                * that when this request caused GPU hang, didn't trigger
+                * context switch interrupt to guest.
+                */
+               if (likely(workload->status == -EINPROGRESS)) {
+                       if (workload->req->fence.error == -EIO)
+                               workload->status = -EIO;
+                       else
+                               workload->status = 0;
+               }
+
                i915_gem_request_put(fetch_and_zero(&workload->req));
 
                if (!workload->status && !vgpu->resetting) {
@@ -464,8 +467,6 @@ struct workload_thread_param {
        int ring_id;
 };
 
-static DEFINE_MUTEX(scheduler_mutex);
-
 static int workload_thread(void *priv)
 {
        struct workload_thread_param *p = (struct workload_thread_param *)priv;
@@ -497,8 +498,6 @@ static int workload_thread(void *priv)
                if (!workload)
                        break;
 
-               mutex_lock(&scheduler_mutex);
-
                gvt_dbg_sched("ring id %d next workload %p vgpu %d\n",
                                workload->ring_id, workload,
                                workload->vgpu->id);
@@ -537,9 +536,6 @@ complete:
                                        FORCEWAKE_ALL);
 
                intel_runtime_pm_put(gvt->dev_priv);
-
-               mutex_unlock(&scheduler_mutex);
-
        }
        return 0;
 }
index 3f44076..00d8967 100644 (file)
@@ -3087,7 +3087,7 @@ static void intel_connector_info(struct seq_file *m,
                           connector->display_info.cea_rev);
        }
 
-       if (!intel_encoder || intel_encoder->type == INTEL_OUTPUT_DP_MST)
+       if (!intel_encoder)
                return;
 
        switch (connector->connector_type) {
index ee2325b..fc307e0 100644 (file)
@@ -1132,10 +1132,12 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
         * and the registers being closely associated.
         *
         * According to chipset errata, on the 965GM, MSI interrupts may
-        * be lost or delayed, but we use them anyways to avoid
-        * stuck interrupts on some machines.
+        * be lost or delayed, and was defeatured. MSI interrupts seem to
+        * get lost on g4x as well, and interrupt delivery seems to stay
+        * properly dead afterwards. So we'll just disable them for all
+        * pre-gen5 chipsets.
         */
-       if (!IS_I945G(dev_priv) && !IS_I945GM(dev_priv)) {
+       if (INTEL_GEN(dev_priv) >= 5) {
                if (pci_enable_msi(pdev) < 0)
                        DRM_DEBUG_DRIVER("can't enable MSI");
        }
index 7dcac3b..969bac8 100644 (file)
@@ -2434,8 +2434,9 @@ rebuild_st:
                                 * again with !__GFP_NORETRY. However, we still
                                 * want to fail this allocation rather than
                                 * trigger the out-of-memory killer and for
-                                * this we want the future __GFP_MAYFAIL.
+                                * this we want __GFP_RETRY_MAYFAIL.
                                 */
+                               gfp |= __GFP_RETRY_MAYFAIL;
                        }
                } while (1);
 
index 152f16c..348b29a 100644 (file)
@@ -114,7 +114,7 @@ i915_clflush_notify(struct i915_sw_fence *fence,
        return NOTIFY_DONE;
 }
 
-void i915_gem_clflush_object(struct drm_i915_gem_object *obj,
+bool i915_gem_clflush_object(struct drm_i915_gem_object *obj,
                             unsigned int flags)
 {
        struct clflush *clflush;
@@ -128,7 +128,7 @@ void i915_gem_clflush_object(struct drm_i915_gem_object *obj,
         */
        if (!i915_gem_object_has_struct_page(obj)) {
                obj->cache_dirty = false;
-               return;
+               return false;
        }
 
        /* If the GPU is snooping the contents of the CPU cache,
@@ -140,7 +140,7 @@ void i915_gem_clflush_object(struct drm_i915_gem_object *obj,
         * tracking.
         */
        if (!(flags & I915_CLFLUSH_FORCE) && obj->cache_coherent)
-               return;
+               return false;
 
        trace_i915_gem_object_clflush(obj);
 
@@ -179,4 +179,5 @@ void i915_gem_clflush_object(struct drm_i915_gem_object *obj,
        }
 
        obj->cache_dirty = false;
+       return true;
 }
index 2455a78..f390247 100644 (file)
@@ -28,7 +28,7 @@
 struct drm_i915_private;
 struct drm_i915_gem_object;
 
-void i915_gem_clflush_object(struct drm_i915_gem_object *obj,
+bool i915_gem_clflush_object(struct drm_i915_gem_object *obj,
                             unsigned int flags);
 #define I915_CLFLUSH_FORCE BIT(0)
 #define I915_CLFLUSH_SYNC BIT(1)
index 9337446..e9503f6 100644 (file)
@@ -288,20 +288,26 @@ static int eb_create(struct i915_execbuffer *eb)
                 * direct lookup.
                 */
                do {
+                       unsigned int flags;
+
+                       /* While we can still reduce the allocation size, don't
+                        * raise a warning and allow the allocation to fail.
+                        * On the last pass though, we want to try as hard
+                        * as possible to perform the allocation and warn
+                        * if it fails.
+                        */
+                       flags = GFP_TEMPORARY;
+                       if (size > 1)
+                               flags |= __GFP_NORETRY | __GFP_NOWARN;
+
                        eb->buckets = kzalloc(sizeof(struct hlist_head) << size,
-                                             GFP_TEMPORARY |
-                                             __GFP_NORETRY |
-                                             __GFP_NOWARN);
+                                             flags);
                        if (eb->buckets)
                                break;
                } while (--size);
 
-               if (unlikely(!eb->buckets)) {
-                       eb->buckets = kzalloc(sizeof(struct hlist_head),
-                                             GFP_TEMPORARY);
-                       if (unlikely(!eb->buckets))
-                               return -ENOMEM;
-               }
+               if (unlikely(!size))
+                       return -ENOMEM;
 
                eb->lut_size = size;
        } else {
@@ -452,7 +458,7 @@ eb_add_vma(struct i915_execbuffer *eb,
                        return err;
        }
 
-       if (eb->lut_size >= 0) {
+       if (eb->lut_size > 0) {
                vma->exec_handle = entry->handle;
                hlist_add_head(&vma->exec_node,
                               &eb->buckets[hash_32(entry->handle,
@@ -554,9 +560,6 @@ static int eb_reserve_vma(const struct i915_execbuffer *eb,
                eb->args->flags |= __EXEC_HAS_RELOC;
        }
 
-       entry->flags |= __EXEC_OBJECT_HAS_PIN;
-       GEM_BUG_ON(eb_vma_misplaced(entry, vma));
-
        if (unlikely(entry->flags & EXEC_OBJECT_NEEDS_FENCE)) {
                err = i915_vma_get_fence(vma);
                if (unlikely(err)) {
@@ -568,6 +571,9 @@ static int eb_reserve_vma(const struct i915_execbuffer *eb,
                        entry->flags |= __EXEC_OBJECT_HAS_FENCE;
        }
 
+       entry->flags |= __EXEC_OBJECT_HAS_PIN;
+       GEM_BUG_ON(eb_vma_misplaced(entry, vma));
+
        return 0;
 }
 
@@ -894,7 +900,7 @@ static void eb_release_vmas(const struct i915_execbuffer *eb)
 static void eb_reset_vmas(const struct i915_execbuffer *eb)
 {
        eb_release_vmas(eb);
-       if (eb->lut_size >= 0)
+       if (eb->lut_size > 0)
                memset(eb->buckets, 0,
                       sizeof(struct hlist_head) << eb->lut_size);
 }
@@ -903,7 +909,7 @@ static void eb_destroy(const struct i915_execbuffer *eb)
 {
        GEM_BUG_ON(eb->reloc_cache.rq);
 
-       if (eb->lut_size >= 0)
+       if (eb->lut_size > 0)
                kfree(eb->buckets);
 }
 
@@ -1452,7 +1458,7 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct i915_vma *vma)
         * to read. However, if the array is not writable the user loses
         * the updated relocation values.
         */
-       if (unlikely(!access_ok(VERIFY_READ, urelocs, remain*sizeof(urelocs))))
+       if (unlikely(!access_ok(VERIFY_READ, urelocs, remain*sizeof(*urelocs))))
                return -EFAULT;
 
        do {
@@ -1769,7 +1775,7 @@ out:
                }
        }
 
-       return err ?: have_copy;
+       return err;
 }
 
 static int eb_relocate(struct i915_execbuffer *eb)
@@ -1819,7 +1825,7 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb)
        int err;
 
        for (i = 0; i < count; i++) {
-               const struct drm_i915_gem_exec_object2 *entry = &eb->exec[i];
+               struct drm_i915_gem_exec_object2 *entry = &eb->exec[i];
                struct i915_vma *vma = exec_to_vma(entry);
                struct drm_i915_gem_object *obj = vma->obj;
 
@@ -1835,12 +1841,14 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb)
                        eb->request->capture_list = capture;
                }
 
+               if (unlikely(obj->cache_dirty && !obj->cache_coherent)) {
+                       if (i915_gem_clflush_object(obj, 0))
+                               entry->flags &= ~EXEC_OBJECT_ASYNC;
+               }
+
                if (entry->flags & EXEC_OBJECT_ASYNC)
                        goto skip_flushes;
 
-               if (unlikely(obj->cache_dirty && !obj->cache_coherent))
-                       i915_gem_clflush_object(obj, 0);
-
                err = i915_gem_request_await_object
                        (eb->request, obj, entry->flags & EXEC_OBJECT_WRITE);
                if (err)
@@ -2180,8 +2188,11 @@ i915_gem_do_execbuffer(struct drm_device *dev,
                }
        }
 
-       if (eb_create(&eb))
-               return -ENOMEM;
+       err = eb_create(&eb);
+       if (err)
+               goto err_out_fence;
+
+       GEM_BUG_ON(!eb.lut_size);
 
        /*
         * Take a local wakeref for preparing to dispatch the execbuf as
@@ -2200,7 +2211,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
                goto err_unlock;
 
        err = eb_relocate(&eb);
-       if (err)
+       if (err) {
                /*
                 * If the user expects the execobject.offset and
                 * reloc.presumed_offset to be an exact match,
@@ -2209,8 +2220,8 @@ i915_gem_do_execbuffer(struct drm_device *dev,
                 * relocation.
                 */
                args->flags &= ~__EXEC_HAS_RELOC;
-       if (err < 0)
                goto err_vma;
+       }
 
        if (unlikely(eb.batch->exec_entry->flags & EXEC_OBJECT_WRITE)) {
                DRM_DEBUG("Attempting to use self-modifying batch buffer\n");
@@ -2340,6 +2351,7 @@ err_unlock:
 err_rpm:
        intel_runtime_pm_put(eb.i915);
        eb_destroy(&eb);
+err_out_fence:
        if (out_fence_fd != -1)
                put_unused_fd(out_fence_fd);
 err_in_fence:
index 38c4440..9cd22f8 100644 (file)
@@ -2067,10 +2067,6 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
                        return ret;
        }
 
-       ret = alloc_oa_buffer(dev_priv);
-       if (ret)
-               goto err_oa_buf_alloc;
-
        /* PRM - observability performance counters:
         *
         *   OACONTROL, performance counter enable, note:
@@ -2086,6 +2082,10 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
        intel_runtime_pm_get(dev_priv);
        intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
+       ret = alloc_oa_buffer(dev_priv);
+       if (ret)
+               goto err_oa_buf_alloc;
+
        ret = dev_priv->perf.oa.ops.enable_metric_set(dev_priv);
        if (ret)
                goto err_enable;
@@ -2097,11 +2097,11 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
        return 0;
 
 err_enable:
-       intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
-       intel_runtime_pm_put(dev_priv);
        free_oa_buffer(dev_priv);
 
 err_oa_buf_alloc:
+       intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+       intel_runtime_pm_put(dev_priv);
        if (stream->ctx)
                oa_put_render_ctx_id(stream);
 
index c8647cf..64cc674 100644 (file)
@@ -1802,7 +1802,7 @@ enum skl_disp_power_wells {
 #define   POST_CURSOR_2(x)             ((x) << 6)
 #define   POST_CURSOR_2_MASK           (0x3F << 6)
 #define   CURSOR_COEFF(x)              ((x) << 0)
-#define   CURSOR_COEFF_MASK            (0x3F << 6)
+#define   CURSOR_COEFF_MASK            (0x3F << 0)
 
 #define _CNL_PORT_TX_DW5_GRP_AE                0x162354
 #define _CNL_PORT_TX_DW5_GRP_B         0x1623D4
index 4a673fc..20cf272 100644 (file)
@@ -284,12 +284,12 @@ static inline void __i915_vma_pin(struct i915_vma *vma)
 
 static inline void __i915_vma_unpin(struct i915_vma *vma)
 {
-       GEM_BUG_ON(!i915_vma_is_pinned(vma));
        vma->flags--;
 }
 
 static inline void i915_vma_unpin(struct i915_vma *vma)
 {
+       GEM_BUG_ON(!i915_vma_is_pinned(vma));
        GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
        __i915_vma_unpin(vma);
 }
index b8914db..1241e58 100644 (file)
@@ -491,6 +491,14 @@ static void vlv_set_cdclk(struct drm_i915_private *dev_priv,
        int cdclk = cdclk_state->cdclk;
        u32 val, cmd;
 
+       /* There are cases where we can end up here with power domains
+        * off and a CDCLK frequency other than the minimum, like when
+        * issuing a modeset without actually changing any display after
+        * a system suspend.  So grab the PIPE-A domain, which covers
+        * the HW blocks needed for the following programming.
+        */
+       intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
+
        if (cdclk >= 320000) /* jump to highest voltage for 400MHz too */
                cmd = 2;
        else if (cdclk == 266667)
@@ -549,6 +557,8 @@ static void vlv_set_cdclk(struct drm_i915_private *dev_priv,
        intel_update_cdclk(dev_priv);
 
        vlv_program_pfi_credits(dev_priv);
+
+       intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A);
 }
 
 static void chv_set_cdclk(struct drm_i915_private *dev_priv,
@@ -568,6 +578,14 @@ static void chv_set_cdclk(struct drm_i915_private *dev_priv,
                return;
        }
 
+       /* There are cases where we can end up here with power domains
+        * off and a CDCLK frequency other than the minimum, like when
+        * issuing a modeset without actually changing any display after
+        * a system suspend.  So grab the PIPE-A domain, which covers
+        * the HW blocks needed for the following programming.
+        */
+       intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
+
        /*
         * Specs are full of misinformation, but testing on actual
         * hardware has shown that we just need to write the desired
@@ -590,6 +608,8 @@ static void chv_set_cdclk(struct drm_i915_private *dev_priv,
        intel_update_cdclk(dev_priv);
 
        vlv_program_pfi_credits(dev_priv);
+
+       intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A);
 }
 
 static int bdw_calc_cdclk(int max_pixclk)
index 80e96f1..9edeaae 100644 (file)
@@ -1896,8 +1896,8 @@ static void cnl_ddi_vswing_sequence(struct intel_encoder *encoder, u32 level)
                val = I915_READ(CNL_PORT_TX_DW4_LN(port, ln));
                val &= ~LOADGEN_SELECT;
 
-               if (((rate < 600000) && (width == 4) && (ln >= 1))  ||
-                   ((rate < 600000) && (width < 4) && ((ln == 1) || (ln == 2)))) {
+               if ((rate <= 600000 && width == 4 && ln >= 1)  ||
+                   (rate <= 600000 && width < 4 && (ln == 1 || ln == 2))) {
                        val |= LOADGEN_SELECT;
                }
                I915_WRITE(CNL_PORT_TX_DW4_LN(port, ln), val);
index dec9e58..9471c88 100644 (file)
@@ -3427,26 +3427,6 @@ static void intel_complete_page_flips(struct drm_i915_private *dev_priv)
                intel_finish_page_flip_cs(dev_priv, crtc->pipe);
 }
 
-static void intel_update_primary_planes(struct drm_device *dev)
-{
-       struct drm_crtc *crtc;
-
-       for_each_crtc(dev, crtc) {
-               struct intel_plane *plane = to_intel_plane(crtc->primary);
-               struct intel_plane_state *plane_state =
-                       to_intel_plane_state(plane->base.state);
-
-               if (plane_state->base.visible) {
-                       trace_intel_update_plane(&plane->base,
-                                                to_intel_crtc(crtc));
-
-                       plane->update_plane(plane,
-                                           to_intel_crtc_state(crtc->state),
-                                           plane_state);
-               }
-       }
-}
-
 static int
 __intel_display_resume(struct drm_device *dev,
                       struct drm_atomic_state *state,
@@ -3499,6 +3479,12 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv)
        struct drm_atomic_state *state;
        int ret;
 
+
+       /* reset doesn't touch the display */
+       if (!i915.force_reset_modeset_test &&
+           !gpu_reset_clobbers_display(dev_priv))
+               return;
+
        /*
         * Need mode_config.mutex so that we don't
         * trample ongoing ->detect() and whatnot.
@@ -3512,12 +3498,6 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv)
 
                drm_modeset_backoff(ctx);
        }
-
-       /* reset doesn't touch the display, but flips might get nuked anyway, */
-       if (!i915.force_reset_modeset_test &&
-           !gpu_reset_clobbers_display(dev_priv))
-               return;
-
        /*
         * Disabling the crtcs gracefully seems nicer. Also the
         * g33 docs say we should at least disable all the planes.
@@ -3547,6 +3527,14 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
        struct drm_atomic_state *state = dev_priv->modeset_restore_state;
        int ret;
 
+       /* reset doesn't touch the display */
+       if (!i915.force_reset_modeset_test &&
+           !gpu_reset_clobbers_display(dev_priv))
+               return;
+
+       if (!state)
+               goto unlock;
+
        /*
         * Flips in the rings will be nuked by the reset,
         * so complete all pending flips so that user space
@@ -3558,22 +3546,10 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
 
        /* reset doesn't touch the display */
        if (!gpu_reset_clobbers_display(dev_priv)) {
-               if (!state) {
-                       /*
-                        * Flips in the rings have been nuked by the reset,
-                        * so update the base address of all primary
-                        * planes to the the last fb to make sure we're
-                        * showing the correct fb after a reset.
-                        *
-                        * FIXME: Atomic will make this obsolete since we won't schedule
-                        * CS-based flips (which might get lost in gpu resets) any more.
-                        */
-                       intel_update_primary_planes(dev);
-               } else {
-                       ret = __intel_display_resume(dev, state, ctx);
+               /* for testing only restore the display */
+               ret = __intel_display_resume(dev, state, ctx);
                        if (ret)
                                DRM_ERROR("Restoring old state failed with %i\n", ret);
-               }
        } else {
                /*
                 * The display has been reset as well,
@@ -3597,8 +3573,8 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
                intel_hpd_init(dev_priv);
        }
 
-       if (state)
-               drm_atomic_state_put(state);
+       drm_atomic_state_put(state);
+unlock:
        drm_modeset_drop_locks(ctx);
        drm_modeset_acquire_fini(ctx);
        mutex_unlock(&dev->mode_config.mutex);
@@ -9117,6 +9093,13 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        u64 power_domain_mask;
        bool active;
 
+       if (INTEL_GEN(dev_priv) >= 9) {
+               intel_crtc_init_scalers(crtc, pipe_config);
+
+               pipe_config->scaler_state.scaler_id = -1;
+               pipe_config->scaler_state.scaler_users &= ~(1 << SKL_CRTC_INDEX);
+       }
+
        power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
        if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
@@ -9145,13 +9128,6 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        pipe_config->gamma_mode =
                I915_READ(GAMMA_MODE(crtc->pipe)) & GAMMA_MODE_MODE_MASK;
 
-       if (INTEL_GEN(dev_priv) >= 9) {
-               intel_crtc_init_scalers(crtc, pipe_config);
-
-               pipe_config->scaler_state.scaler_id = -1;
-               pipe_config->scaler_state.scaler_users &= ~(1 << SKL_CRTC_INDEX);
-       }
-
        power_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
        if (intel_display_power_get_if_enabled(dev_priv, power_domain)) {
                power_domain_mask |= BIT_ULL(power_domain);
@@ -9540,7 +9516,16 @@ static void i9xx_update_cursor(struct intel_plane *plane,
         * On some platforms writing CURCNTR first will also
         * cause CURPOS to be armed by the CURBASE write.
         * Without the CURCNTR write the CURPOS write would
-        * arm itself.
+        * arm itself. Thus we always start the full update
+        * with a CURCNTR write.
+        *
+        * On other platforms CURPOS always requires the
+        * CURBASE write to arm the update. Additonally
+        * a write to any of the cursor register will cancel
+        * an already armed cursor update. Thus leaving out
+        * the CURBASE write after CURPOS could lead to a
+        * cursor that doesn't appear to move, or even change
+        * shape. Thus we always write CURBASE.
         *
         * CURCNTR and CUR_FBC_CTL are always
         * armed by the CURBASE write only.
@@ -9559,6 +9544,7 @@ static void i9xx_update_cursor(struct intel_plane *plane,
                plane->cursor.cntl = cntl;
        } else {
                I915_WRITE_FW(CURPOS(pipe), pos);
+               I915_WRITE_FW(CURBASE(pipe), base);
        }
 
        POSTING_READ_FW(CURBASE(pipe));
index a4487c5..5b4de71 100644 (file)
@@ -821,9 +821,10 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine)
        I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) |
                   GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE);
 
-       /* WaDisableKillLogic:bxt,skl,kbl,cfl */
-       I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
-                  ECOCHK_DIS_TLB);
+       /* WaDisableKillLogic:bxt,skl,kbl */
+       if (!IS_COFFEELAKE(dev_priv))
+               I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
+                          ECOCHK_DIS_TLB);
 
        /* WaClearFlowControlGpgpuContextSave:skl,bxt,kbl,glk,cfl */
        /* WaDisablePartialInstShootdown:skl,bxt,kbl,glk,cfl */
@@ -894,10 +895,9 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine)
        WA_SET_BIT_MASKED(HDC_CHICKEN0,
                          HDC_FORCE_NON_COHERENT);
 
-       /* WaDisableHDCInvalidation:skl,bxt,kbl */
-       if (!IS_COFFEELAKE(dev_priv))
-               I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
-                          BDW_DISABLE_HDC_INVALIDATION);
+       /* WaDisableHDCInvalidation:skl,bxt,kbl,cfl */
+       I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
+                  BDW_DISABLE_HDC_INVALIDATION);
 
        /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt,kbl,cfl */
        if (IS_SKYLAKE(dev_priv) ||
index 03347c6..0c4cde6 100644 (file)
@@ -535,13 +535,14 @@ static void intel_fbdev_destroy(struct intel_fbdev *ifbdev)
 
        drm_fb_helper_fini(&ifbdev->helper);
 
-       if (ifbdev->fb) {
+       if (ifbdev->vma) {
                mutex_lock(&ifbdev->helper.dev->struct_mutex);
                intel_unpin_fb_vma(ifbdev->vma);
                mutex_unlock(&ifbdev->helper.dev->struct_mutex);
+       }
 
+       if (ifbdev->fb)
                drm_framebuffer_remove(&ifbdev->fb->base);
-       }
 
        kfree(ifbdev);
 }
@@ -765,7 +766,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous
        struct intel_fbdev *ifbdev = dev_priv->fbdev;
        struct fb_info *info;
 
-       if (!ifbdev || !ifbdev->fb)
+       if (!ifbdev || !ifbdev->vma)
                return;
 
        info = ifbdev->helper.fbdev;
@@ -812,7 +813,7 @@ void intel_fbdev_output_poll_changed(struct drm_device *dev)
 {
        struct intel_fbdev *ifbdev = to_i915(dev)->fbdev;
 
-       if (ifbdev && ifbdev->fb)
+       if (ifbdev && ifbdev->vma)
                drm_fb_helper_hotplug_event(&ifbdev->helper);
 }
 
@@ -824,7 +825,7 @@ void intel_fbdev_restore_mode(struct drm_device *dev)
                return;
 
        intel_fbdev_sync(ifbdev);
-       if (!ifbdev->fb)
+       if (!ifbdev->vma)
                return;
 
        if (drm_fb_helper_restore_fbdev_mode_unlocked(&ifbdev->helper) == 0)
index 52d5b82..c17ed0e 100644 (file)
@@ -45,7 +45,7 @@ static bool is_supported_device(struct drm_i915_private *dev_priv)
                return true;
        if (IS_SKYLAKE(dev_priv))
                return true;
-       if (IS_KABYLAKE(dev_priv) && INTEL_DEVID(dev_priv) == 0x591D)
+       if (IS_KABYLAKE(dev_priv))
                return true;
        return false;
 }
index 48ea0fc..40b224b 100644 (file)
@@ -4463,8 +4463,8 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
                if ((cpp * cstate->base.adjusted_mode.crtc_htotal / 512 < 1) &&
                    (plane_bytes_per_line / 512 < 1))
                        selected_result = method2;
-               else if ((ddb_allocation && ddb_allocation /
-                       fixed_16_16_to_u32_round_up(plane_blocks_per_line)) >= 1)
+               else if (ddb_allocation >=
+                        fixed_16_16_to_u32_round_up(plane_blocks_per_line))
                        selected_result = min_fixed_16_16(method1, method2);
                else if (latency >= linetime_us)
                        selected_result = min_fixed_16_16(method1, method2);
index d15cc9d..89dc25a 100644 (file)
@@ -246,9 +246,9 @@ static int igt_dmabuf_export_vmap(void *arg)
        i915_gem_object_put(obj);
 
        ptr = dma_buf_vmap(dmabuf);
-       if (IS_ERR(ptr)) {
-               err = PTR_ERR(ptr);
-               pr_err("dma_buf_vmap failed with err=%d\n", err);
+       if (!ptr) {
+               pr_err("dma_buf_vmap failed\n");
+               err = -ENOMEM;
                goto out;
        }
 
index 627e2aa..8cdec45 100644 (file)
@@ -206,7 +206,7 @@ struct drm_i915_private *mock_gem_device(void)
        mkwrite_device_info(i915)->ring_mask = BIT(0);
        i915->engine[RCS] = mock_engine(i915, "mock");
        if (!i915->engine[RCS])
-               goto err_dependencies;
+               goto err_priorities;
 
        i915->kernel_context = mock_context(i915, NULL);
        if (!i915->kernel_context)
index 4954622..6276bb8 100644 (file)
@@ -54,7 +54,7 @@ static const uint32_t ipu_plane_formats[] = {
        DRM_FORMAT_RGBA8888,
        DRM_FORMAT_RGBX8888,
        DRM_FORMAT_BGRA8888,
-       DRM_FORMAT_BGRA8888,
+       DRM_FORMAT_BGRX8888,
        DRM_FORMAT_UYVY,
        DRM_FORMAT_VYUY,
        DRM_FORMAT_YUYV,
index 636031a..8aca202 100644 (file)
@@ -237,7 +237,7 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
 
        /* port@1 is the output port */
        ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel, &imxpd->bridge);
-       if (ret)
+       if (ret && ret != -ENODEV)
                return ret;
 
        imxpd->dev = dev;
index bf2e5be..e37b55a 100644 (file)
@@ -1,4 +1,5 @@
-mediatek-drm-y := mtk_disp_ovl.o \
+mediatek-drm-y := mtk_disp_color.o \
+                 mtk_disp_ovl.o \
                  mtk_disp_rdma.o \
                  mtk_drm_crtc.o \
                  mtk_drm_ddp.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_color.c b/drivers/gpu/drm/mediatek/mtk_disp_color.c
new file mode 100644 (file)
index 0000000..ef79a6d
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2017 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#include "mtk_drm_crtc.h"
+#include "mtk_drm_ddp_comp.h"
+
+#define DISP_COLOR_CFG_MAIN                    0x0400
+#define DISP_COLOR_START_MT2701                        0x0f00
+#define DISP_COLOR_START_MT8173                        0x0c00
+#define DISP_COLOR_START(comp)                 ((comp)->data->color_offset)
+#define DISP_COLOR_WIDTH(comp)                 (DISP_COLOR_START(comp) + 0x50)
+#define DISP_COLOR_HEIGHT(comp)                        (DISP_COLOR_START(comp) + 0x54)
+
+#define COLOR_BYPASS_ALL                       BIT(7)
+#define COLOR_SEQ_SEL                          BIT(13)
+
+struct mtk_disp_color_data {
+       unsigned int color_offset;
+};
+
+/**
+ * struct mtk_disp_color - DISP_COLOR driver structure
+ * @ddp_comp - structure containing type enum and hardware resources
+ * @crtc - associated crtc to report irq events to
+ */
+struct mtk_disp_color {
+       struct mtk_ddp_comp                     ddp_comp;
+       struct drm_crtc                         *crtc;
+       const struct mtk_disp_color_data        *data;
+};
+
+static inline struct mtk_disp_color *comp_to_color(struct mtk_ddp_comp *comp)
+{
+       return container_of(comp, struct mtk_disp_color, ddp_comp);
+}
+
+static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
+                            unsigned int h, unsigned int vrefresh,
+                            unsigned int bpc)
+{
+       struct mtk_disp_color *color = comp_to_color(comp);
+
+       writel(w, comp->regs + DISP_COLOR_WIDTH(color));
+       writel(h, comp->regs + DISP_COLOR_HEIGHT(color));
+}
+
+static void mtk_color_start(struct mtk_ddp_comp *comp)
+{
+       struct mtk_disp_color *color = comp_to_color(comp);
+
+       writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL,
+              comp->regs + DISP_COLOR_CFG_MAIN);
+       writel(0x1, comp->regs + DISP_COLOR_START(color));
+}
+
+static const struct mtk_ddp_comp_funcs mtk_disp_color_funcs = {
+       .config = mtk_color_config,
+       .start = mtk_color_start,
+};
+
+static int mtk_disp_color_bind(struct device *dev, struct device *master,
+                              void *data)
+{
+       struct mtk_disp_color *priv = dev_get_drvdata(dev);
+       struct drm_device *drm_dev = data;
+       int ret;
+
+       ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp);
+       if (ret < 0) {
+               dev_err(dev, "Failed to register component %s: %d\n",
+                       dev->of_node->full_name, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void mtk_disp_color_unbind(struct device *dev, struct device *master,
+                                 void *data)
+{
+       struct mtk_disp_color *priv = dev_get_drvdata(dev);
+       struct drm_device *drm_dev = data;
+
+       mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp);
+}
+
+static const struct component_ops mtk_disp_color_component_ops = {
+       .bind   = mtk_disp_color_bind,
+       .unbind = mtk_disp_color_unbind,
+};
+
+static int mtk_disp_color_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mtk_disp_color *priv;
+       int comp_id;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_COLOR);
+       if (comp_id < 0) {
+               dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
+               return comp_id;
+       }
+
+       ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id,
+                               &mtk_disp_color_funcs);
+       if (ret) {
+               dev_err(dev, "Failed to initialize component: %d\n", ret);
+               return ret;
+       }
+
+       priv->data = of_device_get_match_data(dev);
+
+       platform_set_drvdata(pdev, priv);
+
+       ret = component_add(dev, &mtk_disp_color_component_ops);
+       if (ret)
+               dev_err(dev, "Failed to add component: %d\n", ret);
+
+       return ret;
+}
+
+static int mtk_disp_color_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &mtk_disp_color_component_ops);
+
+       return 0;
+}
+
+static const struct mtk_disp_color_data mt2701_color_driver_data = {
+       .color_offset = DISP_COLOR_START_MT2701,
+};
+
+static const struct mtk_disp_color_data mt8173_color_driver_data = {
+       .color_offset = DISP_COLOR_START_MT8173,
+};
+
+static const struct of_device_id mtk_disp_color_driver_dt_match[] = {
+       { .compatible = "mediatek,mt2701-disp-color",
+         .data = &mt2701_color_driver_data},
+       { .compatible = "mediatek,mt8173-disp-color",
+         .data = &mt8173_color_driver_data},
+       {},
+};
+MODULE_DEVICE_TABLE(of, mtk_disp_color_driver_dt_match);
+
+struct platform_driver mtk_disp_color_driver = {
+       .probe          = mtk_disp_color_probe,
+       .remove         = mtk_disp_color_remove,
+       .driver         = {
+               .name   = "mediatek-disp-color",
+               .owner  = THIS_MODULE,
+               .of_match_table = mtk_disp_color_driver_dt_match,
+       },
+};
index a14d7d6..35bc5ba 100644 (file)
 #define        OVL_RDMA_MEM_GMC        0x40402020
 
 #define OVL_CON_BYTE_SWAP      BIT(24)
+#define OVL_CON_MTX_YUV_TO_RGB (6 << 16)
 #define OVL_CON_CLRFMT_RGB     (1 << 12)
 #define OVL_CON_CLRFMT_RGBA8888        (2 << 12)
 #define OVL_CON_CLRFMT_ARGB8888        (3 << 12)
+#define OVL_CON_CLRFMT_UYVY    (4 << 12)
+#define OVL_CON_CLRFMT_YUYV    (5 << 12)
 #define OVL_CON_CLRFMT_RGB565(ovl)     ((ovl)->data->fmt_rgb565_is_0 ? \
                                        0 : OVL_CON_CLRFMT_RGB)
 #define OVL_CON_CLRFMT_RGB888(ovl)     ((ovl)->data->fmt_rgb565_is_0 ? \
@@ -176,6 +179,10 @@ static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
        case DRM_FORMAT_XBGR8888:
        case DRM_FORMAT_ABGR8888:
                return OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP;
+       case DRM_FORMAT_UYVY:
+               return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB;
+       case DRM_FORMAT_YUYV:
+               return OVL_CON_CLRFMT_YUYV | OVL_CON_MTX_YUV_TO_RGB;
        }
 }
 
index 6582e1f..cb32c93 100644 (file)
@@ -559,6 +559,8 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
        mtk_crtc->ddp_comp = devm_kmalloc_array(dev, mtk_crtc->ddp_comp_nr,
                                                sizeof(*mtk_crtc->ddp_comp),
                                                GFP_KERNEL);
+       if (!mtk_crtc->ddp_comp)
+               return -ENOMEM;
 
        mtk_crtc->mutex = mtk_disp_mutex_get(priv->mutex_dev, pipe);
        if (IS_ERR(mtk_crtc->mutex)) {
index 8b52416..07d7ea2 100644 (file)
 
 #define DISP_REG_UFO_START                     0x0000
 
-#define DISP_COLOR_CFG_MAIN                    0x0400
-#define DISP_COLOR_START_MT2701                        0x0f00
-#define DISP_COLOR_START_MT8173                        0x0c00
-#define DISP_COLOR_START(comp)                 ((comp)->data->color_offset)
-#define DISP_COLOR_WIDTH(comp)                 (DISP_COLOR_START(comp) + 0x50)
-#define DISP_COLOR_HEIGHT(comp)                        (DISP_COLOR_START(comp) + 0x54)
-
 #define DISP_AAL_EN                            0x0000
 #define DISP_AAL_SIZE                          0x0030
 
@@ -55,9 +48,6 @@
 
 #define LUT_10BIT_MASK                         0x03ff
 
-#define COLOR_BYPASS_ALL                       BIT(7)
-#define COLOR_SEQ_SEL                          BIT(13)
-
 #define OD_RELAYMODE                           BIT(0)
 
 #define UFO_BYPASS                             BIT(2)
 #define DITHER_ADD_LSHIFT_G(x)                 (((x) & 0x7) << 4)
 #define DITHER_ADD_RSHIFT_G(x)                 (((x) & 0x7) << 0)
 
-struct mtk_disp_color_data {
-       unsigned int color_offset;
-};
-
-struct mtk_disp_color {
-       struct mtk_ddp_comp                     ddp_comp;
-       const struct mtk_disp_color_data        *data;
-};
-
-static inline struct mtk_disp_color *comp_to_color(struct mtk_ddp_comp *comp)
-{
-       return container_of(comp, struct mtk_disp_color, ddp_comp);
-}
-
 void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc,
                    unsigned int CFG)
 {
@@ -119,25 +95,6 @@ void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc,
        }
 }
 
-static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
-                            unsigned int h, unsigned int vrefresh,
-                            unsigned int bpc)
-{
-       struct mtk_disp_color *color = comp_to_color(comp);
-
-       writel(w, comp->regs + DISP_COLOR_WIDTH(color));
-       writel(h, comp->regs + DISP_COLOR_HEIGHT(color));
-}
-
-static void mtk_color_start(struct mtk_ddp_comp *comp)
-{
-       struct mtk_disp_color *color = comp_to_color(comp);
-
-       writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL,
-              comp->regs + DISP_COLOR_CFG_MAIN);
-       writel(0x1, comp->regs + DISP_COLOR_START(color));
-}
-
 static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
                          unsigned int h, unsigned int vrefresh,
                          unsigned int bpc)
@@ -229,11 +186,6 @@ static const struct mtk_ddp_comp_funcs ddp_gamma = {
        .stop = mtk_gamma_stop,
 };
 
-static const struct mtk_ddp_comp_funcs ddp_color = {
-       .config = mtk_color_config,
-       .start = mtk_color_start,
-};
-
 static const struct mtk_ddp_comp_funcs ddp_od = {
        .config = mtk_od_config,
        .start = mtk_od_start,
@@ -268,8 +220,8 @@ struct mtk_ddp_comp_match {
 static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
        [DDP_COMPONENT_AAL]     = { MTK_DISP_AAL,       0, &ddp_aal },
        [DDP_COMPONENT_BLS]     = { MTK_DISP_BLS,       0, NULL },
-       [DDP_COMPONENT_COLOR0]  = { MTK_DISP_COLOR,     0, &ddp_color },
-       [DDP_COMPONENT_COLOR1]  = { MTK_DISP_COLOR,     1, &ddp_color },
+       [DDP_COMPONENT_COLOR0]  = { MTK_DISP_COLOR,     0, NULL },
+       [DDP_COMPONENT_COLOR1]  = { MTK_DISP_COLOR,     1, NULL },
        [DDP_COMPONENT_DPI0]    = { MTK_DPI,            0, NULL },
        [DDP_COMPONENT_DSI0]    = { MTK_DSI,            0, NULL },
        [DDP_COMPONENT_DSI1]    = { MTK_DSI,            1, NULL },
@@ -286,22 +238,6 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
        [DDP_COMPONENT_WDMA1]   = { MTK_DISP_WDMA,      1, NULL },
 };
 
-static const struct mtk_disp_color_data mt2701_color_driver_data = {
-       .color_offset = DISP_COLOR_START_MT2701,
-};
-
-static const struct mtk_disp_color_data mt8173_color_driver_data = {
-       .color_offset = DISP_COLOR_START_MT8173,
-};
-
-static const struct of_device_id mtk_disp_color_driver_dt_match[] = {
-       { .compatible = "mediatek,mt2701-disp-color",
-         .data = &mt2701_color_driver_data},
-       { .compatible = "mediatek,mt8173-disp-color",
-         .data = &mt8173_color_driver_data},
-       {},
-};
-
 int mtk_ddp_comp_get_id(struct device_node *node,
                        enum mtk_ddp_comp_type comp_type)
 {
@@ -324,23 +260,11 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
        enum mtk_ddp_comp_type type;
        struct device_node *larb_node;
        struct platform_device *larb_pdev;
-       const struct of_device_id *match;
-       struct mtk_disp_color *color;
 
        if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX)
                return -EINVAL;
 
        type = mtk_ddp_matches[comp_id].type;
-       if (type == MTK_DISP_COLOR) {
-               devm_kfree(dev, comp);
-               color = devm_kzalloc(dev, sizeof(*color), GFP_KERNEL);
-               if (!color)
-                       return -ENOMEM;
-
-               match = of_match_node(mtk_disp_color_driver_dt_match, node);
-               color->data = match->data;
-               comp = &color->ddp_comp;
-       }
 
        comp->id = comp_id;
        comp->funcs = funcs ?: mtk_ddp_matches[comp_id].funcs;
index f6c8ec4..41d2cff 100644 (file)
@@ -439,11 +439,12 @@ static int mtk_drm_probe(struct platform_device *pdev)
                private->comp_node[comp_id] = of_node_get(node);
 
                /*
-                * Currently only the OVL, RDMA, DSI, and DPI blocks have
+                * Currently only the COLOR, OVL, RDMA, DSI, and DPI blocks have
                 * separate component platform drivers and initialize their own
                 * DDP component structure. The others are initialized here.
                 */
-               if (comp_type == MTK_DISP_OVL ||
+               if (comp_type == MTK_DISP_COLOR ||
+                   comp_type == MTK_DISP_OVL ||
                    comp_type == MTK_DISP_RDMA ||
                    comp_type == MTK_DSI ||
                    comp_type == MTK_DPI) {
@@ -566,6 +567,7 @@ static struct platform_driver mtk_drm_platform_driver = {
 
 static struct platform_driver * const mtk_drm_drivers[] = {
        &mtk_ddp_driver,
+       &mtk_disp_color_driver,
        &mtk_disp_ovl_driver,
        &mtk_disp_rdma_driver,
        &mtk_dpi_driver,
@@ -576,33 +578,14 @@ static struct platform_driver * const mtk_drm_drivers[] = {
 
 static int __init mtk_drm_init(void)
 {
-       int ret;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(mtk_drm_drivers); i++) {
-               ret = platform_driver_register(mtk_drm_drivers[i]);
-               if (ret < 0) {
-                       pr_err("Failed to register %s driver: %d\n",
-                              mtk_drm_drivers[i]->driver.name, ret);
-                       goto err;
-               }
-       }
-
-       return 0;
-
-err:
-       while (--i >= 0)
-               platform_driver_unregister(mtk_drm_drivers[i]);
-
-       return ret;
+       return platform_register_drivers(mtk_drm_drivers,
+                                        ARRAY_SIZE(mtk_drm_drivers));
 }
 
 static void __exit mtk_drm_exit(void)
 {
-       int i;
-
-       for (i = ARRAY_SIZE(mtk_drm_drivers) - 1; i >= 0; i--)
-               platform_driver_unregister(mtk_drm_drivers[i]);
+       platform_unregister_drivers(mtk_drm_drivers,
+                                   ARRAY_SIZE(mtk_drm_drivers));
 }
 
 module_init(mtk_drm_init);
index aef8747..c3378c4 100644 (file)
@@ -59,6 +59,7 @@ struct mtk_drm_private {
 };
 
 extern struct platform_driver mtk_ddp_driver;
+extern struct platform_driver mtk_disp_color_driver;
 extern struct platform_driver mtk_disp_ovl_driver;
 extern struct platform_driver mtk_disp_rdma_driver;
 extern struct platform_driver mtk_dpi_driver;
index e405e89..1a59b9a 100644 (file)
@@ -28,6 +28,8 @@ static const u32 formats[] = {
        DRM_FORMAT_XRGB8888,
        DRM_FORMAT_ARGB8888,
        DRM_FORMAT_RGB565,
+       DRM_FORMAT_UYVY,
+       DRM_FORMAT_YUYV,
 };
 
 static void mtk_plane_reset(struct drm_plane *plane)
index b5cc6e1..97253c8 100644 (file)
@@ -930,7 +930,7 @@ static u32 mtk_dsi_recv_cnt(u8 type, u8 *read_data)
                DRM_INFO("type is 0x02, try again\n");
                break;
        default:
-               DRM_INFO("type(0x%x) cannot be non-recognite\n", type);
+               DRM_INFO("type(0x%x) not recognized\n", type);
                break;
        }
 
index 0a4ffd7..71eb4fb 100644 (file)
@@ -1778,33 +1778,14 @@ static struct platform_driver * const mtk_hdmi_drivers[] = {
 
 static int __init mtk_hdmitx_init(void)
 {
-       int ret;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(mtk_hdmi_drivers); i++) {
-               ret = platform_driver_register(mtk_hdmi_drivers[i]);
-               if (ret < 0) {
-                       pr_err("Failed to register %s driver: %d\n",
-                              mtk_hdmi_drivers[i]->driver.name, ret);
-                       goto err;
-               }
-       }
-
-       return 0;
-
-err:
-       while (--i >= 0)
-               platform_driver_unregister(mtk_hdmi_drivers[i]);
-
-       return ret;
+       return platform_register_drivers(mtk_hdmi_drivers,
+                                        ARRAY_SIZE(mtk_hdmi_drivers));
 }
 
 static void __exit mtk_hdmitx_exit(void)
 {
-       int i;
-
-       for (i = ARRAY_SIZE(mtk_hdmi_drivers) - 1; i >= 0; i--)
-               platform_driver_unregister(mtk_hdmi_drivers[i]);
+       platform_unregister_drivers(mtk_hdmi_drivers,
+                                   ARRAY_SIZE(mtk_hdmi_drivers));
 }
 
 module_init(mtk_hdmitx_init);
index 147b221..dab78c6 100644 (file)
@@ -1158,8 +1158,6 @@ nouveau_connector_aux_xfer(struct drm_dp_aux *obj, struct drm_dp_aux_msg *msg)
                return -ENODEV;
        if (WARN_ON(msg->size > 16))
                return -E2BIG;
-       if (msg->size == 0)
-               return msg->size;
 
        ret = nvkm_i2c_aux_acquire(aux);
        if (ret)
index 8d1df56..f362c9f 100644 (file)
@@ -409,7 +409,6 @@ nouveau_display_fini(struct drm_device *dev, bool suspend)
        struct nouveau_display *disp = nouveau_display(dev);
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct drm_connector *connector;
-       struct drm_crtc *crtc;
 
        if (!suspend) {
                if (drm_drv_uses_atomic_modeset(dev))
@@ -418,10 +417,6 @@ nouveau_display_fini(struct drm_device *dev, bool suspend)
                        drm_crtc_force_disable_all(dev);
        }
 
-       /* Make sure that drm and hw vblank irqs get properly disabled. */
-       drm_for_each_crtc(crtc, dev)
-               drm_crtc_vblank_off(crtc);
-
        /* disable flip completion events */
        nvif_notify_put(&drm->flip);
 
index e3132a2..2bc0dc9 100644 (file)
@@ -3674,15 +3674,24 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
        drm_mode_connector_attach_encoder(connector, encoder);
 
        if (dcbe->type == DCB_OUTPUT_DP) {
+               struct nv50_disp *disp = nv50_disp(encoder->dev);
                struct nvkm_i2c_aux *aux =
                        nvkm_i2c_aux_find(i2c, dcbe->i2c_index);
                if (aux) {
-                       nv_encoder->i2c = &nv_connector->aux.ddc;
+                       if (disp->disp->oclass < GF110_DISP) {
+                               /* HW has no support for address-only
+                                * transactions, so we're required to
+                                * use custom I2C-over-AUX code.
+                                */
+                               nv_encoder->i2c = &aux->i2c;
+                       } else {
+                               nv_encoder->i2c = &nv_connector->aux.ddc;
+                       }
                        nv_encoder->aux = aux;
                }
 
                /*TODO: Use DP Info Table to check for support. */
-               if (nv50_disp(encoder->dev)->disp->oclass >= GF110_DISP) {
+               if (disp->disp->oclass >= GF110_DISP) {
                        ret = nv50_mstm_new(nv_encoder, &nv_connector->aux, 16,
                                            nv_connector->base.base.id,
                                            &nv_encoder->dp.mstm);
@@ -3931,6 +3940,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
 
                NV_ATOMIC(drm, "%s: clr %04x (set %04x)\n", crtc->name,
                          asyh->clr.mask, asyh->set.mask);
+               if (crtc_state->active && !asyh->state.active)
+                       drm_crtc_vblank_off(crtc);
 
                if (asyh->clr.mask) {
                        nv50_head_flush_clr(head, asyh, atom->flush_disable);
@@ -4016,11 +4027,13 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
                        nv50_head_flush_set(head, asyh);
                        interlock_core = 1;
                }
-       }
 
-       for_each_crtc_in_state(state, crtc, crtc_state, i) {
-               if (crtc->state->event)
-                       drm_crtc_vblank_get(crtc);
+               if (asyh->state.active) {
+                       if (!crtc_state->active)
+                               drm_crtc_vblank_on(crtc);
+                       if (asyh->state.event)
+                               drm_crtc_vblank_get(crtc);
+               }
        }
 
        /* Update plane(s). */
@@ -4067,12 +4080,14 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
                if (crtc->state->event) {
                        unsigned long flags;
                        /* Get correct count/ts if racing with vblank irq */
-                       drm_accurate_vblank_count(crtc);
+                       if (crtc->state->active)
+                               drm_accurate_vblank_count(crtc);
                        spin_lock_irqsave(&crtc->dev->event_lock, flags);
                        drm_crtc_send_vblank_event(crtc, crtc->state->event);
                        spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
                        crtc->state->event = NULL;
-                       drm_crtc_vblank_put(crtc);
+                       if (crtc->state->active)
+                               drm_crtc_vblank_put(crtc);
                }
        }
 
index a24312f..a1e8bf4 100644 (file)
@@ -22,6 +22,7 @@ struct nvkm_ior {
                unsigned proto_evo:4;
                enum nvkm_ior_proto {
                        CRT,
+                       TV,
                        TMDS,
                        LVDS,
                        DP,
index 19c6356..6ea1946 100644 (file)
@@ -22,7 +22,7 @@ struct nv50_disp {
                u8 type[3];
        } pior;
 
-       struct nv50_disp_chan *chan[17];
+       struct nv50_disp_chan *chan[21];
 };
 
 void nv50_disp_super_1(struct nv50_disp *);
index 85aff85..be9e7f8 100644 (file)
@@ -62,6 +62,7 @@ nvkm_outp_xlat(struct nvkm_outp *outp, enum nvkm_ior_type *type)
        case 0:
                switch (outp->info.type) {
                case DCB_OUTPUT_ANALOG: *type = DAC; return  CRT;
+               case DCB_OUTPUT_TV    : *type = DAC; return   TV;
                case DCB_OUTPUT_TMDS  : *type = SOR; return TMDS;
                case DCB_OUTPUT_LVDS  : *type = SOR; return LVDS;
                case DCB_OUTPUT_DP    : *type = SOR; return   DP;
index c794b2c..6d8f212 100644 (file)
@@ -129,7 +129,7 @@ gf100_bar_init(struct nvkm_bar *base)
 
        if (bar->bar[0].mem) {
                addr = nvkm_memory_addr(bar->bar[0].mem) >> 12;
-               nvkm_wr32(device, 0x001714, 0xc0000000 | addr);
+               nvkm_wr32(device, 0x001714, 0x80000000 | addr);
        }
 
        return 0;
index 48f01e4..b768e66 100644 (file)
@@ -25,6 +25,7 @@ nvkm-y += nvkm/subdev/i2c/bit.o
 
 nvkm-y += nvkm/subdev/i2c/aux.o
 nvkm-y += nvkm/subdev/i2c/auxg94.o
+nvkm-y += nvkm/subdev/i2c/auxgf119.o
 nvkm-y += nvkm/subdev/i2c/auxgm200.o
 
 nvkm-y += nvkm/subdev/i2c/anx9805.o
index d172e42..4c1f547 100644 (file)
@@ -117,6 +117,10 @@ int
 nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *aux, bool retry, u8 type,
                  u32 addr, u8 *data, u8 *size)
 {
+       if (!*size && !aux->func->address_only) {
+               AUX_ERR(aux, "address-only transaction dropped");
+               return -ENOSYS;
+       }
        return aux->func->xfer(aux, retry, type, addr, data, size);
 }
 
index 27a4a39..9587ab4 100644 (file)
@@ -3,6 +3,7 @@
 #include "pad.h"
 
 struct nvkm_i2c_aux_func {
+       bool address_only;
        int  (*xfer)(struct nvkm_i2c_aux *, bool retry, u8 type,
                     u32 addr, u8 *data, u8 *size);
        int  (*lnk_ctl)(struct nvkm_i2c_aux *, int link_nr, int link_bw,
@@ -17,7 +18,12 @@ void nvkm_i2c_aux_del(struct nvkm_i2c_aux **);
 int nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *, bool retry, u8 type,
                      u32 addr, u8 *data, u8 *size);
 
+int g94_i2c_aux_new_(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *,
+                    int, u8, struct nvkm_i2c_aux **);
+
 int g94_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **);
+int g94_i2c_aux_xfer(struct nvkm_i2c_aux *, bool, u8, u32, u8 *, u8 *);
+int gf119_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **);
 int gm200_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **);
 
 #define AUX_MSG(b,l,f,a...) do {                                               \
index ab8cb19..c8ab1b5 100644 (file)
@@ -72,7 +72,7 @@ g94_i2c_aux_init(struct g94_i2c_aux *aux)
        return 0;
 }
 
-static int
+int
 g94_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry,
                 u8 type, u32 addr, u8 *data, u8 *size)
 {
@@ -105,9 +105,9 @@ g94_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry,
        }
 
        ctrl  = nvkm_rd32(device, 0x00e4e4 + base);
-       ctrl &= ~0x0001f0ff;
+       ctrl &= ~0x0001f1ff;
        ctrl |= type << 12;
-       ctrl |= *size - 1;
+       ctrl |= (*size ? (*size - 1) : 0x00000100);
        nvkm_wr32(device, 0x00e4e0 + base, addr);
 
        /* (maybe) retry transaction a number of times on failure... */
@@ -160,14 +160,10 @@ out:
        return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
 }
 
-static const struct nvkm_i2c_aux_func
-g94_i2c_aux_func = {
-       .xfer = g94_i2c_aux_xfer,
-};
-
 int
-g94_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive,
-               struct nvkm_i2c_aux **paux)
+g94_i2c_aux_new_(const struct nvkm_i2c_aux_func *func,
+                struct nvkm_i2c_pad *pad, int index, u8 drive,
+                struct nvkm_i2c_aux **paux)
 {
        struct g94_i2c_aux *aux;
 
@@ -175,8 +171,20 @@ g94_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive,
                return -ENOMEM;
        *paux = &aux->base;
 
-       nvkm_i2c_aux_ctor(&g94_i2c_aux_func, pad, index, &aux->base);
+       nvkm_i2c_aux_ctor(func, pad, index, &aux->base);
        aux->ch = drive;
        aux->base.intr = 1 << aux->ch;
        return 0;
 }
+
+static const struct nvkm_i2c_aux_func
+g94_i2c_aux = {
+       .xfer = g94_i2c_aux_xfer,
+};
+
+int
+g94_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive,
+               struct nvkm_i2c_aux **paux)
+{
+       return g94_i2c_aux_new_(&g94_i2c_aux, pad, index, drive, paux);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgf119.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgf119.c
new file mode 100644 (file)
index 0000000..dab40cd
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "aux.h"
+
+static const struct nvkm_i2c_aux_func
+gf119_i2c_aux = {
+       .address_only = true,
+       .xfer = g94_i2c_aux_xfer,
+};
+
+int
+gf119_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive,
+                 struct nvkm_i2c_aux **paux)
+{
+       return g94_i2c_aux_new_(&gf119_i2c_aux, pad, index, drive, paux);
+}
index ee091fa..7ef6089 100644 (file)
@@ -105,9 +105,9 @@ gm200_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry,
        }
 
        ctrl  = nvkm_rd32(device, 0x00d954 + base);
-       ctrl &= ~0x0001f0ff;
+       ctrl &= ~0x0001f1ff;
        ctrl |= type << 12;
-       ctrl |= *size - 1;
+       ctrl |= (*size ? (*size - 1) : 0x00000100);
        nvkm_wr32(device, 0x00d950 + base, addr);
 
        /* (maybe) retry transaction a number of times on failure... */
@@ -162,6 +162,7 @@ out:
 
 static const struct nvkm_i2c_aux_func
 gm200_i2c_aux_func = {
+       .address_only = true,
        .xfer = gm200_i2c_aux_xfer,
 };
 
index d53212f..3bc4d03 100644 (file)
@@ -28,7 +28,7 @@
 static const struct nvkm_i2c_pad_func
 gf119_i2c_pad_s_func = {
        .bus_new_4 = gf119_i2c_bus_new,
-       .aux_new_6 = g94_i2c_aux_new,
+       .aux_new_6 = gf119_i2c_aux_new,
        .mode = g94_i2c_pad_mode,
 };
 
@@ -41,7 +41,7 @@ gf119_i2c_pad_s_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad)
 static const struct nvkm_i2c_pad_func
 gf119_i2c_pad_x_func = {
        .bus_new_4 = gf119_i2c_bus_new,
-       .aux_new_6 = g94_i2c_aux_new,
+       .aux_new_6 = gf119_i2c_aux_new,
 };
 
 int
index fa4f8f0..e67ed38 100644 (file)
@@ -31,6 +31,7 @@
 #include "radeon_asic.h"
 #include "atom.h"
 #include <linux/backlight.h>
+#include <linux/dmi.h>
 
 extern int atom_debug;
 
@@ -2184,9 +2185,17 @@ int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx)
                goto assigned;
        }
 
-       /* on DCE32 and encoder can driver any block so just crtc id */
+       /*
+        * On DCE32 any encoder can drive any block so usually just use crtc id,
+        * but Apple thinks different at least on iMac10,1, so there use linkb,
+        * otherwise the internal eDP panel will stay dark.
+        */
        if (ASIC_IS_DCE32(rdev)) {
-               enc_idx = radeon_crtc->crtc_id;
+               if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1"))
+                       enc_idx = (dig->linkb) ? 1 : 0;
+               else
+                       enc_idx = radeon_crtc->crtc_id;
+
                goto assigned;
        }
 
index 699fe7f..a2ab6dc 100644 (file)
@@ -184,7 +184,6 @@ void radeon_kfd_device_init(struct radeon_device *rdev)
        if (rdev->kfd) {
                struct kgd2kfd_shared_resources gpu_resources = {
                        .compute_vmid_bitmap = 0xFF00,
-                       .num_mec = 1,
                        .num_pipe_per_mec = 4,
                        .num_queue_per_pipe = 8
                };
index 50c41c0..dcc539b 100644 (file)
@@ -5,6 +5,10 @@ config DRM_ROCKCHIP
        select DRM_KMS_HELPER
        select DRM_PANEL
        select VIDEOMODE_HELPERS
+       select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
+       select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
+       select DRM_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
+       select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC
        help
          Choose this option if you have a Rockchip soc chipset.
          This driver provides kernel mode setting and buffer
@@ -12,10 +16,10 @@ config DRM_ROCKCHIP
          2D or 3D acceleration; acceleration is performed by other
          IP found on the SoC.
 
+if DRM_ROCKCHIP
+
 config ROCKCHIP_ANALOGIX_DP
        bool "Rockchip specific extensions for Analogix DP driver"
-       depends on DRM_ROCKCHIP
-       select DRM_ANALOGIX_DP
        help
          This selects support for Rockchip SoC specific extensions
          for the Analogix Core DP driver. If you want to enable DP
@@ -23,9 +27,7 @@ config ROCKCHIP_ANALOGIX_DP
 
 config ROCKCHIP_CDN_DP
         bool "Rockchip cdn DP"
-        depends on DRM_ROCKCHIP
-       depends on EXTCON
-       select SND_SOC_HDMI_CODEC if SND_SOC
+       depends on EXTCON=y || (EXTCON=m && DRM_ROCKCHIP=m)
         help
          This selects support for Rockchip SoC specific extensions
          for the cdn DP driver. If you want to enable Dp on
@@ -34,8 +36,6 @@ config ROCKCHIP_CDN_DP
 
 config ROCKCHIP_DW_HDMI
         bool "Rockchip specific extensions for Synopsys DW HDMI"
-        depends on DRM_ROCKCHIP
-        select DRM_DW_HDMI
         help
          This selects support for Rockchip SoC specific extensions
          for the Synopsys DesignWare HDMI driver. If you want to
@@ -44,8 +44,6 @@ config ROCKCHIP_DW_HDMI
 
 config ROCKCHIP_DW_MIPI_DSI
        bool "Rockchip specific extensions for Synopsys DW MIPI DSI"
-       depends on DRM_ROCKCHIP
-       select DRM_MIPI_DSI
        help
         This selects support for Rockchip SoC specific extensions
         for the Synopsys DesignWare HDMI driver. If you want to
@@ -54,8 +52,9 @@ config ROCKCHIP_DW_MIPI_DSI
 
 config ROCKCHIP_INNO_HDMI
        bool "Rockchip specific extensions for Innosilicon HDMI"
-       depends on DRM_ROCKCHIP
        help
          This selects support for Rockchip SoC specific extensions
          for the Innosilicon HDMI driver. If you want to enable
          HDMI on RK3036 based SoC, you should select this option.
+
+endif
index 14fa1f8..9b0b058 100644 (file)
@@ -1195,7 +1195,7 @@ static int cdn_dp_probe(struct platform_device *pdev)
                        continue;
 
                port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
-               if (!dp)
+               if (!port)
                        return -ENOMEM;
 
                port->extcon = extcon;
index 47905fa..c7e96b8 100644 (file)
@@ -45,13 +45,13 @@ struct rockchip_crtc_state {
  *
  * @crtc: array of enabled CRTCs, used to map from "pipe" to drm_crtc.
  * @num_pipe: number of pipes for this device.
+ * @mm_lock: protect drm_mm on multi-threads.
  */
 struct rockchip_drm_private {
        struct drm_fb_helper fbdev_helper;
        struct drm_gem_object *fbdev_bo;
        struct drm_atomic_state *state;
        struct iommu_domain *domain;
-       /* protect drm_mm on multi-threads */
        struct mutex mm_lock;
        struct drm_mm mm;
        struct list_head psr_list;
index df9e570..b74ac71 100644 (file)
@@ -29,12 +29,11 @@ static int rockchip_gem_iommu_map(struct rockchip_gem_object *rk_obj)
        ssize_t ret;
 
        mutex_lock(&private->mm_lock);
-
        ret = drm_mm_insert_node_generic(&private->mm, &rk_obj->mm,
                                         rk_obj->base.size, PAGE_SIZE,
                                         0, 0);
-
        mutex_unlock(&private->mm_lock);
+
        if (ret < 0) {
                DRM_ERROR("out of I/O virtual memory: %zd\n", ret);
                return ret;
@@ -56,7 +55,9 @@ static int rockchip_gem_iommu_map(struct rockchip_gem_object *rk_obj)
        return 0;
 
 err_remove_node:
+       mutex_lock(&private->mm_lock);
        drm_mm_remove_node(&rk_obj->mm);
+       mutex_unlock(&private->mm_lock);
 
        return ret;
 }
index 403bbd5..a12cc7e 100644 (file)
@@ -520,6 +520,34 @@ static void vc4_crtc_disable(struct drm_crtc *crtc)
                     SCALER_DISPSTATX_EMPTY);
 }
 
+static void vc4_crtc_update_dlist(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct vc4_dev *vc4 = to_vc4_dev(dev);
+       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+       struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
+
+       if (crtc->state->event) {
+               unsigned long flags;
+
+               crtc->state->event->pipe = drm_crtc_index(crtc);
+
+               WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+               spin_lock_irqsave(&dev->event_lock, flags);
+               vc4_crtc->event = crtc->state->event;
+               crtc->state->event = NULL;
+
+               HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
+                         vc4_state->mm.start);
+
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+       } else {
+               HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
+                         vc4_state->mm.start);
+       }
+}
+
 static void vc4_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -530,6 +558,12 @@ static void vc4_crtc_enable(struct drm_crtc *crtc)
 
        require_hvs_enabled(dev);
 
+       /* Enable vblank irq handling before crtc is started otherwise
+        * drm_crtc_get_vblank() fails in vc4_crtc_update_dlist().
+        */
+       drm_crtc_vblank_on(crtc);
+       vc4_crtc_update_dlist(crtc);
+
        /* Turn on the scaler, which will wait for vstart to start
         * compositing.
         */
@@ -541,9 +575,6 @@ static void vc4_crtc_enable(struct drm_crtc *crtc)
        /* Turn on the pixel valve, which will emit the vstart signal. */
        CRTC_WRITE(PV_V_CONTROL,
                   CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);
-
-       /* Enable vblank irq handling after crtc is started. */
-       drm_crtc_vblank_on(crtc);
 }
 
 static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -598,7 +629,6 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
        struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
        struct drm_plane *plane;
        bool debug_dump_regs = false;
@@ -620,25 +650,15 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
 
        WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size);
 
-       if (crtc->state->event) {
-               unsigned long flags;
-
-               crtc->state->event->pipe = drm_crtc_index(crtc);
-
-               WARN_ON(drm_crtc_vblank_get(crtc) != 0);
-
-               spin_lock_irqsave(&dev->event_lock, flags);
-               vc4_crtc->event = crtc->state->event;
-               crtc->state->event = NULL;
-
-               HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
-                         vc4_state->mm.start);
-
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-       } else {
-               HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
-                         vc4_state->mm.start);
-       }
+       /* Only update DISPLIST if the CRTC was already running and is not
+        * being disabled.
+        * vc4_crtc_enable() takes care of updating the dlist just after
+        * re-enabling VBLANK interrupts and before enabling the engine.
+        * If the CRTC is being disabled, there's no point in updating this
+        * information.
+        */
+       if (crtc->state->active && old_state->active)
+               vc4_crtc_update_dlist(crtc);
 
        if (debug_dump_regs) {
                DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc));
index 35bf781..c705632 100644 (file)
 #include <drm/ttm/ttm_placement.h>
 #include <drm/ttm/ttm_page_alloc.h>
 
-static struct ttm_place vram_placement_flags = {
+static const struct ttm_place vram_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
        .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED
 };
 
-static struct ttm_place vram_ne_placement_flags = {
+static const struct ttm_place vram_ne_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
        .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
 };
 
-static struct ttm_place sys_placement_flags = {
+static const struct ttm_place sys_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
        .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED
 };
 
-static struct ttm_place sys_ne_placement_flags = {
+static const struct ttm_place sys_ne_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
        .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
 };
 
-static struct ttm_place gmr_placement_flags = {
+static const struct ttm_place gmr_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
        .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
 };
 
-static struct ttm_place gmr_ne_placement_flags = {
+static const struct ttm_place gmr_ne_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
        .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
 };
 
-static struct ttm_place mob_placement_flags = {
+static const struct ttm_place mob_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
        .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED
 };
 
-static struct ttm_place mob_ne_placement_flags = {
+static const struct ttm_place mob_ne_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
        .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
@@ -85,7 +85,7 @@ struct ttm_placement vmw_vram_placement = {
        .busy_placement = &vram_placement_flags
 };
 
-static struct ttm_place vram_gmr_placement_flags[] = {
+static const struct ttm_place vram_gmr_placement_flags[] = {
        {
                .fpfn = 0,
                .lpfn = 0,
@@ -97,7 +97,7 @@ static struct ttm_place vram_gmr_placement_flags[] = {
        }
 };
 
-static struct ttm_place gmr_vram_placement_flags[] = {
+static const struct ttm_place gmr_vram_placement_flags[] = {
        {
                .fpfn = 0,
                .lpfn = 0,
@@ -116,7 +116,7 @@ struct ttm_placement vmw_vram_gmr_placement = {
        .busy_placement = &gmr_placement_flags
 };
 
-static struct ttm_place vram_gmr_ne_placement_flags[] = {
+static const struct ttm_place vram_gmr_ne_placement_flags[] = {
        {
                .fpfn = 0,
                .lpfn = 0,
@@ -165,7 +165,7 @@ struct ttm_placement vmw_sys_ne_placement = {
        .busy_placement = &sys_ne_placement_flags
 };
 
-static struct ttm_place evictable_placement_flags[] = {
+static const struct ttm_place evictable_placement_flags[] = {
        {
                .fpfn = 0,
                .lpfn = 0,
index 99a7f4a..8617879 100644 (file)
@@ -779,8 +779,8 @@ static int vmw_cmdbuf_space_pool(struct vmw_cmdbuf_man *man,
        if (ret)
                return ret;
 
-       header->cb_header = dma_pool_alloc(man->headers, GFP_KERNEL,
-                                          &header->handle);
+       header->cb_header = dma_pool_zalloc(man->headers, GFP_KERNEL,
+                                           &header->handle);
        if (!header->cb_header) {
                ret = -ENOMEM;
                goto out_no_cb_header;
@@ -790,7 +790,6 @@ static int vmw_cmdbuf_space_pool(struct vmw_cmdbuf_man *man,
        cb_hdr = header->cb_header;
        offset = header->node.start << PAGE_SHIFT;
        header->cmd = man->map + offset;
-       memset(cb_hdr, 0, sizeof(*cb_hdr));
        if (man->using_mob) {
                cb_hdr->flags = SVGA_CB_FLAG_MOB;
                cb_hdr->ptr.mob.mobid = man->cmd_space->mem.start;
@@ -827,8 +826,8 @@ static int vmw_cmdbuf_space_inline(struct vmw_cmdbuf_man *man,
        if (WARN_ON_ONCE(size > VMW_CMDBUF_INLINE_SIZE))
                return -ENOMEM;
 
-       dheader = dma_pool_alloc(man->dheaders, GFP_KERNEL,
-                                &header->handle);
+       dheader = dma_pool_zalloc(man->dheaders, GFP_KERNEL,
+                                 &header->handle);
        if (!dheader)
                return -ENOMEM;
 
@@ -837,7 +836,6 @@ static int vmw_cmdbuf_space_inline(struct vmw_cmdbuf_man *man,
        cb_hdr = &dheader->cb_header;
        header->cb_header = cb_hdr;
        header->cmd = dheader->cmd;
-       memset(dheader, 0, sizeof(*dheader));
        cb_hdr->status = SVGA_CB_STATUS_NONE;
        cb_hdr->flags = SVGA_CB_FLAG_NONE;
        cb_hdr->ptr.pa = (u64)header->handle +
index 1f013d4..36c7b6c 100644 (file)
@@ -205,7 +205,7 @@ int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
        int ret;
 
        cres = kzalloc(sizeof(*cres), GFP_KERNEL);
-       if (unlikely(cres == NULL))
+       if (unlikely(!cres))
                return -ENOMEM;
 
        cres->hash.key = user_key | (res_type << 24);
@@ -291,7 +291,7 @@ vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
        int ret;
 
        man = kzalloc(sizeof(*man), GFP_KERNEL);
-       if (man == NULL)
+       if (!man)
                return ERR_PTR(-ENOMEM);
 
        man->dev_priv = dev_priv;
index bcc6d41..4212b3e 100644 (file)
@@ -210,8 +210,8 @@ static int vmw_gb_context_init(struct vmw_private *dev_priv,
                for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) {
                        uctx->cotables[i] = vmw_cotable_alloc(dev_priv,
                                                              &uctx->res, i);
-                       if (unlikely(uctx->cotables[i] == NULL)) {
-                               ret = -ENOMEM;
+                       if (unlikely(IS_ERR(uctx->cotables[i]))) {
+                               ret = PTR_ERR(uctx->cotables[i]);
                                goto out_cotables;
                        }
                }
@@ -777,7 +777,7 @@ static int vmw_context_define(struct drm_device *dev, void *data,
        }
 
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-       if (unlikely(ctx == NULL)) {
+       if (unlikely(!ctx)) {
                ttm_mem_global_free(vmw_mem_glob(dev_priv),
                                    vmw_user_context_size);
                ret = -ENOMEM;
index 6c026d7..d87861b 100644 (file)
@@ -584,7 +584,7 @@ struct vmw_resource *vmw_cotable_alloc(struct vmw_private *dev_priv,
                return ERR_PTR(ret);
 
        vcotbl = kzalloc(sizeof(*vcotbl), GFP_KERNEL);
-       if (unlikely(vcotbl == NULL)) {
+       if (unlikely(!vcotbl)) {
                ret = -ENOMEM;
                goto out_no_alloc;
        }
index 4a64155..4436d53 100644 (file)
@@ -227,7 +227,7 @@ static const struct drm_ioctl_desc vmw_ioctls[] = {
                      DRM_AUTH | DRM_RENDER_ALLOW),
 };
 
-static struct pci_device_id vmw_pci_id_list[] = {
+static const struct pci_device_id vmw_pci_id_list[] = {
        {0x15ad, 0x0405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VMWGFX_CHIP_SVGAII},
        {0, 0, 0}
 };
@@ -630,7 +630,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        char host_log[100] = {0};
 
        dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
-       if (unlikely(dev_priv == NULL)) {
+       if (unlikely(!dev_priv)) {
                DRM_ERROR("Failed allocating a device private struct.\n");
                return -ENOMEM;
        }
@@ -1035,7 +1035,7 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv)
        int ret = -ENOMEM;
 
        vmw_fp = kzalloc(sizeof(*vmw_fp), GFP_KERNEL);
-       if (unlikely(vmw_fp == NULL))
+       if (unlikely(!vmw_fp))
                return ret;
 
        vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev, 10);
@@ -1196,7 +1196,7 @@ static int vmw_master_create(struct drm_device *dev,
        struct vmw_master *vmaster;
 
        vmaster = kzalloc(sizeof(*vmaster), GFP_KERNEL);
-       if (unlikely(vmaster == NULL))
+       if (unlikely(!vmaster))
                return -ENOMEM;
 
        vmw_master_init(vmaster);
index c7b53d9..2cfb3c9 100644 (file)
@@ -264,7 +264,7 @@ static int vmw_resource_val_add(struct vmw_sw_context *sw_context,
        }
 
        node = kzalloc(sizeof(*node), GFP_KERNEL);
-       if (unlikely(node == NULL)) {
+       if (unlikely(!node)) {
                DRM_ERROR("Failed to allocate a resource validation "
                          "entry.\n");
                return -ENOMEM;
@@ -452,7 +452,7 @@ static int vmw_resource_relocation_add(struct list_head *list,
        struct vmw_resource_relocation *rel;
 
        rel = kmalloc(sizeof(*rel), GFP_KERNEL);
-       if (unlikely(rel == NULL)) {
+       if (unlikely(!rel)) {
                DRM_ERROR("Failed to allocate a resource relocation.\n");
                return -ENOMEM;
        }
@@ -519,7 +519,7 @@ static int vmw_cmd_invalid(struct vmw_private *dev_priv,
                           struct vmw_sw_context *sw_context,
                           SVGA3dCmdHeader *header)
 {
-       return capable(CAP_SYS_ADMIN) ? : -EINVAL;
+       return -EINVAL;
 }
 
 static int vmw_cmd_ok(struct vmw_private *dev_priv,
@@ -2584,7 +2584,7 @@ static int vmw_cmd_dx_set_vertex_buffers(struct vmw_private *dev_priv,
 
 /**
  * vmw_cmd_dx_ia_set_vertex_buffers - Validate an
- * SVGA_3D_CMD_DX_IA_SET_VERTEX_BUFFERS command.
+ * SVGA_3D_CMD_DX_IA_SET_INDEX_BUFFER command.
  *
  * @dev_priv: Pointer to a device private struct.
  * @sw_context: The software context being used for this batch.
index 6b2708b..b8bc5bc 100644 (file)
@@ -284,7 +284,7 @@ struct vmw_fence_manager *vmw_fence_manager_init(struct vmw_private *dev_priv)
 {
        struct vmw_fence_manager *fman = kzalloc(sizeof(*fman), GFP_KERNEL);
 
-       if (unlikely(fman == NULL))
+       if (unlikely(!fman))
                return NULL;
 
        fman->dev_priv = dev_priv;
@@ -541,7 +541,7 @@ int vmw_fence_create(struct vmw_fence_manager *fman,
        int ret;
 
        fence = kzalloc(sizeof(*fence), GFP_KERNEL);
-       if (unlikely(fence == NULL))
+       if (unlikely(!fence))
                return -ENOMEM;
 
        ret = vmw_fence_obj_init(fman, fence, seqno,
@@ -606,7 +606,7 @@ int vmw_user_fence_create(struct drm_file *file_priv,
                return ret;
 
        ufence = kzalloc(sizeof(*ufence), GFP_KERNEL);
-       if (unlikely(ufence == NULL)) {
+       if (unlikely(!ufence)) {
                ret = -ENOMEM;
                goto out_no_object;
        }
@@ -966,7 +966,7 @@ int vmw_event_fence_action_queue(struct drm_file *file_priv,
        struct vmw_fence_manager *fman = fman_from_fence(fence);
 
        eaction = kzalloc(sizeof(*eaction), GFP_KERNEL);
-       if (unlikely(eaction == NULL))
+       if (unlikely(!eaction))
                return -ENOMEM;
 
        eaction->event = event;
@@ -1002,7 +1002,7 @@ static int vmw_event_fence_action_create(struct drm_file *file_priv,
        int ret;
 
        event = kzalloc(sizeof(*event), GFP_KERNEL);
-       if (unlikely(event == NULL)) {
+       if (unlikely(!event)) {
                DRM_ERROR("Failed to allocate an event.\n");
                ret = -ENOMEM;
                goto out_no_space;
index c1900f4..d2b03d4 100644 (file)
@@ -121,7 +121,7 @@ static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
        struct vmwgfx_gmrid_man *gman =
                kzalloc(sizeof(*gman), GFP_KERNEL);
 
-       if (unlikely(gman == NULL))
+       if (unlikely(!gman))
                return -ENOMEM;
 
        spin_lock_init(&gman->lock);
index 3d94ea6..61e06f0 100644 (file)
@@ -384,6 +384,12 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
 
        hotspot_x = du->hotspot_x;
        hotspot_y = du->hotspot_y;
+
+       if (plane->fb) {
+               hotspot_x += plane->fb->hot_x;
+               hotspot_y += plane->fb->hot_y;
+       }
+
        du->cursor_surface = vps->surf;
        du->cursor_dmabuf = vps->dmabuf;
 
@@ -411,6 +417,9 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
                vmw_cursor_update_position(dev_priv, true,
                                           du->cursor_x + hotspot_x,
                                           du->cursor_y + hotspot_y);
+
+               du->core_hotspot_x = hotspot_x - du->hotspot_x;
+               du->core_hotspot_y = hotspot_y - du->hotspot_y;
        } else {
                DRM_ERROR("Failed to update cursor image\n");
        }
index 941bcfd..b17f08f 100644 (file)
@@ -320,14 +320,14 @@ int vmw_otables_setup(struct vmw_private *dev_priv)
 
        if (dev_priv->has_dx) {
                *otables = kmemdup(dx_tables, sizeof(dx_tables), GFP_KERNEL);
-               if (*otables == NULL)
+               if (!(*otables))
                        return -ENOMEM;
 
                dev_priv->otable_batch.num_otables = ARRAY_SIZE(dx_tables);
        } else {
                *otables = kmemdup(pre_dx_tables, sizeof(pre_dx_tables),
                                   GFP_KERNEL);
-               if (*otables == NULL)
+               if (!(*otables))
                        return -ENOMEM;
 
                dev_priv->otable_batch.num_otables = ARRAY_SIZE(pre_dx_tables);
@@ -407,7 +407,7 @@ struct vmw_mob *vmw_mob_create(unsigned long data_pages)
 {
        struct vmw_mob *mob = kzalloc(sizeof(*mob), GFP_KERNEL);
 
-       if (unlikely(mob == NULL))
+       if (unlikely(!mob))
                return NULL;
 
        mob->num_pages = vmw_mob_calculate_pt_pages(data_pages);
index 6063c96..9700099 100644 (file)
@@ -244,7 +244,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
 
                reply_len = ebx;
                reply     = kzalloc(reply_len + 1, GFP_KERNEL);
-               if (reply == NULL) {
+               if (!reply) {
                        DRM_ERROR("Cannot allocate memory for reply\n");
                        return -ENOMEM;
                }
@@ -340,7 +340,7 @@ int vmw_host_get_guestinfo(const char *guest_info_param,
 
        msg_len = strlen(guest_info_param) + strlen("info-get ") + 1;
        msg = kzalloc(msg_len, GFP_KERNEL);
-       if (msg == NULL) {
+       if (!msg) {
                DRM_ERROR("Cannot allocate memory to get %s", guest_info_param);
                return -ENOMEM;
        }
@@ -400,7 +400,7 @@ int vmw_host_log(const char *log)
 
        msg_len = strlen(log) + strlen("log ") + 1;
        msg = kzalloc(msg_len, GFP_KERNEL);
-       if (msg == NULL) {
+       if (!msg) {
                DRM_ERROR("Cannot allocate memory for log message\n");
                return -ENOMEM;
        }
index 7d591f6..a96f90f 100644 (file)
@@ -446,7 +446,7 @@ int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv,
        int ret;
 
        user_bo = kzalloc(sizeof(*user_bo), GFP_KERNEL);
-       if (unlikely(user_bo == NULL)) {
+       if (unlikely(!user_bo)) {
                DRM_ERROR("Failed to allocate a buffer.\n");
                return -ENOMEM;
        }
@@ -836,7 +836,7 @@ static int vmw_resource_buf_alloc(struct vmw_resource *res,
        }
 
        backup = kzalloc(sizeof(*backup), GFP_KERNEL);
-       if (unlikely(backup == NULL))
+       if (unlikely(!backup))
                return -ENOMEM;
 
        ret = vmw_dmabuf_init(res->dev_priv, backup, res->backup_size,
index 68f135c..9b832f1 100644 (file)
@@ -751,7 +751,7 @@ static int vmw_user_shader_alloc(struct vmw_private *dev_priv,
        }
 
        ushader = kzalloc(sizeof(*ushader), GFP_KERNEL);
-       if (unlikely(ushader == NULL)) {
+       if (unlikely(!ushader)) {
                ttm_mem_global_free(vmw_mem_glob(dev_priv),
                                    vmw_user_shader_size);
                ret = -ENOMEM;
@@ -821,7 +821,7 @@ static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv,
        }
 
        shader = kzalloc(sizeof(*shader), GFP_KERNEL);
-       if (unlikely(shader == NULL)) {
+       if (unlikely(!shader)) {
                ttm_mem_global_free(vmw_mem_glob(dev_priv),
                                    vmw_shader_size);
                ret = -ENOMEM;
@@ -981,7 +981,7 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv,
 
        /* Allocate and pin a DMA buffer */
        buf = kzalloc(sizeof(*buf), GFP_KERNEL);
-       if (unlikely(buf == NULL))
+       if (unlikely(!buf))
                return -ENOMEM;
 
        ret = vmw_dmabuf_init(dev_priv, buf, size, &vmw_sys_ne_placement,
index 50be1f0..5284e8d 100644 (file)
@@ -1640,8 +1640,8 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv)
                 * something arbitrarily large and we will reject any layout
                 * that doesn't fit prim_bb_mem later
                 */
-               dev->mode_config.max_width = 16384;
-               dev->mode_config.max_height = 16384;
+               dev->mode_config.max_width = 8192;
+               dev->mode_config.max_height = 8192;
        }
 
        vmw_kms_create_implicit_placement_property(dev_priv, false);
index 2c58a39..7782725 100644 (file)
@@ -186,8 +186,13 @@ static int host1x_probe(struct platform_device *pdev)
                        return -ENOMEM;
 
                err = iommu_attach_device(host->domain, &pdev->dev);
-               if (err)
+               if (err == -ENODEV) {
+                       iommu_domain_free(host->domain);
+                       host->domain = NULL;
+                       goto skip_iommu;
+               } else if (err) {
                        goto fail_free_domain;
+               }
 
                geometry = &host->domain->geometry;
 
@@ -198,6 +203,7 @@ static int host1x_probe(struct platform_device *pdev)
                host->iova_end = geometry->aperture_end;
        }
 
+skip_iommu:
        err = host1x_channel_list_init(&host->channel_list,
                                       host->info->nb_channels);
        if (err) {
index 6fd01a6..9017dcc 100644 (file)
@@ -2216,6 +2216,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 #if IS_ENABLED(CONFIG_HID_ORTEK)
        { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
 #endif
 #if IS_ENABLED(CONFIG_HID_PANTHERLORD)
index 3d911bf..c9ba4c6 100644 (file)
 #define USB_VENDOR_ID_ORTEK            0x05a4
 #define USB_DEVICE_ID_ORTEK_PKB1700    0x1700
 #define USB_DEVICE_ID_ORTEK_WKB2000    0x2000
+#define USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S   0x8003
 
 #define USB_VENDOR_ID_PLANTRONICS      0x047f
 
index 41b3946..501e16a 100644 (file)
@@ -2732,6 +2732,9 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
                                     hidpp_battery_props,
                                     sizeof(hidpp_battery_props),
                                     GFP_KERNEL);
+       if (!battery_props)
+               return -ENOMEM;
+
        num_battery_props = ARRAY_SIZE(hidpp_battery_props) - 2;
 
        if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE)
index f3e35e7..aff20f4 100644 (file)
@@ -620,16 +620,6 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        return 0;
 }
 
-static int mt_touch_input_mapped(struct hid_device *hdev, struct hid_input *hi,
-               struct hid_field *field, struct hid_usage *usage,
-               unsigned long **bit, int *max)
-{
-       if (usage->type == EV_KEY || usage->type == EV_ABS)
-               set_bit(usage->type, hi->input->evbit);
-
-       return -1;
-}
-
 static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
 {
        __s32 quirks = td->mtclass.quirks;
@@ -969,8 +959,10 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
                return 0;
 
        if (field->application == HID_DG_TOUCHSCREEN ||
-           field->application == HID_DG_TOUCHPAD)
-               return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
+           field->application == HID_DG_TOUCHPAD) {
+               /* We own these mappings, tell hid-input to ignore them */
+               return -1;
+       }
 
        /* let hid-core decide for the others */
        return 0;
index 6620f15..8783a06 100644 (file)
@@ -5,6 +5,7 @@
  *
  *    Ortek PKB-1700
  *    Ortek WKB-2000
+ *    iHome IMAC-A210S
  *    Skycable wireless presenter
  *
  *  Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com>
@@ -28,10 +29,10 @@ static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
        if (*rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) {
-               hid_info(hdev, "Fixing up logical minimum in report descriptor (Ortek)\n");
+               hid_info(hdev, "Fixing up logical maximum in report descriptor (Ortek)\n");
                rdesc[55] = 0x92;
        } else if (*rsize >= 54 && rdesc[52] == 0x25 && rdesc[53] == 0x01) {
-               hid_info(hdev, "Fixing up logical minimum in report descriptor (Skycable)\n");
+               hid_info(hdev, "Fixing up logical maximum in report descriptor (Skycable)\n");
                rdesc[53] = 0x65;
        }
        return rdesc;
@@ -40,6 +41,7 @@ static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 static const struct hid_device_id ortek_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
        { }
 };
index 76013eb..c008847 100644 (file)
@@ -680,18 +680,21 @@ static int usbhid_open(struct hid_device *hid)
        struct usbhid_device *usbhid = hid->driver_data;
        int res;
 
+       set_bit(HID_OPENED, &usbhid->iofl);
+
        if (hid->quirks & HID_QUIRK_ALWAYS_POLL)
                return 0;
 
        res = usb_autopm_get_interface(usbhid->intf);
        /* the device must be awake to reliably request remote wakeup */
-       if (res < 0)
+       if (res < 0) {
+               clear_bit(HID_OPENED, &usbhid->iofl);
                return -EIO;
+       }
 
        usbhid->intf->needs_remote_wakeup = 1;
 
        set_bit(HID_RESUME_RUNNING, &usbhid->iofl);
-       set_bit(HID_OPENED, &usbhid->iofl);
        set_bit(HID_IN_POLLING, &usbhid->iofl);
 
        res = hid_start_in(hid);
@@ -727,19 +730,20 @@ static void usbhid_close(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
 
-       if (hid->quirks & HID_QUIRK_ALWAYS_POLL)
-               return;
-
        /*
         * Make sure we don't restart data acquisition due to
         * a resumption we no longer care about by avoiding racing
         * with hid_start_in().
         */
        spin_lock_irq(&usbhid->lock);
-       clear_bit(HID_IN_POLLING, &usbhid->iofl);
        clear_bit(HID_OPENED, &usbhid->iofl);
+       if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL))
+               clear_bit(HID_IN_POLLING, &usbhid->iofl);
        spin_unlock_irq(&usbhid->lock);
 
+       if (hid->quirks & HID_QUIRK_ALWAYS_POLL)
+               return;
+
        hid_cancel_delayed_stuff(usbhid);
        usb_kill_urb(usbhid->urbin);
        usbhid->intf->needs_remote_wakeup = 0;
index e9bf0bb..e57cc40 100644 (file)
@@ -606,6 +606,8 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
                get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
 
 out:
+       /* re-enable tasklet for use on re-open */
+       tasklet_enable(&channel->callback_event);
        return ret;
 }
 
index 0af7fd3..76c34f4 100644 (file)
@@ -566,6 +566,8 @@ static int applesmc_init_smcreg_try(void)
        if (ret)
                return ret;
        s->fan_count = tmp[0];
+       if (s->fan_count > 10)
+               s->fan_count = 10;
 
        ret = applesmc_get_lower_bound(&s->temp_begin, "T");
        if (ret)
@@ -811,7 +813,8 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
        char newkey[5];
        u8 buffer[2];
 
-       sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
+       scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)],
+                 to_index(attr));
 
        ret = applesmc_read_key(newkey, buffer, 2);
        speed = ((buffer[0] << 8 | buffer[1]) >> 2);
@@ -834,7 +837,8 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
        if (kstrtoul(sysfsbuf, 10, &speed) < 0 || speed >= 0x4000)
                return -EINVAL;         /* Bigger than a 14-bit value */
 
-       sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
+       scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)],
+                 to_index(attr));
 
        buffer[0] = (speed >> 6) & 0xff;
        buffer[1] = (speed << 2) & 0xff;
@@ -903,7 +907,7 @@ static ssize_t applesmc_show_fan_position(struct device *dev,
        char newkey[5];
        u8 buffer[17];
 
-       sprintf(newkey, FAN_ID_FMT, to_index(attr));
+       scnprintf(newkey, sizeof(newkey), FAN_ID_FMT, to_index(attr));
 
        ret = applesmc_read_key(newkey, buffer, 16);
        buffer[16] = 0;
@@ -1116,7 +1120,8 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
                }
                for (i = 0; i < num; i++) {
                        node = &grp->nodes[i];
-                       sprintf(node->name, grp->format, i + 1);
+                       scnprintf(node->name, sizeof(node->name), grp->format,
+                                 i + 1);
                        node->sda.index = (grp->option << 16) | (i & 0xffff);
                        node->sda.dev_attr.show = grp->show;
                        node->sda.dev_attr.store = grp->store;
index 0e05f75..1858e3c 100644 (file)
@@ -104,19 +104,19 @@ u16 ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
 EXPORT_SYMBOL_GPL(ide_pio_cycle_time);
 
 #define ENOUGH(v, unit)                (((v) - 1) / (unit) + 1)
-#define EZ(v, unit)            ((v) ? ENOUGH(v, unit) : 0)
+#define EZ(v, unit)            ((v) ? ENOUGH((v) * 1000, unit) : 0)
 
 static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q,
                                int T, int UT)
 {
-       q->setup   = EZ(t->setup   * 1000,  T);
-       q->act8b   = EZ(t->act8b   * 1000,  T);
-       q->rec8b   = EZ(t->rec8b   * 1000,  T);
-       q->cyc8b   = EZ(t->cyc8b   * 1000,  T);
-       q->active  = EZ(t->active  * 1000,  T);
-       q->recover = EZ(t->recover * 1000,  T);
-       q->cycle   = EZ(t->cycle   * 1000,  T);
-       q->udma    = EZ(t->udma    * 1000, UT);
+       q->setup   = EZ(t->setup  T);
+       q->act8b   = EZ(t->act8b  T);
+       q->rec8b   = EZ(t->rec8b  T);
+       q->cyc8b   = EZ(t->cyc8b  T);
+       q->active  = EZ(t->active,  T);
+       q->recover = EZ(t->recover, T);
+       q->cycle   = EZ(t->cycle  T);
+       q->udma    = EZ(t->udma,    UT);
 }
 
 void ide_timing_merge(struct ide_timing *a, struct ide_timing *b,
index a6cb379..01236ce 100644 (file)
@@ -268,6 +268,7 @@ int rdma_translate_ip(const struct sockaddr *addr,
                        return ret;
 
                ret = rdma_copy_addr(dev_addr, dev, NULL);
+               dev_addr->bound_dev_if = dev->ifindex;
                if (vlan_id)
                        *vlan_id = rdma_vlan_dev_vlan_id(dev);
                dev_put(dev);
@@ -280,6 +281,7 @@ int rdma_translate_ip(const struct sockaddr *addr,
                                          &((const struct sockaddr_in6 *)addr)->sin6_addr,
                                          dev, 1)) {
                                ret = rdma_copy_addr(dev_addr, dev, NULL);
+                               dev_addr->bound_dev_if = dev->ifindex;
                                if (vlan_id)
                                        *vlan_id = rdma_vlan_dev_vlan_id(dev);
                                break;
@@ -405,10 +407,10 @@ static int addr4_resolve(struct sockaddr_in *src_in,
        fl4.saddr = src_ip;
        fl4.flowi4_oif = addr->bound_dev_if;
        rt = ip_route_output_key(addr->net, &fl4);
-       if (IS_ERR(rt)) {
-               ret = PTR_ERR(rt);
-               goto out;
-       }
+       ret = PTR_ERR_OR_ZERO(rt);
+       if (ret)
+               return ret;
+
        src_in->sin_family = AF_INET;
        src_in->sin_addr.s_addr = fl4.saddr;
 
@@ -423,8 +425,6 @@ static int addr4_resolve(struct sockaddr_in *src_in,
 
        *prt = rt;
        return 0;
-out:
-       return ret;
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
@@ -509,6 +509,11 @@ static int addr_resolve(struct sockaddr *src_in,
        struct dst_entry *dst;
        int ret;
 
+       if (!addr->net) {
+               pr_warn_ratelimited("%s: missing namespace\n", __func__);
+               return -EINVAL;
+       }
+
        if (src_in->sa_family == AF_INET) {
                struct rtable *rt = NULL;
                const struct sockaddr_in *dst_in4 =
@@ -522,8 +527,12 @@ static int addr_resolve(struct sockaddr *src_in,
                if (resolve_neigh)
                        ret = addr_resolve_neigh(&rt->dst, dst_in, addr, seq);
 
-               ndev = rt->dst.dev;
-               dev_hold(ndev);
+               if (addr->bound_dev_if) {
+                       ndev = dev_get_by_index(addr->net, addr->bound_dev_if);
+               } else {
+                       ndev = rt->dst.dev;
+                       dev_hold(ndev);
+               }
 
                ip_rt_put(rt);
        } else {
@@ -539,14 +548,27 @@ static int addr_resolve(struct sockaddr *src_in,
                if (resolve_neigh)
                        ret = addr_resolve_neigh(dst, dst_in, addr, seq);
 
-               ndev = dst->dev;
-               dev_hold(ndev);
+               if (addr->bound_dev_if) {
+                       ndev = dev_get_by_index(addr->net, addr->bound_dev_if);
+               } else {
+                       ndev = dst->dev;
+                       dev_hold(ndev);
+               }
 
                dst_release(dst);
        }
 
-       addr->bound_dev_if = ndev->ifindex;
-       addr->net = dev_net(ndev);
+       if (ndev->flags & IFF_LOOPBACK) {
+               ret = rdma_translate_ip(dst_in, addr, NULL);
+               /*
+                * Put the loopback device and get the translated
+                * device instead.
+                */
+               dev_put(ndev);
+               ndev = dev_get_by_index(addr->net, addr->bound_dev_if);
+       } else {
+               addr->bound_dev_if = ndev->ifindex;
+       }
        dev_put(ndev);
 
        return ret;
index 31bb82d..0eb3932 100644 (file)
@@ -623,22 +623,11 @@ static inline int cma_validate_port(struct ib_device *device, u8 port,
        if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port))
                return ret;
 
-       if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port)) {
+       if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port))
                ndev = dev_get_by_index(&init_net, bound_if_index);
-               if (ndev && ndev->flags & IFF_LOOPBACK) {
-                       pr_info("detected loopback device\n");
-                       dev_put(ndev);
-
-                       if (!device->get_netdev)
-                               return -EOPNOTSUPP;
-
-                       ndev = device->get_netdev(device, port);
-                       if (!ndev)
-                               return -ENODEV;
-               }
-       } else {
+       else
                gid_type = IB_GID_TYPE_IB;
-       }
+
 
        ret = ib_find_cached_gid_by_port(device, gid, gid_type, port,
                                         ndev, NULL);
@@ -1044,6 +1033,8 @@ int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
                } else
                        ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
                                                 qp_attr_mask);
+               qp_attr->port_num = id_priv->id.port_num;
+               *qp_attr_mask |= IB_QP_PORT;
        } else
                ret = -ENOSYS;
 
@@ -2569,21 +2560,6 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
                        goto err2;
                }
 
-               if (ndev->flags & IFF_LOOPBACK) {
-                       dev_put(ndev);
-                       if (!id_priv->id.device->get_netdev) {
-                               ret = -EOPNOTSUPP;
-                               goto err2;
-                       }
-
-                       ndev = id_priv->id.device->get_netdev(id_priv->id.device,
-                                                             id_priv->id.port_num);
-                       if (!ndev) {
-                               ret = -ENODEV;
-                               goto err2;
-                       }
-               }
-
                supported_gids = roce_gid_type_mask_support(id_priv->id.device,
                                                            id_priv->id.port_num);
                gid_type = cma_route_gid_type(addr->dev_addr.network,
index db958d3..94a9eef 100644 (file)
@@ -42,6 +42,8 @@
 #include <rdma/ib_cache.h>
 #include <rdma/ib_addr.h>
 
+static struct workqueue_struct *gid_cache_wq;
+
 enum gid_op_type {
        GID_DEL = 0,
        GID_ADD
@@ -560,7 +562,7 @@ static int netdevice_queue_work(struct netdev_event_work_cmd *cmds,
        }
        INIT_WORK(&ndev_work->work, netdevice_event_work_handler);
 
-       queue_work(ib_wq, &ndev_work->work);
+       queue_work(gid_cache_wq, &ndev_work->work);
 
        return NOTIFY_DONE;
 }
@@ -693,7 +695,7 @@ static int addr_event(struct notifier_block *this, unsigned long event,
        dev_hold(ndev);
        work->gid_attr.ndev   = ndev;
 
-       queue_work(ib_wq, &work->work);
+       queue_work(gid_cache_wq, &work->work);
 
        return NOTIFY_DONE;
 }
@@ -740,6 +742,10 @@ static struct notifier_block nb_inet6addr = {
 
 int __init roce_gid_mgmt_init(void)
 {
+       gid_cache_wq = alloc_ordered_workqueue("gid-cache-wq", 0);
+       if (!gid_cache_wq)
+               return -ENOMEM;
+
        register_inetaddr_notifier(&nb_inetaddr);
        if (IS_ENABLED(CONFIG_IPV6))
                register_inet6addr_notifier(&nb_inet6addr);
@@ -764,4 +770,5 @@ void __exit roce_gid_mgmt_cleanup(void)
         * ib-core is removed, all physical devices have been removed,
         * so no issue with remaining hardware contexts.
         */
+       destroy_workqueue(gid_cache_wq);
 }
index 8ba9bfb..2c98533 100644 (file)
@@ -1296,7 +1296,6 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
        struct ib_uobject               *uobj;
        struct ib_cq                    *cq;
        struct ib_ucq_object            *obj;
-       struct ib_uverbs_event_queue    *ev_queue;
        int                              ret = -EINVAL;
 
        if (copy_from_user(&cmd, buf, sizeof cmd))
@@ -1313,7 +1312,6 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
         */
        uverbs_uobject_get(uobj);
        cq      = uobj->object;
-       ev_queue = cq->cq_context;
        obj     = container_of(cq->uobject, struct ib_ucq_object, uobject);
 
        memset(&resp, 0, sizeof(resp));
@@ -1935,7 +1933,8 @@ static int modify_qp(struct ib_uverbs_file *file,
                goto out;
        }
 
-       if (!rdma_is_port_valid(qp->device, cmd->base.port_num)) {
+       if ((cmd->base.attr_mask & IB_QP_PORT) &&
+           !rdma_is_port_valid(qp->device, cmd->base.port_num)) {
                ret = -EINVAL;
                goto release_qp;
        }
@@ -2005,28 +2004,13 @@ static int modify_qp(struct ib_uverbs_file *file,
        rdma_ah_set_port_num(&attr->alt_ah_attr,
                             cmd->base.alt_dest.port_num);
 
-       if (qp->real_qp == qp) {
-               if (cmd->base.attr_mask & IB_QP_AV) {
-                       ret = ib_resolve_eth_dmac(qp->device, &attr->ah_attr);
-                       if (ret)
-                               goto release_qp;
-               }
-               ret = ib_security_modify_qp(qp,
-                                           attr,
-                                           modify_qp_mask(qp->qp_type,
-                                                          cmd->base.attr_mask),
-                                           udata);
-       } else {
-               ret = ib_security_modify_qp(qp,
-                                           attr,
-                                           modify_qp_mask(qp->qp_type,
-                                                          cmd->base.attr_mask),
-                                           NULL);
-       }
+       ret = ib_modify_qp_with_udata(qp, attr,
+                                     modify_qp_mask(qp->qp_type,
+                                                    cmd->base.attr_mask),
+                                     udata);
 
 release_qp:
        uobj_put_obj_read(qp);
-
 out:
        kfree(attr);
 
@@ -2103,7 +2087,6 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
        struct ib_uverbs_destroy_qp      cmd;
        struct ib_uverbs_destroy_qp_resp resp;
        struct ib_uobject               *uobj;
-       struct ib_qp                    *qp;
        struct ib_uqp_object            *obj;
        int                              ret = -EINVAL;
 
@@ -2117,7 +2100,6 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
        if (IS_ERR(uobj))
                return PTR_ERR(uobj);
 
-       qp  = uobj->object;
        obj = container_of(uobj, struct ib_uqp_object, uevent.uobject);
        /*
         * Make sure we don't free the memory in remove_commit as we still
@@ -3019,7 +3001,6 @@ int ib_uverbs_ex_destroy_wq(struct ib_uverbs_file *file,
 {
        struct ib_uverbs_ex_destroy_wq  cmd = {};
        struct ib_uverbs_ex_destroy_wq_resp     resp = {};
-       struct ib_wq                    *wq;
        struct ib_uobject               *uobj;
        struct ib_uwq_object            *obj;
        size_t required_cmd_sz;
@@ -3053,7 +3034,6 @@ int ib_uverbs_ex_destroy_wq(struct ib_uverbs_file *file,
        if (IS_ERR(uobj))
                return PTR_ERR(uobj);
 
-       wq = uobj->object;
        obj = container_of(uobj, struct ib_uwq_object, uevent.uobject);
        /*
         * Make sure we don't free the memory in remove_commit as we still
@@ -3743,10 +3723,8 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
        struct ib_uverbs_destroy_srq      cmd;
        struct ib_uverbs_destroy_srq_resp resp;
        struct ib_uobject                *uobj;
-       struct ib_srq                    *srq;
        struct ib_uevent_object          *obj;
        int                               ret = -EINVAL;
-       enum ib_srq_type                  srq_type;
 
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
@@ -3756,9 +3734,7 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
        if (IS_ERR(uobj))
                return PTR_ERR(uobj);
 
-       srq = uobj->object;
        obj = container_of(uobj, struct ib_uevent_object, uobject);
-       srq_type = srq->srq_type;
        /*
         * Make sure we don't free the memory in remove_commit as we still
         * needs the uobject memory to create the response.
index c973a83..fb98ed6 100644 (file)
@@ -452,6 +452,19 @@ int ib_get_gids_from_rdma_hdr(const union rdma_network_hdr *hdr,
 }
 EXPORT_SYMBOL(ib_get_gids_from_rdma_hdr);
 
+/*
+ * This function creates ah from the incoming packet.
+ * Incoming packet has dgid of the receiver node on which this code is
+ * getting executed and, sgid contains the GID of the sender.
+ *
+ * When resolving mac address of destination, the arrived dgid is used
+ * as sgid and, sgid is used as dgid because sgid contains destinations
+ * GID whom to respond to.
+ *
+ * This is why when calling rdma_addr_find_l2_eth_by_grh() function, the
+ * position of arguments dgid and sgid do not match the order of the
+ * parameters.
+ */
 int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,
                       const struct ib_wc *wc, const struct ib_grh *grh,
                       struct rdma_ah_attr *ah_attr)
@@ -507,11 +520,6 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,
                }
 
                resolved_dev = dev_get_by_index(&init_net, if_index);
-               if (resolved_dev->flags & IFF_LOOPBACK) {
-                       dev_put(resolved_dev);
-                       resolved_dev = idev;
-                       dev_hold(resolved_dev);
-               }
                rcu_read_lock();
                if (resolved_dev != idev && !rdma_is_upper_dev_rcu(idev,
                                                                   resolved_dev))
@@ -887,6 +895,7 @@ static const struct {
 } qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
        [IB_QPS_RESET] = {
                [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 },
                [IB_QPS_INIT]  = {
                        .valid = 1,
                        .req_param = {
@@ -1268,20 +1277,36 @@ out:
 }
 EXPORT_SYMBOL(ib_resolve_eth_dmac);
 
-int ib_modify_qp(struct ib_qp *qp,
-                struct ib_qp_attr *qp_attr,
-                int qp_attr_mask)
+/**
+ * ib_modify_qp_with_udata - Modifies the attributes for the specified QP.
+ * @qp: The QP to modify.
+ * @attr: On input, specifies the QP attributes to modify.  On output,
+ *   the current values of selected QP attributes are returned.
+ * @attr_mask: A bit-mask used to specify which attributes of the QP
+ *   are being modified.
+ * @udata: pointer to user's input output buffer information
+ *   are being modified.
+ * It returns 0 on success and returns appropriate error code on error.
+ */
+int ib_modify_qp_with_udata(struct ib_qp *qp, struct ib_qp_attr *attr,
+                           int attr_mask, struct ib_udata *udata)
 {
+       int ret;
 
-       if (qp_attr_mask & IB_QP_AV) {
-               int ret;
-
-               ret = ib_resolve_eth_dmac(qp->device, &qp_attr->ah_attr);
+       if (attr_mask & IB_QP_AV) {
+               ret = ib_resolve_eth_dmac(qp->device, &attr->ah_attr);
                if (ret)
                        return ret;
        }
+       return ib_security_modify_qp(qp, attr, attr_mask, udata);
+}
+EXPORT_SYMBOL(ib_modify_qp_with_udata);
 
-       return ib_security_modify_qp(qp->real_qp, qp_attr, qp_attr_mask, NULL);
+int ib_modify_qp(struct ib_qp *qp,
+                struct ib_qp_attr *qp_attr,
+                int qp_attr_mask)
+{
+       return ib_modify_qp_with_udata(qp, qp_attr, qp_attr_mask, NULL);
 }
 EXPORT_SYMBOL(ib_modify_qp);
 
index 19982a4..18f5ed0 100644 (file)
@@ -1,6 +1,7 @@
 config INFINIBAND_BNXT_RE
     tristate "Broadcom Netxtreme HCA support"
     depends on ETHERNET && NETDEVICES && PCI && INET && DCB
+    depends on MAY_USE_DEVLINK
     select NET_VENDOR_BROADCOM
     select BNXT
     ---help---
index 0877283..8552753 100644 (file)
@@ -51,6 +51,8 @@
 #define BNXT_RE_PAGE_SIZE_8M           BIT(23)
 #define BNXT_RE_PAGE_SIZE_1G           BIT(30)
 
+#define BNXT_RE_MAX_MR_SIZE            BIT(30)
+
 #define BNXT_RE_MAX_QPC_COUNT          (64 * 1024)
 #define BNXT_RE_MAX_MRW_COUNT          (64 * 1024)
 #define BNXT_RE_MAX_SRQC_COUNT         (64 * 1024)
 
 #define BNXT_RE_RQ_WQE_THRESHOLD       32
 
+/*
+ * Setting the default ack delay value to 16, which means
+ * the default timeout is approx. 260ms(4 usec * 2 ^(timeout))
+ */
+
+#define BNXT_RE_DEFAULT_ACK_DELAY      16
+
 struct bnxt_re_work {
        struct work_struct      work;
        unsigned long           event;
index c7bd683..f0e01b3 100644 (file)
@@ -145,10 +145,8 @@ int bnxt_re_query_device(struct ib_device *ibdev,
        ib_attr->fw_ver = (u64)(unsigned long)(dev_attr->fw_ver);
        bnxt_qplib_get_guid(rdev->netdev->dev_addr,
                            (u8 *)&ib_attr->sys_image_guid);
-       ib_attr->max_mr_size = ~0ull;
-       ib_attr->page_size_cap = BNXT_RE_PAGE_SIZE_4K | BNXT_RE_PAGE_SIZE_8K |
-                                BNXT_RE_PAGE_SIZE_64K | BNXT_RE_PAGE_SIZE_2M |
-                                BNXT_RE_PAGE_SIZE_8M | BNXT_RE_PAGE_SIZE_1G;
+       ib_attr->max_mr_size = BNXT_RE_MAX_MR_SIZE;
+       ib_attr->page_size_cap = BNXT_RE_PAGE_SIZE_4K;
 
        ib_attr->vendor_id = rdev->en_dev->pdev->vendor;
        ib_attr->vendor_part_id = rdev->en_dev->pdev->device;
@@ -174,9 +172,11 @@ int bnxt_re_query_device(struct ib_device *ibdev,
        ib_attr->max_mr = dev_attr->max_mr;
        ib_attr->max_pd = dev_attr->max_pd;
        ib_attr->max_qp_rd_atom = dev_attr->max_qp_rd_atom;
-       ib_attr->max_qp_init_rd_atom = dev_attr->max_qp_rd_atom;
-       ib_attr->atomic_cap = IB_ATOMIC_HCA;
-       ib_attr->masked_atomic_cap = IB_ATOMIC_HCA;
+       ib_attr->max_qp_init_rd_atom = dev_attr->max_qp_init_rd_atom;
+       if (dev_attr->is_atomic) {
+               ib_attr->atomic_cap = IB_ATOMIC_HCA;
+               ib_attr->masked_atomic_cap = IB_ATOMIC_HCA;
+       }
 
        ib_attr->max_ee_rd_atom = 0;
        ib_attr->max_res_rd_atom = 0;
@@ -201,7 +201,7 @@ int bnxt_re_query_device(struct ib_device *ibdev,
        ib_attr->max_fast_reg_page_list_len = MAX_PBL_LVL_1_PGS;
 
        ib_attr->max_pkeys = 1;
-       ib_attr->local_ca_ack_delay = 0;
+       ib_attr->local_ca_ack_delay = BNXT_RE_DEFAULT_ACK_DELAY;
        return 0;
 }
 
@@ -390,15 +390,17 @@ int bnxt_re_del_gid(struct ib_device *ibdev, u8 port_num,
                        return -EINVAL;
                ctx->refcnt--;
                if (!ctx->refcnt) {
-                       rc = bnxt_qplib_del_sgid
-                                       (sgid_tbl,
-                                        &sgid_tbl->tbl[ctx->idx], true);
-                       if (rc)
+                       rc = bnxt_qplib_del_sgid(sgid_tbl,
+                                                &sgid_tbl->tbl[ctx->idx],
+                                                true);
+                       if (rc) {
                                dev_err(rdev_to_dev(rdev),
                                        "Failed to remove GID: %#x", rc);
-                       ctx_tbl = sgid_tbl->ctx;
-                       ctx_tbl[ctx->idx] = NULL;
-                       kfree(ctx);
+                       } else {
+                               ctx_tbl = sgid_tbl->ctx;
+                               ctx_tbl[ctx->idx] = NULL;
+                               kfree(ctx);
+                       }
                }
        } else {
                return -EINVAL;
@@ -588,10 +590,10 @@ static int bnxt_re_create_fence_mr(struct bnxt_re_pd *pd)
 
        /* Create a fence MW only for kernel consumers */
        mw = bnxt_re_alloc_mw(&pd->ib_pd, IB_MW_TYPE_1, NULL);
-       if (!mw) {
+       if (IS_ERR(mw)) {
                dev_err(rdev_to_dev(rdev),
                        "Failed to create fence-MW for PD: %p\n", pd);
-               rc = -EINVAL;
+               rc = PTR_ERR(mw);
                goto fail;
        }
        fence->mw = mw;
@@ -612,30 +614,13 @@ int bnxt_re_dealloc_pd(struct ib_pd *ib_pd)
        int rc;
 
        bnxt_re_destroy_fence_mr(pd);
-       if (ib_pd->uobject && pd->dpi.dbr) {
-               struct ib_ucontext *ib_uctx = ib_pd->uobject->context;
-               struct bnxt_re_ucontext *ucntx;
 
-               /* Free DPI only if this is the first PD allocated by the
-                * application and mark the context dpi as NULL
-                */
-               ucntx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx);
-
-               rc = bnxt_qplib_dealloc_dpi(&rdev->qplib_res,
-                                           &rdev->qplib_res.dpi_tbl,
-                                           &pd->dpi);
+       if (pd->qplib_pd.id) {
+               rc = bnxt_qplib_dealloc_pd(&rdev->qplib_res,
+                                          &rdev->qplib_res.pd_tbl,
+                                          &pd->qplib_pd);
                if (rc)
-                       dev_err(rdev_to_dev(rdev), "Failed to deallocate HW DPI");
-                       /* Don't fail, continue*/
-               ucntx->dpi = NULL;
-       }
-
-       rc = bnxt_qplib_dealloc_pd(&rdev->qplib_res,
-                                  &rdev->qplib_res.pd_tbl,
-                                  &pd->qplib_pd);
-       if (rc) {
-               dev_err(rdev_to_dev(rdev), "Failed to deallocate HW PD");
-               return rc;
+                       dev_err(rdev_to_dev(rdev), "Failed to deallocate HW PD");
        }
 
        kfree(pd);
@@ -667,23 +652,22 @@ struct ib_pd *bnxt_re_alloc_pd(struct ib_device *ibdev,
        if (udata) {
                struct bnxt_re_pd_resp resp;
 
-               if (!ucntx->dpi) {
+               if (!ucntx->dpi.dbr) {
                        /* Allocate DPI in alloc_pd to avoid failing of
                         * ibv_devinfo and family of application when DPIs
                         * are depleted.
                         */
                        if (bnxt_qplib_alloc_dpi(&rdev->qplib_res.dpi_tbl,
-                                                &pd->dpi, ucntx)) {
+                                                &ucntx->dpi, ucntx)) {
                                rc = -ENOMEM;
                                goto dbfail;
                        }
-                       ucntx->dpi = &pd->dpi;
                }
 
                resp.pdid = pd->qplib_pd.id;
                /* Still allow mapping this DBR to the new user PD. */
-               resp.dpi = ucntx->dpi->dpi;
-               resp.dbr = (u64)ucntx->dpi->umdbr;
+               resp.dpi = ucntx->dpi.dpi;
+               resp.dbr = (u64)ucntx->dpi.umdbr;
 
                rc = ib_copy_to_udata(udata, &resp, sizeof(resp));
                if (rc) {
@@ -960,7 +944,7 @@ static int bnxt_re_init_user_qp(struct bnxt_re_dev *rdev, struct bnxt_re_pd *pd,
                qplib_qp->rq.nmap = umem->nmap;
        }
 
-       qplib_qp->dpi = cntx->dpi;
+       qplib_qp->dpi = &cntx->dpi;
        return 0;
 rqfail:
        ib_umem_release(qp->sumem);
@@ -1530,13 +1514,24 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
        if (qp_attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
                qp->qplib_qp.modify_flags |=
                                CMDQ_MODIFY_QP_MODIFY_MASK_MAX_RD_ATOMIC;
-               qp->qplib_qp.max_rd_atomic = qp_attr->max_rd_atomic;
+               /* Cap the max_rd_atomic to device max */
+               qp->qplib_qp.max_rd_atomic = min_t(u32, qp_attr->max_rd_atomic,
+                                                  dev_attr->max_qp_rd_atom);
        }
        if (qp_attr_mask & IB_QP_SQ_PSN) {
                qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_SQ_PSN;
                qp->qplib_qp.sq.psn = qp_attr->sq_psn;
        }
        if (qp_attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
+               if (qp_attr->max_dest_rd_atomic >
+                   dev_attr->max_qp_init_rd_atom) {
+                       dev_err(rdev_to_dev(rdev),
+                               "max_dest_rd_atomic requested%d is > dev_max%d",
+                               qp_attr->max_dest_rd_atomic,
+                               dev_attr->max_qp_init_rd_atom);
+                       return -EINVAL;
+               }
+
                qp->qplib_qp.modify_flags |=
                                CMDQ_MODIFY_QP_MODIFY_MASK_MAX_DEST_RD_ATOMIC;
                qp->qplib_qp.max_dest_rd_atomic = qp_attr->max_dest_rd_atomic;
@@ -2403,7 +2398,7 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev,
                }
                cq->qplib_cq.sghead = cq->umem->sg_head.sgl;
                cq->qplib_cq.nmap = cq->umem->nmap;
-               cq->qplib_cq.dpi = uctx->dpi;
+               cq->qplib_cq.dpi = &uctx->dpi;
        } else {
                cq->max_cql = min_t(u32, entries, MAX_CQL_PER_POLL);
                cq->cql = kcalloc(cq->max_cql, sizeof(struct bnxt_qplib_cqe),
@@ -2905,6 +2900,7 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc)
 
        spin_lock_irqsave(&cq->cq_lock, flags);
        budget = min_t(u32, num_entries, cq->max_cql);
+       num_entries = budget;
        if (!cq->cql) {
                dev_err(rdev_to_dev(cq->rdev), "POLL CQ : no CQL to use");
                goto exit;
@@ -3031,6 +3027,11 @@ int bnxt_re_req_notify_cq(struct ib_cq *ib_cq,
        else if (ib_cqn_flags & IB_CQ_SOLICITED)
                type = DBR_DBR_TYPE_CQ_ARMSE;
 
+       /* Poll to see if there are missed events */
+       if ((ib_cqn_flags & IB_CQ_REPORT_MISSED_EVENTS) &&
+           !(bnxt_qplib_is_cq_empty(&cq->qplib_cq)))
+               return 1;
+
        bnxt_qplib_req_notify_cq(&cq->qplib_cq, type);
 
        return 0;
@@ -3245,6 +3246,12 @@ struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *ib_pd, u64 start, u64 length,
        struct scatterlist *sg;
        int entry;
 
+       if (length > BNXT_RE_MAX_MR_SIZE) {
+               dev_err(rdev_to_dev(rdev), "MR Size: %lld > Max supported:%ld\n",
+                       length, BNXT_RE_MAX_MR_SIZE);
+               return ERR_PTR(-ENOMEM);
+       }
+
        mr = kzalloc(sizeof(*mr), GFP_KERNEL);
        if (!mr)
                return ERR_PTR(-ENOMEM);
@@ -3388,8 +3395,26 @@ int bnxt_re_dealloc_ucontext(struct ib_ucontext *ib_uctx)
        struct bnxt_re_ucontext *uctx = container_of(ib_uctx,
                                                   struct bnxt_re_ucontext,
                                                   ib_uctx);
+
+       struct bnxt_re_dev *rdev = uctx->rdev;
+       int rc = 0;
+
        if (uctx->shpg)
                free_page((unsigned long)uctx->shpg);
+
+       if (uctx->dpi.dbr) {
+               /* Free DPI only if this is the first PD allocated by the
+                * application and mark the context dpi as NULL
+                */
+               rc = bnxt_qplib_dealloc_dpi(&rdev->qplib_res,
+                                           &rdev->qplib_res.dpi_tbl,
+                                           &uctx->dpi);
+               if (rc)
+                       dev_err(rdev_to_dev(rdev), "Deallocte HW DPI failed!");
+                       /* Don't fail, continue*/
+               uctx->dpi.dbr = NULL;
+       }
+
        kfree(uctx);
        return 0;
 }
index 6c160f6..a0bb7e3 100644 (file)
@@ -59,7 +59,6 @@ struct bnxt_re_pd {
        struct bnxt_re_dev      *rdev;
        struct ib_pd            ib_pd;
        struct bnxt_qplib_pd    qplib_pd;
-       struct bnxt_qplib_dpi   dpi;
        struct bnxt_re_fence_data fence;
 };
 
@@ -127,7 +126,7 @@ struct bnxt_re_mw {
 struct bnxt_re_ucontext {
        struct bnxt_re_dev      *rdev;
        struct ib_ucontext      ib_uctx;
-       struct bnxt_qplib_dpi   *dpi;
+       struct bnxt_qplib_dpi   dpi;
        void                    *shpg;
        spinlock_t              sh_lock;        /* protect shpg */
 };
index 1fce5e7..ceae2d9 100644 (file)
@@ -333,6 +333,7 @@ static int bnxt_re_net_stats_ctx_alloc(struct bnxt_re_dev *rdev,
        bnxt_re_init_hwrm_hdr(rdev, (void *)&req, HWRM_STAT_CTX_ALLOC, -1, -1);
        req.update_period_ms = cpu_to_le32(1000);
        req.stats_dma_addr = cpu_to_le64(dma_map);
+       req.stat_ctx_flags = STAT_CTX_ALLOC_REQ_STAT_CTX_FLAGS_ROCE;
        bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp,
                            sizeof(resp), DFLT_HWRM_CMD_TIMEOUT);
        rc = en_dev->en_ops->bnxt_send_fw_msg(en_dev, BNXT_ROCE_ULP, &fw_msg);
index f05500b..9af1514 100644 (file)
@@ -1128,6 +1128,11 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
                }
                /* Each SGE entry = 1 WQE size16 */
                wqe_size16 = wqe->num_sge;
+               /* HW requires wqe size has room for atleast one SGE even if
+                * none was supplied by ULP
+                */
+               if (!wqe->num_sge)
+                       wqe_size16++;
        }
 
        /* Specifics */
@@ -1364,6 +1369,11 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp,
        rqe->flags = wqe->flags;
        rqe->wqe_size = wqe->num_sge +
                        ((offsetof(typeof(*rqe), data) + 15) >> 4);
+       /* HW requires wqe size has room for atleast one SGE even if none
+        * was supplied by ULP
+        */
+       if (!wqe->num_sge)
+               rqe->wqe_size++;
 
        /* Supply the rqe->wr_id index to the wr_id_tbl for now */
        rqe->wr_id[0] = cpu_to_le32(sw_prod);
@@ -1885,6 +1895,25 @@ flush_rq:
        return rc;
 }
 
+bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq)
+{
+       struct cq_base *hw_cqe, **hw_cqe_ptr;
+       unsigned long flags;
+       u32 sw_cons, raw_cons;
+       bool rc = true;
+
+       spin_lock_irqsave(&cq->hwq.lock, flags);
+       raw_cons = cq->hwq.cons;
+       sw_cons = HWQ_CMP(raw_cons, &cq->hwq);
+       hw_cqe_ptr = (struct cq_base **)cq->hwq.pbl_ptr;
+       hw_cqe = &hw_cqe_ptr[CQE_PG(sw_cons)][CQE_IDX(sw_cons)];
+
+        /* Check for Valid bit. If the CQE is valid, return false */
+       rc = !CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements);
+       spin_unlock_irqrestore(&cq->hwq.lock, flags);
+       return rc;
+}
+
 static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
                                                struct cq_res_raweth_qp1 *hwcqe,
                                                struct bnxt_qplib_cqe **pcqe,
index 36b7b7d..19176e0 100644 (file)
@@ -449,6 +449,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq);
 int bnxt_qplib_destroy_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq);
 int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
                       int num, struct bnxt_qplib_qp **qp);
+bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq);
 void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type);
 void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq);
 int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq);
index fde18cf..ef91ab7 100644 (file)
@@ -51,6 +51,19 @@ const struct bnxt_qplib_gid bnxt_qplib_gid_zero = {{ 0, 0, 0, 0, 0, 0, 0, 0,
                                                     0, 0, 0, 0, 0, 0, 0, 0 } };
 
 /* Device */
+
+static bool bnxt_qplib_is_atomic_cap(struct bnxt_qplib_rcfw *rcfw)
+{
+       int rc;
+       u16 pcie_ctl2;
+
+       rc = pcie_capability_read_word(rcfw->pdev, PCI_EXP_DEVCTL2,
+                                      &pcie_ctl2);
+       if (rc)
+               return false;
+       return !!(pcie_ctl2 & PCI_EXP_DEVCTL2_ATOMIC_REQ);
+}
+
 int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
                            struct bnxt_qplib_dev_attr *attr)
 {
@@ -81,6 +94,8 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
 
        /* Extract the context from the side buffer */
        attr->max_qp = le32_to_cpu(sb->max_qp);
+       /* max_qp value reported by FW for PF doesn't include the QP1 for PF */
+       attr->max_qp += 1;
        attr->max_qp_rd_atom =
                sb->max_qp_rd_atom > BNXT_QPLIB_MAX_OUT_RD_ATOM ?
                BNXT_QPLIB_MAX_OUT_RD_ATOM : sb->max_qp_rd_atom;
@@ -129,6 +144,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
                attr->tqm_alloc_reqs[i * 4 + 3] = *(++tqm_alloc);
        }
 
+       attr->is_atomic = bnxt_qplib_is_atomic_cap(rcfw);
 bail:
        bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf);
        return rc;
index a543f95..2ce7e2a 100644 (file)
@@ -42,6 +42,8 @@
 
 #define BNXT_QPLIB_RESERVED_QP_WRS     128
 
+#define PCI_EXP_DEVCTL2_ATOMIC_REQ      0x0040
+
 struct bnxt_qplib_dev_attr {
        char                            fw_ver[32];
        u16                             max_sgid;
@@ -70,6 +72,7 @@ struct bnxt_qplib_dev_attr {
        u32                             max_inline_data;
        u32                             l2_db_size;
        u8                              tqm_alloc_reqs[MAX_TQM_ALLOC_REQ];
+       bool                            is_atomic;
 };
 
 struct bnxt_qplib_pd {
index 29d3074..0cd0c1f 100644 (file)
@@ -718,7 +718,7 @@ static struct ib_mr *iwch_alloc_mr(struct ib_pd *pd,
        struct iwch_mr *mhp;
        u32 mmid;
        u32 stag = 0;
-       int ret = 0;
+       int ret = -ENOMEM;
 
        if (mr_type != IB_MR_TYPE_MEM_REG ||
            max_num_sg > T3_MAX_FASTREG_DEPTH)
@@ -731,10 +731,8 @@ static struct ib_mr *iwch_alloc_mr(struct ib_pd *pd,
                goto err;
 
        mhp->pages = kcalloc(max_num_sg, sizeof(u64), GFP_KERNEL);
-       if (!mhp->pages) {
-               ret = -ENOMEM;
+       if (!mhp->pages)
                goto pl_err;
-       }
 
        mhp->rhp = rhp;
        ret = iwch_alloc_pbl(mhp, max_num_sg);
@@ -751,7 +749,8 @@ static struct ib_mr *iwch_alloc_mr(struct ib_pd *pd,
        mhp->attr.state = 1;
        mmid = (stag) >> 8;
        mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
-       if (insert_handle(rhp, &rhp->mmidr, mhp, mmid))
+       ret = insert_handle(rhp, &rhp->mmidr, mhp, mmid);
+       if (ret)
                goto err3;
 
        pr_debug("%s mmid 0x%x mhp %p stag 0x%x\n", __func__, mmid, mhp, stag);
index e16fcaf..be07da1 100644 (file)
@@ -963,6 +963,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
                goto err3;
 
        if (ucontext) {
+               ret = -ENOMEM;
                mm = kmalloc(sizeof *mm, GFP_KERNEL);
                if (!mm)
                        goto err4;
index bfc7759..cb7fc0d 100644 (file)
@@ -569,7 +569,7 @@ static int build_rdma_read(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
 {
        if (wr->num_sge > 1)
                return -EINVAL;
-       if (wr->num_sge) {
+       if (wr->num_sge && wr->sg_list[0].length) {
                wqe->read.stag_src = cpu_to_be32(rdma_wr(wr)->rkey);
                wqe->read.to_src_hi = cpu_to_be32((u32)(rdma_wr(wr)->remote_addr
                                                        >> 32));
index 2ba00b8..94b5485 100644 (file)
@@ -12847,7 +12847,12 @@ static void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr)
        /* clear from the handled mask of the general interrupt */
        m = isrc / 64;
        n = isrc % 64;
-       dd->gi_mask[m] &= ~((u64)1 << n);
+       if (likely(m < CCE_NUM_INT_CSRS)) {
+               dd->gi_mask[m] &= ~((u64)1 << n);
+       } else {
+               dd_dev_err(dd, "remap interrupt err\n");
+               return;
+       }
 
        /* direct the chip source to the given MSI-X interrupt */
        m = isrc / 8;
index 650305c..1a7af9f 100644 (file)
@@ -647,18 +647,17 @@ void qp_iter_print(struct seq_file *s, struct qp_iter *iter)
                   qp->pid);
 }
 
-void *qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp,
-                   gfp_t gfp)
+void *qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp)
 {
        struct hfi1_qp_priv *priv;
 
-       priv = kzalloc_node(sizeof(*priv), gfp, rdi->dparms.node);
+       priv = kzalloc_node(sizeof(*priv), GFP_KERNEL, rdi->dparms.node);
        if (!priv)
                return ERR_PTR(-ENOMEM);
 
        priv->owner = qp;
 
-       priv->s_ahg = kzalloc_node(sizeof(*priv->s_ahg), gfp,
+       priv->s_ahg = kzalloc_node(sizeof(*priv->s_ahg), GFP_KERNEL,
                                   rdi->dparms.node);
        if (!priv->s_ahg) {
                kfree(priv);
index 1eb9cd7..6fe542b 100644 (file)
@@ -123,8 +123,7 @@ void hfi1_migrate_qp(struct rvt_qp *qp);
 /*
  * Functions provided by hfi1 driver for rdmavt to use
  */
-void *qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp,
-                   gfp_t gfp);
+void *qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp);
 void qp_priv_free(struct rvt_dev_info *rdi, struct rvt_qp *qp);
 unsigned free_all_qps(struct rvt_dev_info *rdi);
 void notify_qp_reset(struct rvt_qp *qp);
index 37d5d29..23fad6d 100644 (file)
@@ -228,14 +228,14 @@ int hns_roce_v1_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_RDMA_READ:
                                ps_opcode = HNS_ROCE_WQE_OPCODE_RDMA_READ;
-                               set_raddr_seg(wqe, atomic_wr(wr)->remote_addr,
-                                             atomic_wr(wr)->rkey);
+                               set_raddr_seg(wqe,  rdma_wr(wr)->remote_addr,
+                                              rdma_wr(wr)->rkey);
                                break;
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
                                ps_opcode = HNS_ROCE_WQE_OPCODE_RDMA_WRITE;
-                               set_raddr_seg(wqe, atomic_wr(wr)->remote_addr,
-                                             atomic_wr(wr)->rkey);
+                               set_raddr_seg(wqe,  rdma_wr(wr)->remote_addr,
+                                             rdma_wr(wr)->rkey);
                                break;
                        case IB_WR_SEND:
                        case IB_WR_SEND_WITH_INV:
@@ -661,9 +661,11 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev)
        union ib_gid dgid;
        u64 subnet_prefix;
        int attr_mask = 0;
-       int i;
+       int i, j;
        int ret;
+       u8 queue_en[HNS_ROCE_V1_RESV_QP] = { 0 };
        u8 phy_port;
+       u8 port = 0;
        u8 sl;
 
        priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv;
@@ -709,11 +711,27 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev)
        attr.rnr_retry          = 7;
        attr.timeout            = 0x12;
        attr.path_mtu           = IB_MTU_256;
+       attr.ah_attr.type       = RDMA_AH_ATTR_TYPE_ROCE;
        rdma_ah_set_grh(&attr.ah_attr, NULL, 0, 0, 1, 0);
        rdma_ah_set_static_rate(&attr.ah_attr, 3);
 
        subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
        for (i = 0; i < HNS_ROCE_V1_RESV_QP; i++) {
+               phy_port = (i >= HNS_ROCE_MAX_PORTS) ? (i - 2) :
+                               (i % HNS_ROCE_MAX_PORTS);
+               sl = i / HNS_ROCE_MAX_PORTS;
+
+               for (j = 0; j < caps->num_ports; j++) {
+                       if (hr_dev->iboe.phy_port[j] == phy_port) {
+                               queue_en[i] = 1;
+                               port = j;
+                               break;
+                       }
+               }
+
+               if (!queue_en[i])
+                       continue;
+
                free_mr->mr_free_qp[i] = hns_roce_v1_create_lp_qp(hr_dev, pd);
                if (IS_ERR(free_mr->mr_free_qp[i])) {
                        dev_err(dev, "Create loop qp failed!\n");
@@ -721,15 +739,7 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev)
                }
                hr_qp = free_mr->mr_free_qp[i];
 
-               sl = i / caps->num_ports;
-
-               if (caps->num_ports == HNS_ROCE_MAX_PORTS)
-                       phy_port = (i >= HNS_ROCE_MAX_PORTS) ? (i - 2) :
-                               (i % caps->num_ports);
-               else
-                       phy_port = i % caps->num_ports;
-
-               hr_qp->port             = phy_port + 1;
+               hr_qp->port             = port;
                hr_qp->phy_port         = phy_port;
                hr_qp->ibqp.qp_type     = IB_QPT_RC;
                hr_qp->ibqp.device      = &hr_dev->ib_dev;
@@ -739,23 +749,22 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev)
                hr_qp->ibqp.recv_cq     = cq;
                hr_qp->ibqp.send_cq     = cq;
 
-               rdma_ah_set_port_num(&attr.ah_attr, phy_port + 1);
-               rdma_ah_set_sl(&attr.ah_attr, phy_port + 1);
-               attr.port_num           = phy_port + 1;
+               rdma_ah_set_port_num(&attr.ah_attr, port + 1);
+               rdma_ah_set_sl(&attr.ah_attr, sl);
+               attr.port_num           = port + 1;
 
                attr.dest_qp_num        = hr_qp->qpn;
                memcpy(rdma_ah_retrieve_dmac(&attr.ah_attr),
-                      hr_dev->dev_addr[phy_port],
+                      hr_dev->dev_addr[port],
                       MAC_ADDR_OCTET_NUM);
 
                memcpy(&dgid.raw, &subnet_prefix, sizeof(u64));
-               memcpy(&dgid.raw[8], hr_dev->dev_addr[phy_port], 3);
-               memcpy(&dgid.raw[13], hr_dev->dev_addr[phy_port] + 3, 3);
+               memcpy(&dgid.raw[8], hr_dev->dev_addr[port], 3);
+               memcpy(&dgid.raw[13], hr_dev->dev_addr[port] + 3, 3);
                dgid.raw[11] = 0xff;
                dgid.raw[12] = 0xfe;
                dgid.raw[8] ^= 2;
                rdma_ah_set_dgid_raw(&attr.ah_attr, dgid.raw);
-               attr_mask |= IB_QP_PORT;
 
                ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, &attr, attr_mask,
                                            IB_QPS_RESET, IB_QPS_INIT);
@@ -812,6 +821,9 @@ static void hns_roce_v1_release_lp_qp(struct hns_roce_dev *hr_dev)
 
        for (i = 0; i < HNS_ROCE_V1_RESV_QP; i++) {
                hr_qp = free_mr->mr_free_qp[i];
+               if (!hr_qp)
+                       continue;
+
                ret = hns_roce_v1_destroy_qp(&hr_qp->ibqp);
                if (ret)
                        dev_err(dev, "Destroy qp %d for mr free failed(%d)!\n",
@@ -963,7 +975,7 @@ static void hns_roce_v1_mr_free_work_fn(struct work_struct *work)
                msecs_to_jiffies(HNS_ROCE_V1_FREE_MR_TIMEOUT_MSECS) + jiffies;
        int i;
        int ret;
-       int ne;
+       int ne = 0;
 
        mr_work = container_of(work, struct hns_roce_mr_free_work, work);
        hr_mr = (struct hns_roce_mr *)mr_work->mr;
@@ -976,6 +988,10 @@ static void hns_roce_v1_mr_free_work_fn(struct work_struct *work)
 
        for (i = 0; i < HNS_ROCE_V1_RESV_QP; i++) {
                hr_qp = free_mr->mr_free_qp[i];
+               if (!hr_qp)
+                       continue;
+               ne++;
+
                ret = hns_roce_v1_send_lp_wqe(hr_qp);
                if (ret) {
                        dev_err(dev,
@@ -985,7 +1001,6 @@ static void hns_roce_v1_mr_free_work_fn(struct work_struct *work)
                }
        }
 
-       ne = HNS_ROCE_V1_RESV_QP;
        do {
                ret = hns_roce_v1_poll_cq(&mr_free_cq->ib_cq, ne, wc);
                if (ret < 0) {
@@ -995,7 +1010,8 @@ static void hns_roce_v1_mr_free_work_fn(struct work_struct *work)
                        goto free_work;
                }
                ne -= ret;
-               msleep(HNS_ROCE_V1_FREE_MR_WAIT_VALUE);
+               usleep_range(HNS_ROCE_V1_FREE_MR_WAIT_VALUE * 1000,
+                            (1 + HNS_ROCE_V1_FREE_MR_WAIT_VALUE) * 1000);
        } while (ne && time_before_eq(jiffies, end));
 
        if (ne != 0)
@@ -2181,7 +2197,7 @@ static int hns_roce_v1_poll_one(struct hns_roce_cq *hr_cq,
                }
                wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)];
                ++wq->tail;
-               } else {
+       } else {
                /* RQ conrespond to CQE */
                wc->byte_len = le32_to_cpu(cqe->byte_cnt);
                opcode = roce_get_field(cqe->cqe_byte_4,
@@ -3533,10 +3549,12 @@ static int check_qp_db_process_status(struct hns_roce_dev *hr_dev,
                                        old_cnt = roce_get_field(old_send,
                                        ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_M,
                                        ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S);
-                                       if (cur_cnt - old_cnt > SDB_ST_CMP_VAL)
+                                       if (cur_cnt - old_cnt >
+                                           SDB_ST_CMP_VAL) {
                                                success_flags = 1;
-                                       else {
-                                           send_ptr = roce_get_field(old_send,
+                                       } else {
+                                               send_ptr =
+                                                       roce_get_field(old_send,
                                            ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_M,
                                            ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S) +
                                            roce_get_field(sdb_retry_cnt,
@@ -3641,6 +3659,7 @@ static void hns_roce_v1_destroy_qp_work_fn(struct work_struct *work)
        struct hns_roce_dev *hr_dev;
        struct hns_roce_qp *hr_qp;
        struct device *dev;
+       unsigned long qpn;
        int ret;
 
        qp_work_entry = container_of(work, struct hns_roce_qp_work, work);
@@ -3648,8 +3667,9 @@ static void hns_roce_v1_destroy_qp_work_fn(struct work_struct *work)
        dev = &hr_dev->pdev->dev;
        priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv;
        hr_qp = qp_work_entry->qp;
+       qpn = hr_qp->qpn;
 
-       dev_dbg(dev, "Schedule destroy QP(0x%lx) work.\n", hr_qp->qpn);
+       dev_dbg(dev, "Schedule destroy QP(0x%lx) work.\n", qpn);
 
        qp_work_entry->sche_cnt++;
 
@@ -3660,7 +3680,7 @@ static void hns_roce_v1_destroy_qp_work_fn(struct work_struct *work)
                                         &qp_work_entry->db_wait_stage);
        if (ret) {
                dev_err(dev, "Check QP(0x%lx) db process status failed!\n",
-                       hr_qp->qpn);
+                       qpn);
                return;
        }
 
@@ -3674,7 +3694,7 @@ static void hns_roce_v1_destroy_qp_work_fn(struct work_struct *work)
        ret = hns_roce_v1_modify_qp(&hr_qp->ibqp, NULL, 0, hr_qp->state,
                                    IB_QPS_RESET);
        if (ret) {
-               dev_err(dev, "Modify QP(0x%lx) to RST failed!\n", hr_qp->qpn);
+               dev_err(dev, "Modify QP(0x%lx) to RST failed!\n", qpn);
                return;
        }
 
@@ -3683,14 +3703,14 @@ static void hns_roce_v1_destroy_qp_work_fn(struct work_struct *work)
 
        if (hr_qp->ibqp.qp_type == IB_QPT_RC) {
                /* RC QP, release QPN */
-               hns_roce_release_range_qp(hr_dev, hr_qp->qpn, 1);
+               hns_roce_release_range_qp(hr_dev, qpn, 1);
                kfree(hr_qp);
        } else
                kfree(hr_to_hr_sqp(hr_qp));
 
        kfree(qp_work_entry);
 
-       dev_dbg(dev, "Accomplished destroy QP(0x%lx) work.\n", hr_qp->qpn);
+       dev_dbg(dev, "Accomplished destroy QP(0x%lx) work.\n", qpn);
 }
 
 int hns_roce_v1_destroy_qp(struct ib_qp *ibqp)
index c3b41f9..d9777b6 100644 (file)
@@ -125,8 +125,6 @@ static int handle_en_event(struct hns_roce_dev *hr_dev, u8 port,
                return -ENODEV;
        }
 
-       spin_lock_bh(&hr_dev->iboe.lock);
-
        switch (event) {
        case NETDEV_UP:
        case NETDEV_CHANGE:
@@ -144,7 +142,6 @@ static int handle_en_event(struct hns_roce_dev *hr_dev, u8 port,
                break;
        }
 
-       spin_unlock_bh(&hr_dev->iboe.lock);
        return 0;
 }
 
index da2eb5a..9b15664 100644 (file)
@@ -527,6 +527,7 @@ enum i40iw_status_code i40iw_add_mac_addr(struct i40iw_device *iwdev,
 int i40iw_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *);
 void i40iw_cq_wq_destroy(struct i40iw_device *iwdev, struct i40iw_sc_cq *cq);
 
+void i40iw_cleanup_pending_cqp_op(struct i40iw_device *iwdev);
 void i40iw_rem_pdusecount(struct i40iw_pd *iwpd, struct i40iw_device *iwdev);
 void i40iw_add_pdusecount(struct i40iw_pd *iwpd);
 void i40iw_rem_devusecount(struct i40iw_device *iwdev);
index 6ae98aa..5a2fa74 100644 (file)
@@ -3487,7 +3487,8 @@ static void i40iw_cm_disconn_true(struct i40iw_qp *iwqp)
        if (((original_hw_tcp_state == I40IW_TCP_STATE_CLOSED) ||
             (original_hw_tcp_state == I40IW_TCP_STATE_TIME_WAIT) ||
             (last_ae == I40IW_AE_RDMAP_ROE_BAD_LLP_CLOSE) ||
-            (last_ae == I40IW_AE_LLP_CONNECTION_RESET))) {
+            (last_ae == I40IW_AE_LLP_CONNECTION_RESET) ||
+             iwdev->reset)) {
                issue_close = 1;
                iwqp->cm_id = NULL;
                if (!iwqp->flush_issued) {
@@ -4265,6 +4266,8 @@ void i40iw_cm_disconnect_all(struct i40iw_device *iwdev)
                cm_node = container_of(list_node, struct i40iw_cm_node, connected_entry);
                attr.qp_state = IB_QPS_ERR;
                i40iw_modify_qp(&cm_node->iwqp->ibqp, &attr, IB_QP_STATE, NULL);
+               if (iwdev->reset)
+                       i40iw_cm_disconn(cm_node->iwqp);
                i40iw_rem_ref_cm_node(cm_node);
        }
 }
index a027e20..9ec1ae9 100644 (file)
@@ -1970,6 +1970,8 @@ static enum i40iw_status_code i40iw_sc_ccq_destroy(struct i40iw_sc_cq *ccq,
                ret_code = i40iw_cqp_poll_registers(cqp, tail, 1000);
        }
 
+       cqp->process_cqp_sds = i40iw_update_sds_noccq;
+
        return ret_code;
 }
 
index e0f47cc..ae8463f 100644 (file)
@@ -243,6 +243,8 @@ static void i40iw_destroy_cqp(struct i40iw_device *iwdev, bool free_hwcqp)
        if (free_hwcqp)
                dev->cqp_ops->cqp_destroy(dev->cqp);
 
+       i40iw_cleanup_pending_cqp_op(iwdev);
+
        i40iw_free_dma_mem(dev->hw, &cqp->sq);
        kfree(cqp->scratch_array);
        iwdev->cqp.scratch_array = NULL;
@@ -274,13 +276,12 @@ static void i40iw_disable_irq(struct i40iw_sc_dev *dev,
 /**
  * i40iw_destroy_aeq - destroy aeq
  * @iwdev: iwarp device
- * @reset: true if called before reset
  *
  * Issue a destroy aeq request and
  * free the resources associated with the aeq
  * The function is called during driver unload
  */
-static void i40iw_destroy_aeq(struct i40iw_device *iwdev, bool reset)
+static void i40iw_destroy_aeq(struct i40iw_device *iwdev)
 {
        enum i40iw_status_code status = I40IW_ERR_NOT_READY;
        struct i40iw_sc_dev *dev = &iwdev->sc_dev;
@@ -288,7 +289,7 @@ static void i40iw_destroy_aeq(struct i40iw_device *iwdev, bool reset)
 
        if (!iwdev->msix_shared)
                i40iw_disable_irq(dev, iwdev->iw_msixtbl, (void *)iwdev);
-       if (reset)
+       if (iwdev->reset)
                goto exit;
 
        if (!dev->aeq_ops->aeq_destroy(&aeq->sc_aeq, 0, 1))
@@ -304,19 +305,17 @@ exit:
  * i40iw_destroy_ceq - destroy ceq
  * @iwdev: iwarp device
  * @iwceq: ceq to be destroyed
- * @reset: true if called before reset
  *
  * Issue a destroy ceq request and
  * free the resources associated with the ceq
  */
 static void i40iw_destroy_ceq(struct i40iw_device *iwdev,
-                             struct i40iw_ceq *iwceq,
-                             bool reset)
+                             struct i40iw_ceq *iwceq)
 {
        enum i40iw_status_code status;
        struct i40iw_sc_dev *dev = &iwdev->sc_dev;
 
-       if (reset)
+       if (iwdev->reset)
                goto exit;
 
        status = dev->ceq_ops->ceq_destroy(&iwceq->sc_ceq, 0, 1);
@@ -335,12 +334,11 @@ exit:
 /**
  * i40iw_dele_ceqs - destroy all ceq's
  * @iwdev: iwarp device
- * @reset: true if called before reset
  *
  * Go through all of the device ceq's and for each ceq
  * disable the ceq interrupt and destroy the ceq
  */
-static void i40iw_dele_ceqs(struct i40iw_device *iwdev, bool reset)
+static void i40iw_dele_ceqs(struct i40iw_device *iwdev)
 {
        u32 i = 0;
        struct i40iw_sc_dev *dev = &iwdev->sc_dev;
@@ -349,32 +347,31 @@ static void i40iw_dele_ceqs(struct i40iw_device *iwdev, bool reset)
 
        if (iwdev->msix_shared) {
                i40iw_disable_irq(dev, msix_vec, (void *)iwdev);
-               i40iw_destroy_ceq(iwdev, iwceq, reset);
+               i40iw_destroy_ceq(iwdev, iwceq);
                iwceq++;
                i++;
        }
 
        for (msix_vec++; i < iwdev->ceqs_count; i++, msix_vec++, iwceq++) {
                i40iw_disable_irq(dev, msix_vec, (void *)iwceq);
-               i40iw_destroy_ceq(iwdev, iwceq, reset);
+               i40iw_destroy_ceq(iwdev, iwceq);
        }
 }
 
 /**
  * i40iw_destroy_ccq - destroy control cq
  * @iwdev: iwarp device
- * @reset: true if called before reset
  *
  * Issue destroy ccq request and
  * free the resources associated with the ccq
  */
-static void i40iw_destroy_ccq(struct i40iw_device *iwdev, bool reset)
+static void i40iw_destroy_ccq(struct i40iw_device *iwdev)
 {
        struct i40iw_sc_dev *dev = &iwdev->sc_dev;
        struct i40iw_ccq *ccq = &iwdev->ccq;
        enum i40iw_status_code status = 0;
 
-       if (!reset)
+       if (!iwdev->reset)
                status = dev->ccq_ops->ccq_destroy(dev->ccq, 0, true);
        if (status)
                i40iw_pr_err("ccq destroy failed %d\n", status);
@@ -810,7 +807,7 @@ static enum i40iw_status_code i40iw_setup_ceqs(struct i40iw_device *iwdev,
                iwceq->msix_idx = msix_vec->idx;
                status = i40iw_configure_ceq_vector(iwdev, iwceq, ceq_id, msix_vec);
                if (status) {
-                       i40iw_destroy_ceq(iwdev, iwceq, false);
+                       i40iw_destroy_ceq(iwdev, iwceq);
                        break;
                }
                i40iw_enable_intr(&iwdev->sc_dev, msix_vec->idx);
@@ -912,7 +909,7 @@ static enum i40iw_status_code i40iw_setup_aeq(struct i40iw_device *iwdev)
 
        status = i40iw_configure_aeq_vector(iwdev);
        if (status) {
-               i40iw_destroy_aeq(iwdev, false);
+               i40iw_destroy_aeq(iwdev);
                return status;
        }
 
@@ -1442,12 +1439,11 @@ static enum i40iw_status_code i40iw_save_msix_info(struct i40iw_device *iwdev,
 /**
  * i40iw_deinit_device - clean up the device resources
  * @iwdev: iwarp device
- * @reset: true if called before reset
  *
  * Destroy the ib device interface, remove the mac ip entry and ipv4/ipv6 addresses,
  * destroy the device queues and free the pble and the hmc objects
  */
-static void i40iw_deinit_device(struct i40iw_device *iwdev, bool reset)
+static void i40iw_deinit_device(struct i40iw_device *iwdev)
 {
        struct i40e_info *ldev = iwdev->ldev;
 
@@ -1464,7 +1460,7 @@ static void i40iw_deinit_device(struct i40iw_device *iwdev, bool reset)
                i40iw_destroy_rdma_device(iwdev->iwibdev);
                /* fallthrough */
        case IP_ADDR_REGISTERED:
-               if (!reset)
+               if (!iwdev->reset)
                        i40iw_del_macip_entry(iwdev, (u8)iwdev->mac_ip_table_idx);
                /* fallthrough */
        case INET_NOTIFIER:
@@ -1474,26 +1470,26 @@ static void i40iw_deinit_device(struct i40iw_device *iwdev, bool reset)
                        unregister_inet6addr_notifier(&i40iw_inetaddr6_notifier);
                }
                /* fallthrough */
+       case PBLE_CHUNK_MEM:
+               i40iw_destroy_pble_pool(dev, iwdev->pble_rsrc);
+               /* fallthrough */
        case CEQ_CREATED:
-               i40iw_dele_ceqs(iwdev, reset);
+               i40iw_dele_ceqs(iwdev);
                /* fallthrough */
        case AEQ_CREATED:
-               i40iw_destroy_aeq(iwdev, reset);
+               i40iw_destroy_aeq(iwdev);
                /* fallthrough */
        case IEQ_CREATED:
-               i40iw_puda_dele_resources(&iwdev->vsi, I40IW_PUDA_RSRC_TYPE_IEQ, reset);
+               i40iw_puda_dele_resources(&iwdev->vsi, I40IW_PUDA_RSRC_TYPE_IEQ, iwdev->reset);
                /* fallthrough */
        case ILQ_CREATED:
-               i40iw_puda_dele_resources(&iwdev->vsi, I40IW_PUDA_RSRC_TYPE_ILQ, reset);
+               i40iw_puda_dele_resources(&iwdev->vsi, I40IW_PUDA_RSRC_TYPE_ILQ, iwdev->reset);
                /* fallthrough */
        case CCQ_CREATED:
-               i40iw_destroy_ccq(iwdev, reset);
-               /* fallthrough */
-       case PBLE_CHUNK_MEM:
-               i40iw_destroy_pble_pool(dev, iwdev->pble_rsrc);
+               i40iw_destroy_ccq(iwdev);
                /* fallthrough */
        case HMC_OBJS_CREATED:
-               i40iw_del_hmc_objects(dev, dev->hmc_info, true, reset);
+               i40iw_del_hmc_objects(dev, dev->hmc_info, true, iwdev->reset);
                /* fallthrough */
        case CQP_CREATED:
                i40iw_destroy_cqp(iwdev, true);
@@ -1670,6 +1666,7 @@ static int i40iw_open(struct i40e_info *ldev, struct i40e_client *client)
                status = i40iw_hmc_init_pble(&iwdev->sc_dev, iwdev->pble_rsrc);
                if (status)
                        break;
+               iwdev->init_state = PBLE_CHUNK_MEM;
                iwdev->virtchnl_wq = alloc_ordered_workqueue("iwvch", WQ_MEM_RECLAIM);
                i40iw_register_notifiers();
                iwdev->init_state = INET_NOTIFIER;
@@ -1693,7 +1690,7 @@ static int i40iw_open(struct i40e_info *ldev, struct i40e_client *client)
        } while (0);
 
        i40iw_pr_err("status = %d last completion = %d\n", status, iwdev->init_state);
-       i40iw_deinit_device(iwdev, false);
+       i40iw_deinit_device(iwdev);
        return -ERESTART;
 }
 
@@ -1774,9 +1771,12 @@ static void i40iw_close(struct i40e_info *ldev, struct i40e_client *client, bool
        iwdev = &hdl->device;
        iwdev->closing = true;
 
+       if (reset)
+               iwdev->reset = true;
+
        i40iw_cm_disconnect_all(iwdev);
        destroy_workqueue(iwdev->virtchnl_wq);
-       i40iw_deinit_device(iwdev, reset);
+       i40iw_deinit_device(iwdev);
 }
 
 /**
index db41ab4..71050c5 100644 (file)
@@ -408,6 +408,9 @@ enum i40iw_status_code i40iw_puda_send(struct i40iw_sc_qp *qp,
        set_64bit_val(wqe, 0, info->paddr);
        set_64bit_val(wqe, 8, LS_64(info->len, I40IWQPSQ_FRAG_LEN));
        set_64bit_val(wqe, 16, header[0]);
+
+       /* Ensure all data is written before writing valid bit */
+       wmb();
        set_64bit_val(wqe, 24, header[1]);
 
        i40iw_debug_buf(qp->dev, I40IW_DEBUG_PUDA, "PUDA SEND WQE", wqe, 32);
@@ -1411,10 +1414,10 @@ static void i40iw_ieq_handle_exception(struct i40iw_puda_rsrc *ieq,
 
        if (!list_empty(rxlist)) {
                tmpbuf = (struct i40iw_puda_buf *)rxlist->next;
-               plist = &tmpbuf->list;
                while ((struct list_head *)tmpbuf != rxlist) {
                        if ((int)(buf->seqnum - tmpbuf->seqnum) < 0)
                                break;
+                       plist = &tmpbuf->list;
                        tmpbuf = (struct i40iw_puda_buf *)plist->next;
                }
                /* Insert buf before tmpbuf */
index 56d9869..e311ec5 100644 (file)
@@ -337,6 +337,7 @@ struct i40iw_cqp_request *i40iw_get_cqp_request(struct i40iw_cqp *cqp, bool wait
  */
 void i40iw_free_cqp_request(struct i40iw_cqp *cqp, struct i40iw_cqp_request *cqp_request)
 {
+       struct i40iw_device *iwdev = container_of(cqp, struct i40iw_device, cqp);
        unsigned long flags;
 
        if (cqp_request->dynamic) {
@@ -350,6 +351,7 @@ void i40iw_free_cqp_request(struct i40iw_cqp *cqp, struct i40iw_cqp_request *cqp
                list_add_tail(&cqp_request->list, &cqp->cqp_avail_reqs);
                spin_unlock_irqrestore(&cqp->req_lock, flags);
        }
+       wake_up(&iwdev->close_wq);
 }
 
 /**
@@ -365,6 +367,56 @@ void i40iw_put_cqp_request(struct i40iw_cqp *cqp,
 }
 
 /**
+ * i40iw_free_pending_cqp_request -free pending cqp request objs
+ * @cqp: cqp ptr
+ * @cqp_request: to be put back in cqp list
+ */
+static void i40iw_free_pending_cqp_request(struct i40iw_cqp *cqp,
+                                          struct i40iw_cqp_request *cqp_request)
+{
+       struct i40iw_device *iwdev = container_of(cqp, struct i40iw_device, cqp);
+
+       if (cqp_request->waiting) {
+               cqp_request->compl_info.error = true;
+               cqp_request->request_done = true;
+               wake_up(&cqp_request->waitq);
+       }
+       i40iw_put_cqp_request(cqp, cqp_request);
+       wait_event_timeout(iwdev->close_wq,
+                          !atomic_read(&cqp_request->refcount),
+                          1000);
+}
+
+/**
+ * i40iw_cleanup_pending_cqp_op - clean-up cqp with no completions
+ * @iwdev: iwarp device
+ */
+void i40iw_cleanup_pending_cqp_op(struct i40iw_device *iwdev)
+{
+       struct i40iw_sc_dev *dev = &iwdev->sc_dev;
+       struct i40iw_cqp *cqp = &iwdev->cqp;
+       struct i40iw_cqp_request *cqp_request = NULL;
+       struct cqp_commands_info *pcmdinfo = NULL;
+       u32 i, pending_work, wqe_idx;
+
+       pending_work = I40IW_RING_WORK_AVAILABLE(cqp->sc_cqp.sq_ring);
+       wqe_idx = I40IW_RING_GETCURRENT_TAIL(cqp->sc_cqp.sq_ring);
+       for (i = 0; i < pending_work; i++) {
+               cqp_request = (struct i40iw_cqp_request *)(unsigned long)cqp->scratch_array[wqe_idx];
+               if (cqp_request)
+                       i40iw_free_pending_cqp_request(cqp, cqp_request);
+               wqe_idx = (wqe_idx + 1) % I40IW_RING_GETSIZE(cqp->sc_cqp.sq_ring);
+       }
+
+       while (!list_empty(&dev->cqp_cmd_head)) {
+               pcmdinfo = (struct cqp_commands_info *)i40iw_remove_head(&dev->cqp_cmd_head);
+               cqp_request = container_of(pcmdinfo, struct i40iw_cqp_request, info);
+               if (cqp_request)
+                       i40iw_free_pending_cqp_request(cqp, cqp_request);
+       }
+}
+
+/**
  * i40iw_free_qp - callback after destroy cqp completes
  * @cqp_request: cqp request for destroy qp
  * @num: not used
@@ -546,8 +598,12 @@ void i40iw_rem_ref(struct ib_qp *ibqp)
        cqp_info->in.u.qp_destroy.scratch = (uintptr_t)cqp_request;
        cqp_info->in.u.qp_destroy.remove_hash_idx = true;
        status = i40iw_handle_cqp_op(iwdev, cqp_request);
-       if (status)
-               i40iw_pr_err("CQP-OP Destroy QP fail");
+       if (!status)
+               return;
+
+       i40iw_rem_pdusecount(iwqp->iwpd, iwdev);
+       i40iw_free_qp_resources(iwdev, iwqp, qp_num);
+       i40iw_rem_devusecount(iwdev);
 }
 
 /**
index 4dbe61e..02d871d 100644 (file)
@@ -426,9 +426,13 @@ void i40iw_free_qp_resources(struct i40iw_device *iwdev,
                             struct i40iw_qp *iwqp,
                             u32 qp_num)
 {
+       struct i40iw_pbl *iwpbl = &iwqp->iwpbl;
+
        i40iw_dealloc_push_page(iwdev, &iwqp->sc_qp);
        if (qp_num)
                i40iw_free_resource(iwdev, iwdev->allocated_qps, qp_num);
+       if (iwpbl->pbl_allocated)
+               i40iw_free_pble(iwdev->pble_rsrc, &iwpbl->pble_alloc);
        i40iw_free_dma_mem(iwdev->sc_dev.hw, &iwqp->q2_ctx_mem);
        i40iw_free_dma_mem(iwdev->sc_dev.hw, &iwqp->kqp.dma_mem);
        kfree(iwqp->kqp.wrid_mem);
@@ -483,7 +487,7 @@ static int i40iw_setup_virt_qp(struct i40iw_device *iwdev,
                               struct i40iw_qp *iwqp,
                               struct i40iw_qp_init_info *init_info)
 {
-       struct i40iw_pbl *iwpbl = iwqp->iwpbl;
+       struct i40iw_pbl *iwpbl = &iwqp->iwpbl;
        struct i40iw_qp_mr *qpmr = &iwpbl->qp_mr;
 
        iwqp->page = qpmr->sq_page;
@@ -688,19 +692,22 @@ static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd,
                        ucontext = to_ucontext(ibpd->uobject->context);
 
                        if (req.user_wqe_buffers) {
+                               struct i40iw_pbl *iwpbl;
+
                                spin_lock_irqsave(
                                    &ucontext->qp_reg_mem_list_lock, flags);
-                               iwqp->iwpbl = i40iw_get_pbl(
+                               iwpbl = i40iw_get_pbl(
                                    (unsigned long)req.user_wqe_buffers,
                                    &ucontext->qp_reg_mem_list);
                                spin_unlock_irqrestore(
                                    &ucontext->qp_reg_mem_list_lock, flags);
 
-                               if (!iwqp->iwpbl) {
+                               if (!iwpbl) {
                                        err_code = -ENODATA;
                                        i40iw_pr_err("no pbl info\n");
                                        goto error;
                                }
+                               memcpy(&iwqp->iwpbl, iwpbl, sizeof(iwqp->iwpbl));
                        }
                }
                err_code = i40iw_setup_virt_qp(iwdev, iwqp, &init_info);
@@ -1161,8 +1168,10 @@ static struct ib_cq *i40iw_create_cq(struct ib_device *ibdev,
                memset(&req, 0, sizeof(req));
                iwcq->user_mode = true;
                ucontext = to_ucontext(context);
-               if (ib_copy_from_udata(&req, udata, sizeof(struct i40iw_create_cq_req)))
+               if (ib_copy_from_udata(&req, udata, sizeof(struct i40iw_create_cq_req))) {
+                       err_code = -EFAULT;
                        goto cq_free_resources;
+               }
 
                spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
                iwpbl = i40iw_get_pbl((unsigned long)req.user_cq_buffer,
@@ -2063,7 +2072,7 @@ static int i40iw_dereg_mr(struct ib_mr *ib_mr)
                        ucontext = to_ucontext(ibpd->uobject->context);
                        i40iw_del_memlist(iwmr, ucontext);
                }
-               if (iwpbl->pbl_allocated)
+               if (iwpbl->pbl_allocated && iwmr->type != IW_MEMREG_TYPE_QP)
                        i40iw_free_pble(iwdev->pble_rsrc, palloc);
                kfree(iwmr);
                return 0;
index 07c3fec..9067443 100644 (file)
@@ -170,7 +170,7 @@ struct i40iw_qp {
        struct i40iw_qp_kmode kqp;
        struct i40iw_dma_mem host_ctx;
        struct timer_list terminate_timer;
-       struct i40iw_pbl *iwpbl;
+       struct i40iw_pbl iwpbl;
        struct i40iw_dma_mem q2_ctx_mem;
        struct i40iw_dma_mem ietf_mem;
        struct completion sq_drained;
index 1e6c526..fedaf82 100644 (file)
@@ -323,6 +323,9 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id
                        mad->mad_hdr.attr_id == CM_REP_ATTR_ID ||
                        mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
                sl_cm_id = get_local_comm_id(mad);
+               id = id_map_get(ibdev, &pv_cm_id, slave_id, sl_cm_id);
+               if (id)
+                       goto cont;
                id = id_map_alloc(ibdev, slave_id, sl_cm_id);
                if (IS_ERR(id)) {
                        mlx4_ib_warn(ibdev, "%s: id{slave: %d, sl_cm_id: 0x%x} Failed to id_map_alloc\n",
@@ -343,6 +346,7 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id
                return -EINVAL;
        }
 
+cont:
        set_local_comm_id(mad, id->pv_cm_id);
 
        if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID)
index 4f5a143..ff931c5 100644 (file)
@@ -102,7 +102,7 @@ static int mlx4_ib_alloc_cq_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq_buf *
        int err;
 
        err = mlx4_buf_alloc(dev->dev, nent * dev->dev->caps.cqe_size,
-                            PAGE_SIZE * 2, &buf->buf, GFP_KERNEL);
+                            PAGE_SIZE * 2, &buf->buf);
 
        if (err)
                goto out;
@@ -113,7 +113,7 @@ static int mlx4_ib_alloc_cq_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq_buf *
        if (err)
                goto err_buf;
 
-       err = mlx4_buf_write_mtt(dev->dev, &buf->mtt, &buf->buf, GFP_KERNEL);
+       err = mlx4_buf_write_mtt(dev->dev, &buf->mtt, &buf->buf);
        if (err)
                goto err_mtt;
 
@@ -219,7 +219,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev,
 
                uar = &to_mucontext(context)->uar;
        } else {
-               err = mlx4_db_alloc(dev->dev, &cq->db, 1, GFP_KERNEL);
+               err = mlx4_db_alloc(dev->dev, &cq->db, 1);
                if (err)
                        goto err_cq;
 
index 75b2f7d..d1b43cb 100644 (file)
@@ -1155,7 +1155,7 @@ static void mlx4_ib_disassociate_ucontext(struct ib_ucontext *ibcontext)
                         * call to mlx4_ib_vma_close.
                         */
                        put_task_struct(owning_process);
-                       msleep(1);
+                       usleep_range(1000, 2000);
                        owning_process = get_pid_task(ibcontext->tgid,
                                                      PIDTYPE_PID);
                        if (!owning_process ||
index 3405e94..b73f897 100644 (file)
@@ -1091,7 +1091,7 @@ static void _mlx4_ib_mcg_port_cleanup(struct mlx4_ib_demux_ctx *ctx, int destroy
                if (!count)
                        break;
 
-               msleep(1);
+               usleep_range(1000, 2000);
        } while (time_after(end, jiffies));
 
        flush_workqueue(ctx->mcg_wq);
index c2b9cbf..9db82e6 100644 (file)
@@ -185,7 +185,6 @@ enum mlx4_ib_qp_flags {
        MLX4_IB_QP_LSO = IB_QP_CREATE_IPOIB_UD_LSO,
        MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK = IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK,
        MLX4_IB_QP_NETIF = IB_QP_CREATE_NETIF_QP,
-       MLX4_IB_QP_CREATE_USE_GFP_NOIO = IB_QP_CREATE_USE_GFP_NOIO,
 
        /* Mellanox specific flags start from IB_QP_CREATE_RESERVED_START */
        MLX4_IB_ROCE_V2_GSI_QP = MLX4_IB_QP_CREATE_ROCE_V2_GSI,
index 996e905..75c0e6c 100644 (file)
@@ -634,8 +634,8 @@ static void mlx4_ib_free_qp_counter(struct mlx4_ib_dev *dev,
 
 static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                            struct ib_qp_init_attr *init_attr,
-                           struct ib_udata *udata, int sqpn, struct mlx4_ib_qp **caller_qp,
-                           gfp_t gfp)
+                           struct ib_udata *udata, int sqpn,
+                           struct mlx4_ib_qp **caller_qp)
 {
        int qpn;
        int err;
@@ -691,14 +691,14 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                if (qp_type == MLX4_IB_QPT_SMI || qp_type == MLX4_IB_QPT_GSI ||
                    (qp_type & (MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_SMI_OWNER |
                                MLX4_IB_QPT_PROXY_GSI | MLX4_IB_QPT_TUN_SMI_OWNER))) {
-                       sqp = kzalloc(sizeof (struct mlx4_ib_sqp), gfp);
+                       sqp = kzalloc(sizeof(struct mlx4_ib_sqp), GFP_KERNEL);
                        if (!sqp)
                                return -ENOMEM;
                        qp = &sqp->qp;
                        qp->pri.vid = 0xFFFF;
                        qp->alt.vid = 0xFFFF;
                } else {
-                       qp = kzalloc(sizeof (struct mlx4_ib_qp), gfp);
+                       qp = kzalloc(sizeof(struct mlx4_ib_qp), GFP_KERNEL);
                        if (!qp)
                                return -ENOMEM;
                        qp->pri.vid = 0xFFFF;
@@ -780,7 +780,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                        goto err;
 
                if (qp_has_rq(init_attr)) {
-                       err = mlx4_db_alloc(dev->dev, &qp->db, 0, gfp);
+                       err = mlx4_db_alloc(dev->dev, &qp->db, 0);
                        if (err)
                                goto err;
 
@@ -788,7 +788,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                }
 
                if (mlx4_buf_alloc(dev->dev, qp->buf_size, qp->buf_size,
-                                  &qp->buf, gfp)) {
+                                  &qp->buf)) {
                        memcpy(&init_attr->cap, &backup_cap,
                               sizeof(backup_cap));
                        err = set_kernel_sq_size(dev, &init_attr->cap, qp_type,
@@ -797,7 +797,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                                goto err_db;
 
                        if (mlx4_buf_alloc(dev->dev, qp->buf_size,
-                                          PAGE_SIZE * 2, &qp->buf, gfp)) {
+                                          PAGE_SIZE * 2, &qp->buf)) {
                                err = -ENOMEM;
                                goto err_db;
                        }
@@ -808,20 +808,20 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                if (err)
                        goto err_buf;
 
-               err = mlx4_buf_write_mtt(dev->dev, &qp->mtt, &qp->buf, gfp);
+               err = mlx4_buf_write_mtt(dev->dev, &qp->mtt, &qp->buf);
                if (err)
                        goto err_mtt;
 
                qp->sq.wrid = kmalloc_array(qp->sq.wqe_cnt, sizeof(u64),
-                                       gfp | __GFP_NOWARN);
+                                       GFP_KERNEL | __GFP_NOWARN);
                if (!qp->sq.wrid)
                        qp->sq.wrid = __vmalloc(qp->sq.wqe_cnt * sizeof(u64),
-                                               gfp, PAGE_KERNEL);
+                                               GFP_KERNEL, PAGE_KERNEL);
                qp->rq.wrid = kmalloc_array(qp->rq.wqe_cnt, sizeof(u64),
-                                       gfp | __GFP_NOWARN);
+                                       GFP_KERNEL | __GFP_NOWARN);
                if (!qp->rq.wrid)
                        qp->rq.wrid = __vmalloc(qp->rq.wqe_cnt * sizeof(u64),
-                                               gfp, PAGE_KERNEL);
+                                               GFP_KERNEL, PAGE_KERNEL);
                if (!qp->sq.wrid || !qp->rq.wrid) {
                        err = -ENOMEM;
                        goto err_wrid;
@@ -859,7 +859,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
        if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)
                qp->flags |= MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK;
 
-       err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp, gfp);
+       err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp);
        if (err)
                goto err_qpn;
 
@@ -1127,10 +1127,7 @@ static struct ib_qp *_mlx4_ib_create_qp(struct ib_pd *pd,
        int err;
        int sup_u_create_flags = MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK;
        u16 xrcdn = 0;
-       gfp_t gfp;
 
-       gfp = (init_attr->create_flags & MLX4_IB_QP_CREATE_USE_GFP_NOIO) ?
-               GFP_NOIO : GFP_KERNEL;
        /*
         * We only support LSO, vendor flag1, and multicast loopback blocking,
         * and only for kernel UD QPs.
@@ -1140,8 +1137,7 @@ static struct ib_qp *_mlx4_ib_create_qp(struct ib_pd *pd,
                                        MLX4_IB_SRIOV_TUNNEL_QP |
                                        MLX4_IB_SRIOV_SQP |
                                        MLX4_IB_QP_NETIF |
-                                       MLX4_IB_QP_CREATE_ROCE_V2_GSI |
-                                       MLX4_IB_QP_CREATE_USE_GFP_NOIO))
+                                       MLX4_IB_QP_CREATE_ROCE_V2_GSI))
                return ERR_PTR(-EINVAL);
 
        if (init_attr->create_flags & IB_QP_CREATE_NETIF_QP) {
@@ -1154,7 +1150,6 @@ static struct ib_qp *_mlx4_ib_create_qp(struct ib_pd *pd,
                        return ERR_PTR(-EINVAL);
 
                if ((init_attr->create_flags & ~(MLX4_IB_SRIOV_SQP |
-                                                MLX4_IB_QP_CREATE_USE_GFP_NOIO |
                                                 MLX4_IB_QP_CREATE_ROCE_V2_GSI  |
                                                 MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK) &&
                     init_attr->qp_type != IB_QPT_UD) ||
@@ -1179,7 +1174,7 @@ static struct ib_qp *_mlx4_ib_create_qp(struct ib_pd *pd,
        case IB_QPT_RC:
        case IB_QPT_UC:
        case IB_QPT_RAW_PACKET:
-               qp = kzalloc(sizeof *qp, gfp);
+               qp = kzalloc(sizeof(*qp), GFP_KERNEL);
                if (!qp)
                        return ERR_PTR(-ENOMEM);
                qp->pri.vid = 0xFFFF;
@@ -1188,7 +1183,7 @@ static struct ib_qp *_mlx4_ib_create_qp(struct ib_pd *pd,
        case IB_QPT_UD:
        {
                err = create_qp_common(to_mdev(pd->device), pd, init_attr,
-                                      udata, 0, &qp, gfp);
+                                      udata, 0, &qp);
                if (err) {
                        kfree(qp);
                        return ERR_PTR(err);
@@ -1217,8 +1212,7 @@ static struct ib_qp *_mlx4_ib_create_qp(struct ib_pd *pd,
                }
 
                err = create_qp_common(to_mdev(pd->device), pd, init_attr, udata,
-                                      sqpn,
-                                      &qp, gfp);
+                                      sqpn, &qp);
                if (err)
                        return ERR_PTR(err);
 
index e32dd58..0facaf5 100644 (file)
@@ -135,14 +135,14 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
                if (err)
                        goto err_mtt;
        } else {
-               err = mlx4_db_alloc(dev->dev, &srq->db, 0, GFP_KERNEL);
+               err = mlx4_db_alloc(dev->dev, &srq->db, 0);
                if (err)
                        goto err_srq;
 
                *srq->db.db = 0;
 
-               if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &srq->buf,
-                                  GFP_KERNEL)) {
+               if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2,
+                                  &srq->buf)) {
                        err = -ENOMEM;
                        goto err_db;
                }
@@ -167,7 +167,7 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
                if (err)
                        goto err_buf;
 
-               err = mlx4_buf_write_mtt(dev->dev, &srq->mtt, &srq->buf, GFP_KERNEL);
+               err = mlx4_buf_write_mtt(dev->dev, &srq->mtt, &srq->buf);
                if (err)
                        goto err_mtt;
 
index 763bb5b..2c40a2e 100644 (file)
@@ -582,6 +582,15 @@ static void clean_keys(struct mlx5_ib_dev *dev, int c)
        }
 }
 
+static void mlx5_mr_cache_debugfs_cleanup(struct mlx5_ib_dev *dev)
+{
+       if (!mlx5_debugfs_root)
+               return;
+
+       debugfs_remove_recursive(dev->cache.root);
+       dev->cache.root = NULL;
+}
+
 static int mlx5_mr_cache_debugfs_init(struct mlx5_ib_dev *dev)
 {
        struct mlx5_mr_cache *cache = &dev->cache;
@@ -600,38 +609,34 @@ static int mlx5_mr_cache_debugfs_init(struct mlx5_ib_dev *dev)
                sprintf(ent->name, "%d", ent->order);
                ent->dir = debugfs_create_dir(ent->name,  cache->root);
                if (!ent->dir)
-                       return -ENOMEM;
+                       goto err;
 
                ent->fsize = debugfs_create_file("size", 0600, ent->dir, ent,
                                                 &size_fops);
                if (!ent->fsize)
-                       return -ENOMEM;
+                       goto err;
 
                ent->flimit = debugfs_create_file("limit", 0600, ent->dir, ent,
                                                  &limit_fops);
                if (!ent->flimit)
-                       return -ENOMEM;
+                       goto err;
 
                ent->fcur = debugfs_create_u32("cur", 0400, ent->dir,
                                               &ent->cur);
                if (!ent->fcur)
-                       return -ENOMEM;
+                       goto err;
 
                ent->fmiss = debugfs_create_u32("miss", 0600, ent->dir,
                                                &ent->miss);
                if (!ent->fmiss)
-                       return -ENOMEM;
+                       goto err;
        }
 
        return 0;
-}
-
-static void mlx5_mr_cache_debugfs_cleanup(struct mlx5_ib_dev *dev)
-{
-       if (!mlx5_debugfs_root)
-               return;
+err:
+       mlx5_mr_cache_debugfs_cleanup(dev);
 
-       debugfs_remove_recursive(dev->cache.root);
+       return -ENOMEM;
 }
 
 static void delay_time_func(unsigned long ctx)
@@ -692,6 +697,11 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev)
        if (err)
                mlx5_ib_warn(dev, "cache debugfs failure\n");
 
+       /*
+        * We don't want to fail driver if debugfs failed to initialize,
+        * so we are not forwarding error to the user.
+        */
+
        return 0;
 }
 
@@ -825,7 +835,7 @@ static int mr_umem_get(struct ib_pd *pd, u64 start, u64 length,
                            access_flags, 0);
        err = PTR_ERR_OR_ZERO(*umem);
        if (err < 0) {
-               mlx5_ib_err(dev, "umem get failed (%ld)\n", PTR_ERR(umem));
+               mlx5_ib_err(dev, "umem get failed (%d)\n", err);
                return err;
        }
 
@@ -1779,7 +1789,7 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr,
        mr->ndescs = sg_nents;
 
        for_each_sg(sgl, sg, sg_nents, i) {
-               if (unlikely(i > mr->max_descs))
+               if (unlikely(i >= mr->max_descs))
                        break;
                klms[i].va = cpu_to_be64(sg_dma_address(sg) + sg_offset);
                klms[i].bcount = cpu_to_be32(sg_dma_len(sg) - sg_offset);
index 8f9d8b4..b0adf65 100644 (file)
@@ -551,7 +551,7 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
                        if ((0x0F000100 == (pcs_control_status0 & 0x0F000100))
                            || (0x0F000100 == (pcs_control_status1 & 0x0F000100)))
                                int_cnt++;
-                       msleep(1);
+                       usleep_range(1000, 2000);
                }
                if (int_cnt > 1) {
                        spin_lock_irqsave(&nesadapter->phy_lock, flags);
@@ -592,7 +592,7 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
                                                break;
                                        }
                                }
-                               msleep(1);
+                               usleep_range(1000, 2000);
                        }
                }
        }
index 2f30bda..27d5e8d 100644 (file)
@@ -744,7 +744,8 @@ err:
        if (is_uctx_pd) {
                ocrdma_release_ucontext_pd(uctx);
        } else {
-               status = _ocrdma_dealloc_pd(dev, pd);
+               if (_ocrdma_dealloc_pd(dev, pd))
+                       pr_err("%s: _ocrdma_dealloc_pd() failed\n", __func__);
        }
 exit:
        return ERR_PTR(status);
@@ -1901,6 +1902,7 @@ struct ib_srq *ocrdma_create_srq(struct ib_pd *ibpd,
                goto err;
 
        if (udata == NULL) {
+               status = -ENOMEM;
                srq->rqe_wr_id_tbl = kzalloc(sizeof(u64) * srq->rq.max_cnt,
                            GFP_KERNEL);
                if (srq->rqe_wr_id_tbl == NULL)
index 548e4d1..2ae71b8 100644 (file)
 
 #define DB_ADDR_SHIFT(addr)            ((addr) << DB_PWM_ADDR_OFFSET_SHIFT)
 
+static inline int qedr_ib_copy_to_udata(struct ib_udata *udata, void *src,
+                                       size_t len)
+{
+       size_t min_len = min_t(size_t, len, udata->outlen);
+
+       return ib_copy_to_udata(udata, src, min_len);
+}
+
 int qedr_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
 {
        if (index > QEDR_ROCE_PKEY_TABLE_LEN)
@@ -378,7 +386,7 @@ struct ib_ucontext *qedr_alloc_ucontext(struct ib_device *ibdev,
        uresp.sges_per_srq_wr = dev->attr.max_srq_sge;
        uresp.max_cqes = QEDR_MAX_CQES;
 
-       rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+       rc = qedr_ib_copy_to_udata(udata, &uresp, sizeof(uresp));
        if (rc)
                goto err;
 
@@ -499,7 +507,7 @@ struct ib_pd *qedr_alloc_pd(struct ib_device *ibdev,
 
                uresp.pd_id = pd_id;
 
-               rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+               rc = qedr_ib_copy_to_udata(udata, &uresp, sizeof(uresp));
                if (rc) {
                        DP_ERR(dev, "copy error pd_id=0x%x.\n", pd_id);
                        dev->ops->rdma_dealloc_pd(dev->rdma_ctx, pd_id);
@@ -729,7 +737,7 @@ static int qedr_copy_cq_uresp(struct qedr_dev *dev,
        uresp.db_offset = DB_ADDR_SHIFT(DQ_PWM_OFFSET_UCM_RDMA_CQ_CONS_32BIT);
        uresp.icid = cq->icid;
 
-       rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+       rc = qedr_ib_copy_to_udata(udata, &uresp, sizeof(uresp));
        if (rc)
                DP_ERR(dev, "copy error cqid=0x%x.\n", cq->icid);
 
@@ -1238,7 +1246,7 @@ static int qedr_copy_qp_uresp(struct qedr_dev *dev,
        uresp.atomic_supported = dev->atomic_cap != IB_ATOMIC_NONE;
        uresp.qp_id = qp->qp_id;
 
-       rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+       rc = qedr_ib_copy_to_udata(udata, &uresp, sizeof(uresp));
        if (rc)
                DP_ERR(dev,
                       "create qp: failed a copy to user space with qp icid=0x%x.\n",
index 5984981..a343e3b 100644 (file)
@@ -104,10 +104,9 @@ const struct rvt_operation_params qib_post_parms[RVT_OPERATION_MAX] = {
 
 };
 
-static void get_map_page(struct rvt_qpn_table *qpt, struct rvt_qpn_map *map,
-                        gfp_t gfp)
+static void get_map_page(struct rvt_qpn_table *qpt, struct rvt_qpn_map *map)
 {
-       unsigned long page = get_zeroed_page(gfp);
+       unsigned long page = get_zeroed_page(GFP_KERNEL);
 
        /*
         * Free the page if someone raced with us installing it.
@@ -126,7 +125,7 @@ static void get_map_page(struct rvt_qpn_table *qpt, struct rvt_qpn_map *map,
  * zero/one for QP type IB_QPT_SMI/IB_QPT_GSI.
  */
 int qib_alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt,
-                 enum ib_qp_type type, u8 port, gfp_t gfp)
+                 enum ib_qp_type type, u8 port)
 {
        u32 i, offset, max_scan, qpn;
        struct rvt_qpn_map *map;
@@ -160,7 +159,7 @@ int qib_alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt,
        max_scan = qpt->nmaps - !offset;
        for (i = 0;;) {
                if (unlikely(!map->page)) {
-                       get_map_page(qpt, map, gfp);
+                       get_map_page(qpt, map);
                        if (unlikely(!map->page))
                                break;
                }
@@ -317,16 +316,16 @@ u32 qib_mtu_from_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, u32 pmtu)
        return ib_mtu_enum_to_int(pmtu);
 }
 
-void *qib_qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp, gfp_t gfp)
+void *qib_qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp)
 {
        struct qib_qp_priv *priv;
 
-       priv = kzalloc(sizeof(*priv), gfp);
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return ERR_PTR(-ENOMEM);
        priv->owner = qp;
 
-       priv->s_hdr = kzalloc(sizeof(*priv->s_hdr), gfp);
+       priv->s_hdr = kzalloc(sizeof(*priv->s_hdr), GFP_KERNEL);
        if (!priv->s_hdr) {
                kfree(priv);
                return ERR_PTR(-ENOMEM);
index da0db54..a52fc67 100644 (file)
@@ -274,11 +274,11 @@ int qib_get_counters(struct qib_pportdata *ppd,
  * Functions provided by qib driver for rdmavt to use
  */
 unsigned qib_free_all_qps(struct rvt_dev_info *rdi);
-void *qib_qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp, gfp_t gfp);
+void *qib_qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp);
 void qib_qp_priv_free(struct rvt_dev_info *rdi, struct rvt_qp *qp);
 void qib_notify_qp_reset(struct rvt_qp *qp);
 int qib_alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt,
-                 enum ib_qp_type type, u8 port, gfp_t gfp);
+                 enum ib_qp_type type, u8 port);
 void qib_restart_rc(struct rvt_qp *qp, u32 psn, int wait);
 #ifdef CONFIG_DEBUG_FS
 
index 727e81c..8876ee7 100644 (file)
@@ -118,10 +118,9 @@ const int ib_rvt_state_ops[IB_QPS_ERR + 1] = {
 EXPORT_SYMBOL(ib_rvt_state_ops);
 
 static void get_map_page(struct rvt_qpn_table *qpt,
-                        struct rvt_qpn_map *map,
-                        gfp_t gfp)
+                        struct rvt_qpn_map *map)
 {
-       unsigned long page = get_zeroed_page(gfp);
+       unsigned long page = get_zeroed_page(GFP_KERNEL);
 
        /*
         * Free the page if someone raced with us installing it.
@@ -173,7 +172,7 @@ static int init_qpn_table(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt)
                    rdi->dparms.qpn_res_start, rdi->dparms.qpn_res_end);
        for (i = rdi->dparms.qpn_res_start; i <= rdi->dparms.qpn_res_end; i++) {
                if (!map->page) {
-                       get_map_page(qpt, map, GFP_KERNEL);
+                       get_map_page(qpt, map);
                        if (!map->page) {
                                ret = -ENOMEM;
                                break;
@@ -342,14 +341,14 @@ static inline unsigned mk_qpn(struct rvt_qpn_table *qpt,
  * Return: The queue pair number
  */
 static int alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt,
-                    enum ib_qp_type type, u8 port_num, gfp_t gfp)
+                    enum ib_qp_type type, u8 port_num)
 {
        u32 i, offset, max_scan, qpn;
        struct rvt_qpn_map *map;
        u32 ret;
 
        if (rdi->driver_f.alloc_qpn)
-               return rdi->driver_f.alloc_qpn(rdi, qpt, type, port_num, gfp);
+               return rdi->driver_f.alloc_qpn(rdi, qpt, type, port_num);
 
        if (type == IB_QPT_SMI || type == IB_QPT_GSI) {
                unsigned n;
@@ -374,7 +373,7 @@ static int alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt,
        max_scan = qpt->nmaps - !offset;
        for (i = 0;;) {
                if (unlikely(!map->page)) {
-                       get_map_page(qpt, map, gfp);
+                       get_map_page(qpt, map);
                        if (unlikely(!map->page))
                                break;
                }
@@ -672,7 +671,6 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
        struct ib_qp *ret = ERR_PTR(-ENOMEM);
        struct rvt_dev_info *rdi = ib_to_rvt(ibpd->device);
        void *priv = NULL;
-       gfp_t gfp;
        size_t sqsize;
 
        if (!rdi)
@@ -680,18 +678,9 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
 
        if (init_attr->cap.max_send_sge > rdi->dparms.props.max_sge ||
            init_attr->cap.max_send_wr > rdi->dparms.props.max_qp_wr ||
-           init_attr->create_flags & ~(IB_QP_CREATE_USE_GFP_NOIO))
+           init_attr->create_flags)
                return ERR_PTR(-EINVAL);
 
-       /* GFP_NOIO is applicable to RC QP's only */
-
-       if (init_attr->create_flags & IB_QP_CREATE_USE_GFP_NOIO &&
-           init_attr->qp_type != IB_QPT_RC)
-               return ERR_PTR(-EINVAL);
-
-       gfp = init_attr->create_flags & IB_QP_CREATE_USE_GFP_NOIO ?
-                                               GFP_NOIO : GFP_KERNEL;
-
        /* Check receive queue parameters if no SRQ is specified. */
        if (!init_attr->srq) {
                if (init_attr->cap.max_recv_sge > rdi->dparms.props.max_sge ||
@@ -719,14 +708,7 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
                sz = sizeof(struct rvt_sge) *
                        init_attr->cap.max_send_sge +
                        sizeof(struct rvt_swqe);
-               if (gfp == GFP_NOIO)
-                       swq = __vmalloc(
-                               sqsize * sz,
-                               gfp | __GFP_ZERO, PAGE_KERNEL);
-               else
-                       swq = vzalloc_node(
-                               sqsize * sz,
-                               rdi->dparms.node);
+               swq = vzalloc_node(sqsize * sz, rdi->dparms.node);
                if (!swq)
                        return ERR_PTR(-ENOMEM);
 
@@ -741,7 +723,8 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
                } else if (init_attr->cap.max_recv_sge > 1)
                        sg_list_sz = sizeof(*qp->r_sg_list) *
                                (init_attr->cap.max_recv_sge - 1);
-               qp = kzalloc_node(sz + sg_list_sz, gfp, rdi->dparms.node);
+               qp = kzalloc_node(sz + sg_list_sz, GFP_KERNEL,
+                                 rdi->dparms.node);
                if (!qp)
                        goto bail_swq;
 
@@ -751,7 +734,7 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
                                kzalloc_node(
                                        sizeof(*qp->s_ack_queue) *
                                         rvt_max_atomic(rdi),
-                                       gfp,
+                                       GFP_KERNEL,
                                        rdi->dparms.node);
                        if (!qp->s_ack_queue)
                                goto bail_qp;
@@ -766,7 +749,7 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
                 * Driver needs to set up it's private QP structure and do any
                 * initialization that is needed.
                 */
-               priv = rdi->driver_f.qp_priv_alloc(rdi, qp, gfp);
+               priv = rdi->driver_f.qp_priv_alloc(rdi, qp);
                if (IS_ERR(priv)) {
                        ret = priv;
                        goto bail_qp;
@@ -786,11 +769,6 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
                                qp->r_rq.wq = vmalloc_user(
                                                sizeof(struct rvt_rwq) +
                                                qp->r_rq.size * sz);
-                       else if (gfp == GFP_NOIO)
-                               qp->r_rq.wq = __vmalloc(
-                                               sizeof(struct rvt_rwq) +
-                                               qp->r_rq.size * sz,
-                                               gfp | __GFP_ZERO, PAGE_KERNEL);
                        else
                                qp->r_rq.wq = vzalloc_node(
                                                sizeof(struct rvt_rwq) +
@@ -824,7 +802,7 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
 
                err = alloc_qpn(rdi, &rdi->qp_dev->qpn_table,
                                init_attr->qp_type,
-                               init_attr->port_num, gfp);
+                               init_attr->port_num);
                if (err < 0) {
                        ret = ERR_PTR(err);
                        goto bail_rq_wq;
@@ -1280,9 +1258,7 @@ int rvt_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
 
        if (attr_mask & IB_QP_TIMEOUT) {
                qp->timeout = attr->timeout;
-               qp->timeout_jiffies =
-                       usecs_to_jiffies((4096UL * (1UL << qp->timeout)) /
-                               1000UL);
+               qp->timeout_jiffies = rvt_timeout_to_jiffies(qp->timeout);
        }
 
        if (attr_mask & IB_QP_QKEY)
index c3a140e..08f3f90 100644 (file)
@@ -441,6 +441,8 @@ static void rxe_skb_tx_dtor(struct sk_buff *skb)
        if (unlikely(qp->need_req_skb &&
                     skb_out < RXE_INFLIGHT_SKBS_PER_QP_LOW))
                rxe_run_task(&qp->req.task, 1);
+
+       rxe_drop_ref(qp);
 }
 
 int rxe_send(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, struct sk_buff *skb)
@@ -473,6 +475,7 @@ int rxe_send(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, struct sk_buff *skb)
                return -EAGAIN;
        }
 
+       rxe_add_ref(pkt->qp);
        atomic_inc(&pkt->qp->skb_out);
        kfree_skb(skb);
 
index 2303976..a958ee9 100644 (file)
@@ -995,7 +995,9 @@ static int send_atomic_ack(struct rxe_qp *qp, struct rxe_pkt_info *pkt,
        free_rd_atomic_resource(qp, res);
        rxe_advance_resp_resource(qp);
 
-       memcpy(SKB_TO_PKT(skb), &ack_pkt, sizeof(skb->cb));
+       memcpy(SKB_TO_PKT(skb), &ack_pkt, sizeof(ack_pkt));
+       memset((unsigned char *)SKB_TO_PKT(skb) + sizeof(ack_pkt), 0,
+              sizeof(skb->cb) - sizeof(ack_pkt));
 
        res->type = RXE_ATOMIC_MASK;
        res->atomic.skb = skb;
@@ -1217,6 +1219,9 @@ void rxe_drain_req_pkts(struct rxe_qp *qp, bool notify)
                kfree_skb(skb);
        }
 
+       if (notify)
+               return;
+
        while (!qp->srq && qp->rq.queue && queue_head(qp->rq.queue))
                advance_consumer(qp->rq.queue);
 }
index 073e667..af90a7d 100644 (file)
@@ -914,6 +914,9 @@ static int rxe_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
 
        spin_unlock_irqrestore(&rq->producer_lock, flags);
 
+       if (qp->resp.state == QP_STATE_ERROR)
+               rxe_run_task(&qp->resp.task, 1);
+
 err1:
        return err;
 }
@@ -1240,6 +1243,8 @@ int rxe_register_device(struct rxe_dev *rxe)
        addrconf_addr_eui48((unsigned char *)&dev->node_guid,
                            rxe->ndev->dev_addr);
        dev->dev.dma_ops = &dma_virt_ops;
+       dma_coerce_mask_and_coherent(&dev->dev,
+                                    dma_get_required_mask(dev->dev.parent));
 
        dev->uverbs_abi_ver = RXE_UVERBS_ABI_VERSION;
        dev->uverbs_cmd_mask = BIT_ULL(IB_USER_VERBS_CMD_GET_CONTEXT)
index 7cbcfda..f87d104 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
 #include <linux/sched/signal.h>
+#include <linux/sched/mm.h>
 
 #include "ipoib.h"
 
@@ -954,7 +955,7 @@ void ipoib_cm_dev_stop(struct net_device *dev)
                        break;
                }
                spin_unlock_irq(&priv->lock);
-               msleep(1);
+               usleep_range(1000, 2000);
                ipoib_drain_cq(dev);
                spin_lock_irq(&priv->lock);
        }
@@ -1047,9 +1048,8 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
                .sq_sig_type            = IB_SIGNAL_ALL_WR,
                .qp_type                = IB_QPT_RC,
                .qp_context             = tx,
-               .create_flags           = IB_QP_CREATE_USE_GFP_NOIO
+               .create_flags           = 0
        };
-
        struct ib_qp *tx_qp;
 
        if (dev->features & NETIF_F_SG)
@@ -1057,10 +1057,6 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
                        min_t(u32, priv->ca->attrs.max_sge, MAX_SKB_FRAGS + 1);
 
        tx_qp = ib_create_qp(priv->pd, &attr);
-       if (PTR_ERR(tx_qp) == -EINVAL) {
-               attr.create_flags &= ~IB_QP_CREATE_USE_GFP_NOIO;
-               tx_qp = ib_create_qp(priv->pd, &attr);
-       }
        tx->max_send_sge = attr.cap.max_send_sge;
        return tx_qp;
 }
@@ -1131,10 +1127,11 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn,
                            struct sa_path_rec *pathrec)
 {
        struct ipoib_dev_priv *priv = ipoib_priv(p->dev);
+       unsigned int noio_flag;
        int ret;
 
-       p->tx_ring = __vmalloc(ipoib_sendq_size * sizeof *p->tx_ring,
-                              GFP_NOIO, PAGE_KERNEL);
+       noio_flag = memalloc_noio_save();
+       p->tx_ring = vzalloc(ipoib_sendq_size * sizeof(*p->tx_ring));
        if (!p->tx_ring) {
                ret = -ENOMEM;
                goto err_tx;
@@ -1142,9 +1139,10 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn,
        memset(p->tx_ring, 0, ipoib_sendq_size * sizeof *p->tx_ring);
 
        p->qp = ipoib_cm_create_tx_qp(p->dev, p);
+       memalloc_noio_restore(noio_flag);
        if (IS_ERR(p->qp)) {
                ret = PTR_ERR(p->qp);
-               ipoib_warn(priv, "failed to allocate tx qp: %d\n", ret);
+               ipoib_warn(priv, "failed to create tx qp: %d\n", ret);
                goto err_qp;
        }
 
@@ -1206,7 +1204,7 @@ static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p)
                                goto timeout;
                        }
 
-                       msleep(1);
+                       usleep_range(1000, 2000);
                }
        }
 
index efe7402..57a9655 100644 (file)
@@ -770,7 +770,7 @@ int ipoib_ib_dev_stop_default(struct net_device *dev)
 
                ipoib_drain_cq(dev);
 
-               msleep(1);
+               usleep_range(1000, 2000);
        }
 
        ipoib_dbg(priv, "All sends and receives done.\n");
index 6e86eee..4ce315c 100644 (file)
@@ -233,6 +233,7 @@ static netdev_features_t ipoib_fix_features(struct net_device *dev, netdev_featu
 static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct ipoib_dev_priv *priv = ipoib_priv(dev);
+       int ret = 0;
 
        /* dev->mtu > 2K ==> connected mode */
        if (ipoib_cm_admin_enabled(dev)) {
@@ -256,9 +257,34 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
                ipoib_dbg(priv, "MTU must be smaller than the underlying "
                                "link layer MTU - 4 (%u)\n", priv->mcast_mtu);
 
-       dev->mtu = min(priv->mcast_mtu, priv->admin_mtu);
+       new_mtu = min(priv->mcast_mtu, priv->admin_mtu);
 
-       return 0;
+       if (priv->rn_ops->ndo_change_mtu) {
+               bool carrier_status = netif_carrier_ok(dev);
+
+               netif_carrier_off(dev);
+
+               /* notify lower level on the real mtu */
+               ret = priv->rn_ops->ndo_change_mtu(dev, new_mtu);
+
+               if (carrier_status)
+                       netif_carrier_on(dev);
+       } else {
+               dev->mtu = new_mtu;
+       }
+
+       return ret;
+}
+
+static void ipoib_get_stats(struct net_device *dev,
+                           struct rtnl_link_stats64 *stats)
+{
+       struct ipoib_dev_priv *priv = ipoib_priv(dev);
+
+       if (priv->rn_ops->ndo_get_stats64)
+               priv->rn_ops->ndo_get_stats64(dev, stats);
+       else
+               netdev_stats_to_stats64(stats, &dev->stats);
 }
 
 /* Called with an RCU read lock taken */
@@ -1808,6 +1834,7 @@ static const struct net_device_ops ipoib_netdev_ops_pf = {
        .ndo_get_vf_stats        = ipoib_get_vf_stats,
        .ndo_set_vf_guid         = ipoib_set_vf_guid,
        .ndo_set_mac_address     = ipoib_set_mac,
+       .ndo_get_stats64         = ipoib_get_stats,
 };
 
 static const struct net_device_ops ipoib_netdev_ops_vf = {
@@ -2212,6 +2239,7 @@ static struct net_device *ipoib_add_port(const char *format,
                goto register_failed;
        }
 
+       result = -ENOMEM;
        if (ipoib_cm_add_mode_attr(priv->dev))
                goto sysfs_failed;
        if (ipoib_add_pkey_attr(priv->dev))
index 5a887ef..37b33d7 100644 (file)
@@ -83,6 +83,7 @@ static struct scsi_host_template iscsi_iser_sht;
 static struct iscsi_transport iscsi_iser_transport;
 static struct scsi_transport_template *iscsi_iser_scsi_transport;
 static struct workqueue_struct *release_wq;
+static DEFINE_MUTEX(unbind_iser_conn_mutex);
 struct iser_global ig;
 
 int iser_debug_level = 0;
@@ -550,12 +551,14 @@ iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
         */
        if (iser_conn) {
                mutex_lock(&iser_conn->state_mutex);
+               mutex_lock(&unbind_iser_conn_mutex);
                iser_conn_terminate(iser_conn);
                iscsi_conn_stop(cls_conn, flag);
 
                /* unbind */
                iser_conn->iscsi_conn = NULL;
                conn->dd_data = NULL;
+               mutex_unlock(&unbind_iser_conn_mutex);
 
                complete(&iser_conn->stop_completion);
                mutex_unlock(&iser_conn->state_mutex);
@@ -977,13 +980,21 @@ static int iscsi_iser_slave_alloc(struct scsi_device *sdev)
        struct iser_conn *iser_conn;
        struct ib_device *ib_dev;
 
+       mutex_lock(&unbind_iser_conn_mutex);
+
        session = starget_to_session(scsi_target(sdev))->dd_data;
        iser_conn = session->leadconn->dd_data;
+       if (!iser_conn) {
+               mutex_unlock(&unbind_iser_conn_mutex);
+               return -ENOTCONN;
+       }
        ib_dev = iser_conn->ib_conn.device->ib_device;
 
        if (!(ib_dev->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG))
                blk_queue_virt_boundary(sdev->request_queue, ~MASK_4K);
 
+       mutex_unlock(&unbind_iser_conn_mutex);
+
        return 0;
 }
 
index 12ed62c..2a07692 100644 (file)
@@ -137,8 +137,10 @@ iser_prepare_write_cmd(struct iscsi_task *task,
 
        if (unsol_sz < edtl) {
                hdr->flags     |= ISER_WSV;
-               hdr->write_stag = cpu_to_be32(mem_reg->rkey);
-               hdr->write_va   = cpu_to_be64(mem_reg->sge.addr + unsol_sz);
+               if (buf_out->data_len > imm_sz) {
+                       hdr->write_stag = cpu_to_be32(mem_reg->rkey);
+                       hdr->write_va = cpu_to_be64(mem_reg->sge.addr + unsol_sz);
+               }
 
                iser_dbg("Cmd itt:%d, WRITE tags, RKEY:%#.4X "
                         "VA:%#llX + unsol:%d\n",
index c538a38..26a004e 100644 (file)
@@ -708,8 +708,14 @@ iser_calc_scsi_params(struct iser_conn *iser_conn,
        unsigned short sg_tablesize, sup_sg_tablesize;
 
        sg_tablesize = DIV_ROUND_UP(max_sectors * 512, SIZE_4K);
-       sup_sg_tablesize = min_t(unsigned, ISCSI_ISER_MAX_SG_TABLESIZE,
-                                device->ib_device->attrs.max_fast_reg_page_list_len);
+       if (device->ib_device->attrs.device_cap_flags &
+                       IB_DEVICE_MEM_MGT_EXTENSIONS)
+               sup_sg_tablesize =
+                       min_t(
+                        uint, ISCSI_ISER_MAX_SG_TABLESIZE,
+                        device->ib_device->attrs.max_fast_reg_page_list_len);
+       else
+               sup_sg_tablesize = ISCSI_ISER_MAX_SG_TABLESIZE;
 
        iser_conn->scsi_sg_tablesize = min(sg_tablesize, sup_sg_tablesize);
 }
index fcbed35..0e66265 100644 (file)
@@ -1452,7 +1452,7 @@ static void
 isert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc)
 {
        struct isert_conn *isert_conn = wc->qp->qp_context;
-       struct ib_device *ib_dev = isert_conn->cm_id->device;
+       struct ib_device *ib_dev = isert_conn->device->ib_device;
 
        if (unlikely(wc->status != IB_WC_SUCCESS)) {
                isert_print_wc(wc, "login recv");
index 1ced073..402275b 100644 (file)
@@ -1157,8 +1157,8 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx)
        }
        spin_unlock_irqrestore(&ioctx->spinlock, flags);
 
-       pr_debug("Aborting cmd with state %d and tag %lld\n", state,
-                ioctx->cmd.tag);
+       pr_debug("Aborting cmd with state %d -> %d and tag %lld\n", state,
+                ioctx->state, ioctx->cmd.tag);
 
        switch (state) {
        case SRPT_STATE_NEW:
index da3d362..a047b9a 100644 (file)
@@ -48,6 +48,7 @@ struct gpio_button_data {
        spinlock_t lock;
        bool disabled;
        bool key_pressed;
+       bool suspended;
 };
 
 struct gpio_keys_drvdata {
@@ -396,8 +397,20 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
 
        BUG_ON(irq != bdata->irq);
 
-       if (bdata->button->wakeup)
+       if (bdata->button->wakeup) {
+               const struct gpio_keys_button *button = bdata->button;
+
                pm_stay_awake(bdata->input->dev.parent);
+               if (bdata->suspended  &&
+                   (button->type == 0 || button->type == EV_KEY)) {
+                       /*
+                        * Simulate wakeup key press in case the key has
+                        * already released by the time we got interrupt
+                        * handler to run.
+                        */
+                       input_report_key(bdata->input, button->code, 1);
+               }
+       }
 
        mod_delayed_work(system_wq,
                         &bdata->work,
@@ -855,6 +868,7 @@ static int __maybe_unused gpio_keys_suspend(struct device *dev)
                        struct gpio_button_data *bdata = &ddata->data[i];
                        if (bdata->button->wakeup)
                                enable_irq_wake(bdata->irq);
+                       bdata->suspended = true;
                }
        } else {
                mutex_lock(&input->mutex);
@@ -878,6 +892,7 @@ static int __maybe_unused gpio_keys_resume(struct device *dev)
                        struct gpio_button_data *bdata = &ddata->data[i];
                        if (bdata->button->wakeup)
                                disable_irq_wake(bdata->irq);
+                       bdata->suspended = false;
                }
        } else {
                mutex_lock(&input->mutex);
index eb77061..fa130e7 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/slab.h>
 
 #include <asm/xen/hypervisor.h>
 struct xenkbd_info {
        struct input_dev *kbd;
        struct input_dev *ptr;
+       struct input_dev *mtouch;
        struct xenkbd_page *page;
        int gref;
        int irq;
        struct xenbus_device *xbdev;
        char phys[32];
+       /* current MT slot/contact ID we are injecting events in */
+       int mtouch_cur_contact_id;
 };
 
 enum { KPARAM_X, KPARAM_Y, KPARAM_CNT };
@@ -56,6 +60,112 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *);
  * to do that.
  */
 
+static void xenkbd_handle_motion_event(struct xenkbd_info *info,
+                                      struct xenkbd_motion *motion)
+{
+       input_report_rel(info->ptr, REL_X, motion->rel_x);
+       input_report_rel(info->ptr, REL_Y, motion->rel_y);
+       if (motion->rel_z)
+               input_report_rel(info->ptr, REL_WHEEL, -motion->rel_z);
+       input_sync(info->ptr);
+}
+
+static void xenkbd_handle_position_event(struct xenkbd_info *info,
+                                        struct xenkbd_position *pos)
+{
+       input_report_abs(info->ptr, ABS_X, pos->abs_x);
+       input_report_abs(info->ptr, ABS_Y, pos->abs_y);
+       if (pos->rel_z)
+               input_report_rel(info->ptr, REL_WHEEL, -pos->rel_z);
+       input_sync(info->ptr);
+}
+
+static void xenkbd_handle_key_event(struct xenkbd_info *info,
+                                   struct xenkbd_key *key)
+{
+       struct input_dev *dev;
+
+       if (test_bit(key->keycode, info->ptr->keybit)) {
+               dev = info->ptr;
+       } else if (test_bit(key->keycode, info->kbd->keybit)) {
+               dev = info->kbd;
+       } else {
+               pr_warn("unhandled keycode 0x%x\n", key->keycode);
+               return;
+       }
+
+       input_report_key(dev, key->keycode, key->pressed);
+       input_sync(dev);
+}
+
+static void xenkbd_handle_mt_event(struct xenkbd_info *info,
+                                  struct xenkbd_mtouch *mtouch)
+{
+       if (unlikely(!info->mtouch))
+               return;
+
+       if (mtouch->contact_id != info->mtouch_cur_contact_id) {
+               info->mtouch_cur_contact_id = mtouch->contact_id;
+               input_mt_slot(info->mtouch, mtouch->contact_id);
+       }
+
+       switch (mtouch->event_type) {
+       case XENKBD_MT_EV_DOWN:
+               input_mt_report_slot_state(info->mtouch, MT_TOOL_FINGER, true);
+               /* fall through */
+
+       case XENKBD_MT_EV_MOTION:
+               input_report_abs(info->mtouch, ABS_MT_POSITION_X,
+                                mtouch->u.pos.abs_x);
+               input_report_abs(info->mtouch, ABS_MT_POSITION_Y,
+                                mtouch->u.pos.abs_y);
+               break;
+
+       case XENKBD_MT_EV_SHAPE:
+               input_report_abs(info->mtouch, ABS_MT_TOUCH_MAJOR,
+                                mtouch->u.shape.major);
+               input_report_abs(info->mtouch, ABS_MT_TOUCH_MINOR,
+                                mtouch->u.shape.minor);
+               break;
+
+       case XENKBD_MT_EV_ORIENT:
+               input_report_abs(info->mtouch, ABS_MT_ORIENTATION,
+                                mtouch->u.orientation);
+               break;
+
+       case XENKBD_MT_EV_UP:
+               input_mt_report_slot_state(info->mtouch, MT_TOOL_FINGER, false);
+               break;
+
+       case XENKBD_MT_EV_SYN:
+               input_mt_sync_frame(info->mtouch);
+               input_sync(info->mtouch);
+               break;
+       }
+}
+
+static void xenkbd_handle_event(struct xenkbd_info *info,
+                               union xenkbd_in_event *event)
+{
+       switch (event->type) {
+       case XENKBD_TYPE_MOTION:
+               xenkbd_handle_motion_event(info, &event->motion);
+               break;
+
+       case XENKBD_TYPE_KEY:
+               xenkbd_handle_key_event(info, &event->key);
+               break;
+
+       case XENKBD_TYPE_POS:
+               xenkbd_handle_position_event(info, &event->pos);
+               break;
+
+       case XENKBD_TYPE_MTOUCH:
+               xenkbd_handle_mt_event(info, &event->mtouch);
+               break;
+       }
+}
+
 static irqreturn_t input_handler(int rq, void *dev_id)
 {
        struct xenkbd_info *info = dev_id;
@@ -66,44 +176,8 @@ static irqreturn_t input_handler(int rq, void *dev_id)
        if (prod == page->in_cons)
                return IRQ_HANDLED;
        rmb();                  /* ensure we see ring contents up to prod */
-       for (cons = page->in_cons; cons != prod; cons++) {
-               union xenkbd_in_event *event;
-               struct input_dev *dev;
-               event = &XENKBD_IN_RING_REF(page, cons);
-
-               dev = info->ptr;
-               switch (event->type) {
-               case XENKBD_TYPE_MOTION:
-                       input_report_rel(dev, REL_X, event->motion.rel_x);
-                       input_report_rel(dev, REL_Y, event->motion.rel_y);
-                       if (event->motion.rel_z)
-                               input_report_rel(dev, REL_WHEEL,
-                                                -event->motion.rel_z);
-                       break;
-               case XENKBD_TYPE_KEY:
-                       dev = NULL;
-                       if (test_bit(event->key.keycode, info->kbd->keybit))
-                               dev = info->kbd;
-                       if (test_bit(event->key.keycode, info->ptr->keybit))
-                               dev = info->ptr;
-                       if (dev)
-                               input_report_key(dev, event->key.keycode,
-                                                event->key.pressed);
-                       else
-                               pr_warn("unhandled keycode 0x%x\n",
-                                       event->key.keycode);
-                       break;
-               case XENKBD_TYPE_POS:
-                       input_report_abs(dev, ABS_X, event->pos.abs_x);
-                       input_report_abs(dev, ABS_Y, event->pos.abs_y);
-                       if (event->pos.rel_z)
-                               input_report_rel(dev, REL_WHEEL,
-                                                -event->pos.rel_z);
-                       break;
-               }
-               if (dev)
-                       input_sync(dev);
-       }
+       for (cons = page->in_cons; cons != prod; cons++)
+               xenkbd_handle_event(info, &XENKBD_IN_RING_REF(page, cons));
        mb();                   /* ensure we got ring contents */
        page->in_cons = cons;
        notify_remote_via_irq(info->irq);
@@ -115,9 +189,9 @@ static int xenkbd_probe(struct xenbus_device *dev,
                                  const struct xenbus_device_id *id)
 {
        int ret, i;
-       unsigned int abs;
+       unsigned int abs, touch;
        struct xenkbd_info *info;
-       struct input_dev *kbd, *ptr;
+       struct input_dev *kbd, *ptr, *mtouch;
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info) {
@@ -152,6 +226,17 @@ static int xenkbd_probe(struct xenbus_device *dev,
                }
        }
 
+       touch = xenbus_read_unsigned(dev->nodename,
+                                    XENKBD_FIELD_FEAT_MTOUCH, 0);
+       if (touch) {
+               ret = xenbus_write(XBT_NIL, dev->nodename,
+                                  XENKBD_FIELD_REQ_MTOUCH, "1");
+               if (ret) {
+                       pr_warn("xenkbd: can't request multi-touch");
+                       touch = 0;
+               }
+       }
+
        /* keyboard */
        kbd = input_allocate_device();
        if (!kbd)
@@ -208,6 +293,58 @@ static int xenkbd_probe(struct xenbus_device *dev,
        }
        info->ptr = ptr;
 
+       /* multi-touch device */
+       if (touch) {
+               int num_cont, width, height;
+
+               mtouch = input_allocate_device();
+               if (!mtouch)
+                       goto error_nomem;
+
+               num_cont = xenbus_read_unsigned(info->xbdev->nodename,
+                                               XENKBD_FIELD_MT_NUM_CONTACTS,
+                                               1);
+               width = xenbus_read_unsigned(info->xbdev->nodename,
+                                            XENKBD_FIELD_MT_WIDTH,
+                                            XENFB_WIDTH);
+               height = xenbus_read_unsigned(info->xbdev->nodename,
+                                             XENKBD_FIELD_MT_HEIGHT,
+                                             XENFB_HEIGHT);
+
+               mtouch->name = "Xen Virtual Multi-touch";
+               mtouch->phys = info->phys;
+               mtouch->id.bustype = BUS_PCI;
+               mtouch->id.vendor = 0x5853;
+               mtouch->id.product = 0xfffd;
+
+               input_set_abs_params(mtouch, ABS_MT_TOUCH_MAJOR,
+                                    0, 255, 0, 0);
+               input_set_abs_params(mtouch, ABS_MT_POSITION_X,
+                                    0, width, 0, 0);
+               input_set_abs_params(mtouch, ABS_MT_POSITION_Y,
+                                    0, height, 0, 0);
+               input_set_abs_params(mtouch, ABS_MT_PRESSURE,
+                                    0, 255, 0, 0);
+
+               ret = input_mt_init_slots(mtouch, num_cont, INPUT_MT_DIRECT);
+               if (ret) {
+                       input_free_device(mtouch);
+                       xenbus_dev_fatal(info->xbdev, ret,
+                                        "input_mt_init_slots");
+                       goto error;
+               }
+
+               ret = input_register_device(mtouch);
+               if (ret) {
+                       input_free_device(mtouch);
+                       xenbus_dev_fatal(info->xbdev, ret,
+                                        "input_register_device(mtouch)");
+                       goto error;
+               }
+               info->mtouch_cur_contact_id = -1;
+               info->mtouch = mtouch;
+       }
+
        ret = xenkbd_connect_backend(dev, info);
        if (ret < 0)
                goto error;
@@ -240,6 +377,8 @@ static int xenkbd_remove(struct xenbus_device *dev)
                input_unregister_device(info->kbd);
        if (info->ptr)
                input_unregister_device(info->ptr);
+       if (info->mtouch)
+               input_unregister_device(info->mtouch);
        free_page((unsigned long)info->page);
        kfree(info);
        return 0;
index c52da65..824f4c1 100644 (file)
@@ -436,8 +436,10 @@ static int i8042_start(struct serio *serio)
 {
        struct i8042_port *port = serio->port_data;
 
+       spin_lock_irq(&i8042_lock);
        port->exists = true;
-       mb();
+       spin_unlock_irq(&i8042_lock);
+
        return 0;
 }
 
@@ -450,16 +452,20 @@ static void i8042_stop(struct serio *serio)
 {
        struct i8042_port *port = serio->port_data;
 
+       spin_lock_irq(&i8042_lock);
        port->exists = false;
+       port->serio = NULL;
+       spin_unlock_irq(&i8042_lock);
 
        /*
+        * We need to make sure that interrupt handler finishes using
+        * our serio port before we return from this function.
         * We synchronize with both AUX and KBD IRQs because there is
         * a (very unlikely) chance that AUX IRQ is raised for KBD port
         * and vice versa.
         */
        synchronize_irq(I8042_AUX_IRQ);
        synchronize_irq(I8042_KBD_IRQ);
-       port->serio = NULL;
 }
 
 /*
@@ -576,7 +582,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
 
        spin_unlock_irqrestore(&i8042_lock, flags);
 
-       if (likely(port->exists && !filtered))
+       if (likely(serio && !filtered))
                serio_interrupt(serio, data, dfl);
 
  out:
index dad85e7..3aae015 100644 (file)
@@ -71,7 +71,7 @@ static void __init digicolor_set_gc(void __iomem *reg_base, unsigned irq_base,
 static int __init digicolor_of_init(struct device_node *node,
                                struct device_node *parent)
 {
-       static void __iomem *reg_base;
+       void __iomem *reg_base;
        unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
        struct regmap *ucregs;
        int ret;
index 54c2964..18d58d2 100644 (file)
@@ -43,7 +43,7 @@ static const struct of_device_id syscon_pldset_of_match[] = {
 static int __init
 realview_gic_of_init(struct device_node *node, struct device_node *parent)
 {
-       static struct regmap *map;
+       struct regmap *map;
        struct device_node *np;
        const struct of_device_id *gic_id;
        u32 pld1_ctrl;
index 0a8ed1c..14461cb 100644 (file)
@@ -154,7 +154,7 @@ asmlinkage void __weak plat_irq_dispatch(void)
 static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq,
                             irq_hw_number_t hw)
 {
-       static struct irq_chip *chip;
+       struct irq_chip *chip;
 
        if (hw < 2 && cpu_has_mipsmt) {
                /* Software interrupts are used for MT/CMT IPI */
index 832ebf4..6ab1d3a 100644 (file)
@@ -950,7 +950,6 @@ static void __init __gic_init(unsigned long gic_base_addr,
                                               &gic_irq_domain_ops, NULL);
        if (!gic_irq_domain)
                panic("Failed to add GIC IRQ domain");
-       gic_irq_domain->name = "mips-gic-irq";
 
        gic_ipi_domain = irq_domain_add_hierarchy(gic_irq_domain,
                                                  IRQ_DOMAIN_FLAG_IPI_PER_CPU,
@@ -959,7 +958,6 @@ static void __init __gic_init(unsigned long gic_base_addr,
        if (!gic_ipi_domain)
                panic("Failed to add GIC IPI domain");
 
-       gic_ipi_domain->name = "mips-gic-ipi";
        irq_domain_update_bus_token(gic_ipi_domain, DOMAIN_BUS_IPI);
 
        if (node &&
index 060d357..6f423bc 100644 (file)
@@ -485,18 +485,19 @@ static int isdn_divert_icall(isdn_ctrl *ic)
                                cs->deflect_dest[0] = '\0';
                                retval = 4; /* only proceed */
                        }
-                       sprintf(cs->info, "%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
-                               cs->akt_state,
-                               cs->divert_id,
-                               divert_if.drv_to_name(cs->ics.driver),
-                               (ic->command == ISDN_STAT_ICALLW) ? "1" : "0",
-                               cs->ics.parm.setup.phone,
-                               cs->ics.parm.setup.eazmsn,
-                               cs->ics.parm.setup.si1,
-                               cs->ics.parm.setup.si2,
-                               cs->ics.parm.setup.screen,
-                               dv->rule.waittime,
-                               cs->deflect_dest);
+                       snprintf(cs->info, sizeof(cs->info),
+                                "%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
+                                cs->akt_state,
+                                cs->divert_id,
+                                divert_if.drv_to_name(cs->ics.driver),
+                                (ic->command == ISDN_STAT_ICALLW) ? "1" : "0",
+                                cs->ics.parm.setup.phone,
+                                cs->ics.parm.setup.eazmsn,
+                                cs->ics.parm.setup.si1,
+                                cs->ics.parm.setup.si2,
+                                cs->ics.parm.setup.screen,
+                                dv->rule.waittime,
+                                cs->deflect_dest);
                        if ((dv->rule.action == DEFLECT_REPORT) ||
                            (dv->rule.action == DEFLECT_REJECT)) {
                                put_info_buffer(cs->info);
index 40c7e2c..034caba 100644 (file)
@@ -42,7 +42,7 @@ static char *revision = "$Revision: 1.1.2.2 $";
 
 static bool suppress_pollack;
 
-static struct pci_device_id c4_pci_tbl[] = {
+static const struct pci_device_id c4_pci_tbl[] = {
        { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, 0, 0, (unsigned long)4 },
        { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C2, 0, 0, (unsigned long)2 },
        { }                     /* Terminating entry */
index 8b7ad4f..b2023e0 100644 (file)
@@ -110,7 +110,7 @@ typedef struct _diva_os_thread_dpc {
 /*
   This table should be sorted by PCI device ID
 */
-static struct pci_device_id divas_pci_tbl[] = {
+static const struct pci_device_id divas_pci_tbl[] = {
        /* Diva Server BRI-2M PCI 0xE010 */
        { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRA),
          CARDTYPE_MAESTRA_PCI },
index e3fa1cd..dce6632 100644 (file)
@@ -1142,7 +1142,7 @@ fritz_remove_pci(struct pci_dev *pdev)
                        pr_info("%s: drvdata already removed\n", __func__);
 }
 
-static struct pci_device_id fcpci_ids[] = {
+static const struct pci_device_id fcpci_ids[] = {
        { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID,
          0, 0, (unsigned long) "Fritz!Card PCI"},
        { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID,
index aea0c96..3cf07b8 100644 (file)
@@ -5348,7 +5348,7 @@ static const struct hm_map hfcm_map[] = {
 
 #undef H
 #define H(x)   ((unsigned long)&hfcm_map[x])
-static struct pci_device_id hfmultipci_ids[] = {
+static const struct pci_device_id hfmultipci_ids[] = {
 
        /* Cards with HFC-4S Chip */
        { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
index 5dc246d..d2e401a 100644 (file)
@@ -2161,7 +2161,7 @@ static const struct _hfc_map hfc_map[] =
        {},
 };
 
-static struct pci_device_id hfc_ids[] =
+static const struct pci_device_id hfc_ids[] =
 {
        { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0),
          (unsigned long) &hfc_map[0] },
index afde4ed..6a6d848 100644 (file)
@@ -1137,7 +1137,7 @@ static void nj_remove(struct pci_dev *pdev)
 /* We cannot select cards with PCI_SUB... IDs, since here are cards with
  * SUB IDs set to PCI_ANY_ID, so we need to match all and reject
  * known other cards which not work with this driver - see probe function */
-static struct pci_device_id nj_pci_ids[] = {
+static const struct pci_device_id nj_pci_ids[] = {
        { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        { }
index 3052c83..d80072f 100644 (file)
@@ -1398,7 +1398,7 @@ w6692_remove_pci(struct pci_dev *pdev)
                        pr_notice("%s: drvdata already removed\n", __func__);
 }
 
-static struct pci_device_id w6692_ids[] = {
+static const struct pci_device_id w6692_ids[] = {
        { PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[0]},
        { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692,
index c7d6867..7108bdb 100644 (file)
@@ -1909,7 +1909,7 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if)
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
 
-static struct pci_device_id hisax_pci_tbl[] __used = {
+static const struct pci_device_id hisax_pci_tbl[] __used = {
 #ifdef CONFIG_HISAX_FRITZPCI
        {PCI_VDEVICE(AVM,      PCI_DEVICE_ID_AVM_A1)                    },
 #endif
index 90f051c..9090cc1 100644 (file)
@@ -86,7 +86,7 @@ typedef struct {
        char *device_name;
 } hfc4s8s_param;
 
-static struct pci_device_id hfc4s8s_ids[] = {
+static const struct pci_device_id hfc4s8s_ids[] = {
        {.vendor = PCI_VENDOR_ID_CCD,
         .device = PCI_DEVICE_ID_4S,
         .subvendor = 0x1397,
index 5a9f39e..e4f7573 100644 (file)
@@ -52,7 +52,7 @@ module_param(debug, int, 0);
 MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
 MODULE_DESCRIPTION("AVM Fritz!PCI/PnP ISDN driver");
 
-static struct pci_device_id fcpci_ids[] = {
+static const struct pci_device_id fcpci_ids[] = {
        { .vendor      = PCI_VENDOR_ID_AVM,
          .device      = PCI_DEVICE_ID_AVM_A1,
          .subvendor   = PCI_ANY_ID,
index 5ecc154..9bc3257 100644 (file)
@@ -657,7 +657,7 @@ try:
  * be directed to disk.
  */
 int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
-                       struct ppa_addr ppa, int bio_iter)
+                       struct ppa_addr ppa, int bio_iter, bool advanced_bio)
 {
        struct pblk *pblk = container_of(rb, struct pblk, rwb);
        struct pblk_rb_entry *entry;
@@ -694,7 +694,7 @@ int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
         * filled with data from the cache). If part of the data resides on the
         * media, we will read later on
         */
-       if (unlikely(!bio->bi_iter.bi_idx))
+       if (unlikely(!advanced_bio))
                bio_advance(bio, bio_iter * PBLK_EXPOSED_PAGE_SIZE);
 
        data = bio_data(bio);
index 4e5c48f..d682e89 100644 (file)
@@ -26,7 +26,7 @@
  */
 static int pblk_read_from_cache(struct pblk *pblk, struct bio *bio,
                                sector_t lba, struct ppa_addr ppa,
-                               int bio_iter)
+                               int bio_iter, bool advanced_bio)
 {
 #ifdef CONFIG_NVM_DEBUG
        /* Callers must ensure that the ppa points to a cache address */
@@ -34,7 +34,8 @@ static int pblk_read_from_cache(struct pblk *pblk, struct bio *bio,
        BUG_ON(!pblk_addr_in_cache(ppa));
 #endif
 
-       return pblk_rb_copy_to_bio(&pblk->rwb, bio, lba, ppa, bio_iter);
+       return pblk_rb_copy_to_bio(&pblk->rwb, bio, lba, ppa,
+                                               bio_iter, advanced_bio);
 }
 
 static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
@@ -44,7 +45,7 @@ static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
        struct ppa_addr ppas[PBLK_MAX_REQ_ADDRS];
        sector_t blba = pblk_get_lba(bio);
        int nr_secs = rqd->nr_ppas;
-       int advanced_bio = 0;
+       bool advanced_bio = false;
        int i, j = 0;
 
        /* logic error: lba out-of-bounds. Ignore read request */
@@ -62,19 +63,26 @@ static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
 retry:
                if (pblk_ppa_empty(p)) {
                        WARN_ON(test_and_set_bit(i, read_bitmap));
-                       continue;
+
+                       if (unlikely(!advanced_bio)) {
+                               bio_advance(bio, (i) * PBLK_EXPOSED_PAGE_SIZE);
+                               advanced_bio = true;
+                       }
+
+                       goto next;
                }
 
                /* Try to read from write buffer. The address is later checked
                 * on the write buffer to prevent retrieving overwritten data.
                 */
                if (pblk_addr_in_cache(p)) {
-                       if (!pblk_read_from_cache(pblk, bio, lba, p, i)) {
+                       if (!pblk_read_from_cache(pblk, bio, lba, p, i,
+                                                               advanced_bio)) {
                                pblk_lookup_l2p_seq(pblk, &p, lba, 1);
                                goto retry;
                        }
                        WARN_ON(test_and_set_bit(i, read_bitmap));
-                       advanced_bio = 1;
+                       advanced_bio = true;
 #ifdef CONFIG_NVM_DEBUG
                        atomic_long_inc(&pblk->cache_reads);
 #endif
@@ -83,6 +91,7 @@ retry:
                        rqd->ppa_list[j++] = p;
                }
 
+next:
                if (advanced_bio)
                        bio_advance(bio, PBLK_EXPOSED_PAGE_SIZE);
        }
@@ -282,7 +291,7 @@ retry:
         * write buffer to prevent retrieving overwritten data.
         */
        if (pblk_addr_in_cache(ppa)) {
-               if (!pblk_read_from_cache(pblk, bio, lba, ppa, 0)) {
+               if (!pblk_read_from_cache(pblk, bio, lba, ppa, 0, 1)) {
                        pblk_lookup_l2p_seq(pblk, &ppa, lba, 1);
                        goto retry;
                }
index 0c5692c..67e623b 100644 (file)
@@ -670,7 +670,7 @@ unsigned int pblk_rb_read_to_bio_list(struct pblk_rb *rb, struct bio *bio,
                                      struct list_head *list,
                                      unsigned int max);
 int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
-                       struct ppa_addr ppa, int bio_iter);
+                       struct ppa_addr ppa, int bio_iter, bool advanced_bio);
 unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int entries);
 
 unsigned int pblk_rb_sync_init(struct pblk_rb *rb, unsigned long *flags);
index f4eace5..40f3cd7 100644 (file)
@@ -156,7 +156,8 @@ static int read_sb_page(struct mddev *mddev, loff_t offset,
 
        rdev_for_each(rdev, mddev) {
                if (! test_bit(In_sync, &rdev->flags)
-                   || test_bit(Faulty, &rdev->flags))
+                   || test_bit(Faulty, &rdev->flags)
+                   || test_bit(Bitmap_sync, &rdev->flags))
                        continue;
 
                target = offset + index * (PAGE_SIZE/512);
index 850ff6c..44f4a8a 100644 (file)
@@ -1258,8 +1258,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_write_dirty_buffers_async);
  */
 int dm_bufio_write_dirty_buffers(struct dm_bufio_client *c)
 {
-       blk_status_t a;
-       int f;
+       int a, f;
        unsigned long buffers_processed = 0;
        struct dm_buffer *b, *tmp;
 
index 1b224aa..3acce09 100644 (file)
@@ -1587,16 +1587,18 @@ retry:
        if (likely(ic->mode == 'J')) {
                if (dio->write) {
                        unsigned next_entry, i, pos;
-                       unsigned ws, we;
+                       unsigned ws, we, range_sectors;
 
-                       dio->range.n_sectors = min(dio->range.n_sectors, ic->free_sectors);
+                       dio->range.n_sectors = min(dio->range.n_sectors,
+                                                  ic->free_sectors << ic->sb->log2_sectors_per_block);
                        if (unlikely(!dio->range.n_sectors))
                                goto sleep;
-                       ic->free_sectors -= dio->range.n_sectors;
+                       range_sectors = dio->range.n_sectors >> ic->sb->log2_sectors_per_block;
+                       ic->free_sectors -= range_sectors;
                        journal_section = ic->free_section;
                        journal_entry = ic->free_section_entry;
 
-                       next_entry = ic->free_section_entry + dio->range.n_sectors;
+                       next_entry = ic->free_section_entry + range_sectors;
                        ic->free_section_entry = next_entry % ic->journal_section_entries;
                        ic->free_section += next_entry / ic->journal_section_entries;
                        ic->n_uncommitted_sections += next_entry / ic->journal_section_entries;
@@ -1727,6 +1729,8 @@ static void pad_uncommitted(struct dm_integrity_c *ic)
                wraparound_section(ic, &ic->free_section);
                ic->n_uncommitted_sections++;
        }
+       WARN_ON(ic->journal_sections * ic->journal_section_entries !=
+               (ic->n_uncommitted_sections + ic->n_committed_sections) * ic->journal_section_entries + ic->free_sectors);
 }
 
 static void integrity_commit(struct work_struct *w)
@@ -1821,6 +1825,9 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
 {
        unsigned i, j, n;
        struct journal_completion comp;
+       struct blk_plug plug;
+
+       blk_start_plug(&plug);
 
        comp.ic = ic;
        comp.in_flight = (atomic_t)ATOMIC_INIT(1);
@@ -1945,6 +1952,8 @@ skip_io:
 
        dm_bufio_write_dirty_buffers_async(ic->bufio);
 
+       blk_finish_plug(&plug);
+
        complete_journal_op(&comp);
        wait_for_completion_io(&comp.comp);
 
@@ -3019,6 +3028,11 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                ti->error = "Block size doesn't match the information in superblock";
                goto bad;
        }
+       if (!le32_to_cpu(ic->sb->journal_sections)) {
+               r = -EINVAL;
+               ti->error = "Corrupted superblock, journal_sections is 0";
+               goto bad;
+       }
        /* make sure that ti->max_io_len doesn't overflow */
        if (ic->sb->log2_interleave_sectors < MIN_LOG2_INTERLEAVE_SECTORS ||
            ic->sb->log2_interleave_sectors > MAX_LOG2_INTERLEAVE_SECTORS) {
index 2e10c2f..5bfe285 100644 (file)
@@ -208,6 +208,7 @@ struct raid_dev {
 #define RT_FLAG_RS_BITMAP_LOADED       2
 #define RT_FLAG_UPDATE_SBS             3
 #define RT_FLAG_RESHAPE_RS             4
+#define RT_FLAG_RS_SUSPENDED           5
 
 /* Array elements of 64 bit needed for rebuild/failed disk bits */
 #define DISKS_ARRAY_ELEMS ((MAX_RAID_DEVICES + (sizeof(uint64_t) * 8 - 1)) / sizeof(uint64_t) / 8)
@@ -564,9 +565,10 @@ static const char *raid10_md_layout_to_format(int layout)
        if (__raid10_near_copies(layout) > 1)
                return "near";
 
-       WARN_ON(__raid10_far_copies(layout) < 2);
+       if (__raid10_far_copies(layout) > 1)
+               return "far";
 
-       return "far";
+       return "unknown";
 }
 
 /* Return md raid10 algorithm for @name */
@@ -2540,11 +2542,6 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
        if (!freshest)
                return 0;
 
-       if (validate_raid_redundancy(rs)) {
-               rs->ti->error = "Insufficient redundancy to activate array";
-               return -EINVAL;
-       }
-
        /*
         * Validation of the freshest device provides the source of
         * validation for the remaining devices.
@@ -2553,6 +2550,11 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
        if (super_validate(rs, freshest))
                return -EINVAL;
 
+       if (validate_raid_redundancy(rs)) {
+               rs->ti->error = "Insufficient redundancy to activate array";
+               return -EINVAL;
+       }
+
        rdev_for_each(rdev, mddev)
                if (!test_bit(Journal, &rdev->flags) &&
                    rdev != freshest &&
@@ -3168,6 +3170,7 @@ static int raid_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
 
        mddev_suspend(&rs->md);
+       set_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags);
 
        /* Try to adjust the raid4/5/6 stripe cache size to the stripe size */
        if (rs_is_raid456(rs)) {
@@ -3625,7 +3628,7 @@ static void raid_postsuspend(struct dm_target *ti)
 {
        struct raid_set *rs = ti->private;
 
-       if (!rs->md.suspended)
+       if (!test_and_set_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags))
                mddev_suspend(&rs->md);
 
        rs->md.ro = 1;
@@ -3759,7 +3762,7 @@ static int rs_start_reshape(struct raid_set *rs)
                return r;
 
        /* Need to be resumed to be able to start reshape, recovery is frozen until raid_resume() though */
-       if (mddev->suspended)
+       if (test_and_clear_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags))
                mddev_resume(mddev);
 
        /*
@@ -3786,8 +3789,8 @@ static int rs_start_reshape(struct raid_set *rs)
        }
 
        /* Suspend because a resume will happen in raid_resume() */
-       if (!mddev->suspended)
-               mddev_suspend(mddev);
+       set_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags);
+       mddev_suspend(mddev);
 
        /*
         * Now reshape got set up, update superblocks to
@@ -3883,13 +3886,13 @@ static void raid_resume(struct dm_target *ti)
        if (!(rs->ctr_flags & RESUME_STAY_FROZEN_FLAGS))
                clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
 
-       if (mddev->suspended)
+       if (test_and_clear_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags))
                mddev_resume(mddev);
 }
 
 static struct target_type raid_target = {
        .name = "raid",
-       .version = {1, 11, 1},
+       .version = {1, 12, 1},
        .module = THIS_MODULE,
        .ctr = raid_ctr,
        .dtr = raid_dtr,
index a39bcd9..28a4071 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/atomic.h>
 #include <linux/blk-mq.h>
 #include <linux/mount.h>
+#include <linux/dax.h>
 
 #define DM_MSG_PREFIX "table"
 
@@ -1630,6 +1631,37 @@ static bool dm_table_supports_flush(struct dm_table *t, unsigned long flush)
        return false;
 }
 
+static int device_dax_write_cache_enabled(struct dm_target *ti,
+                                         struct dm_dev *dev, sector_t start,
+                                         sector_t len, void *data)
+{
+       struct dax_device *dax_dev = dev->dax_dev;
+
+       if (!dax_dev)
+               return false;
+
+       if (dax_write_cache_enabled(dax_dev))
+               return true;
+       return false;
+}
+
+static int dm_table_supports_dax_write_cache(struct dm_table *t)
+{
+       struct dm_target *ti;
+       unsigned i;
+
+       for (i = 0; i < dm_table_get_num_targets(t); i++) {
+               ti = dm_table_get_target(t, i);
+
+               if (ti->type->iterate_devices &&
+                   ti->type->iterate_devices(ti,
+                               device_dax_write_cache_enabled, NULL))
+                       return true;
+       }
+
+       return false;
+}
+
 static int device_is_nonrot(struct dm_target *ti, struct dm_dev *dev,
                            sector_t start, sector_t len, void *data)
 {
@@ -1785,6 +1817,9 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
        }
        blk_queue_write_cache(q, wc, fua);
 
+       if (dm_table_supports_dax_write_cache(t))
+               dax_write_cache(t->md->dax_dev, true);
+
        /* Ensure that all underlying devices are non-rotational. */
        if (dm_table_all_devices_attribute(t, device_is_nonrot))
                queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
index 504ba3f..e13f908 100644 (file)
@@ -308,19 +308,14 @@ static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
 {
        unsigned n;
 
-       if (!fio->rs) {
-               fio->rs = mempool_alloc(v->fec->rs_pool, 0);
-               if (unlikely(!fio->rs)) {
-                       DMERR("failed to allocate RS");
-                       return -ENOMEM;
-               }
-       }
+       if (!fio->rs)
+               fio->rs = mempool_alloc(v->fec->rs_pool, GFP_NOIO);
 
        fec_for_each_prealloc_buffer(n) {
                if (fio->bufs[n])
                        continue;
 
-               fio->bufs[n] = mempool_alloc(v->fec->prealloc_pool, GFP_NOIO);
+               fio->bufs[n] = mempool_alloc(v->fec->prealloc_pool, GFP_NOWAIT);
                if (unlikely(!fio->bufs[n])) {
                        DMERR("failed to allocate FEC buffer");
                        return -ENOMEM;
@@ -332,22 +327,16 @@ static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
                if (fio->bufs[n])
                        continue;
 
-               fio->bufs[n] = mempool_alloc(v->fec->extra_pool, GFP_NOIO);
+               fio->bufs[n] = mempool_alloc(v->fec->extra_pool, GFP_NOWAIT);
                /* we can manage with even one buffer if necessary */
                if (unlikely(!fio->bufs[n]))
                        break;
        }
        fio->nbufs = n;
 
-       if (!fio->output) {
+       if (!fio->output)
                fio->output = mempool_alloc(v->fec->output_pool, GFP_NOIO);
 
-               if (!fio->output) {
-                       DMERR("failed to allocate FEC page");
-                       return -ENOMEM;
-               }
-       }
-
        return 0;
 }
 
index 884ff7c..a4fa2ad 100644 (file)
@@ -624,7 +624,7 @@ static int dmz_write_sb(struct dmz_metadata *zmd, unsigned int set)
 
        ret = dmz_rdwr_block(zmd, REQ_OP_WRITE, block, mblk->page);
        if (ret == 0)
-               ret = blkdev_issue_flush(zmd->dev->bdev, GFP_KERNEL, NULL);
+               ret = blkdev_issue_flush(zmd->dev->bdev, GFP_NOIO, NULL);
 
        return ret;
 }
@@ -658,7 +658,7 @@ static int dmz_write_dirty_mblocks(struct dmz_metadata *zmd,
 
        /* Flush drive cache (this will also sync data) */
        if (ret == 0)
-               ret = blkdev_issue_flush(zmd->dev->bdev, GFP_KERNEL, NULL);
+               ret = blkdev_issue_flush(zmd->dev->bdev, GFP_NOIO, NULL);
 
        return ret;
 }
@@ -722,7 +722,7 @@ int dmz_flush_metadata(struct dmz_metadata *zmd)
 
        /* If there are no dirty metadata blocks, just flush the device cache */
        if (list_empty(&write_list)) {
-               ret = blkdev_issue_flush(zmd->dev->bdev, GFP_KERNEL, NULL);
+               ret = blkdev_issue_flush(zmd->dev->bdev, GFP_NOIO, NULL);
                goto out;
        }
 
@@ -927,7 +927,7 @@ static int dmz_recover_mblocks(struct dmz_metadata *zmd, unsigned int dst_set)
                        (zmd->nr_meta_zones << zmd->dev->zone_nr_blocks_shift);
        }
 
-       page = alloc_page(GFP_KERNEL);
+       page = alloc_page(GFP_NOIO);
        if (!page)
                return -ENOMEM;
 
@@ -1183,7 +1183,7 @@ static int dmz_update_zone(struct dmz_metadata *zmd, struct dm_zone *zone)
 
        /* Get zone information from disk */
        ret = blkdev_report_zones(zmd->dev->bdev, dmz_start_sect(zmd, zone),
-                                 &blkz, &nr_blkz, GFP_KERNEL);
+                                 &blkz, &nr_blkz, GFP_NOIO);
        if (ret) {
                dmz_dev_err(zmd->dev, "Get zone %u report failed",
                            dmz_id(zmd, zone));
@@ -1257,7 +1257,7 @@ static int dmz_reset_zone(struct dmz_metadata *zmd, struct dm_zone *zone)
 
                ret = blkdev_reset_zones(dev->bdev,
                                         dmz_start_sect(zmd, zone),
-                                        dev->zone_nr_sectors, GFP_KERNEL);
+                                        dev->zone_nr_sectors, GFP_NOIO);
                if (ret) {
                        dmz_dev_err(dev, "Reset zone %u failed %d",
                                    dmz_id(zmd, zone), ret);
index 05c0a12..44a119e 100644 (file)
@@ -75,7 +75,7 @@ static int dmz_reclaim_align_wp(struct dmz_reclaim *zrc, struct dm_zone *zone,
        nr_blocks = block - wp_block;
        ret = blkdev_issue_zeroout(zrc->dev->bdev,
                                   dmz_start_sect(zmd, zone) + dmz_blk2sect(wp_block),
-                                  dmz_blk2sect(nr_blocks), GFP_NOFS, false);
+                                  dmz_blk2sect(nr_blocks), GFP_NOIO, 0);
        if (ret) {
                dmz_dev_err(zrc->dev,
                            "Align zone %u wp %llu to %llu (wp+%u) blocks failed %d",
index 2b538fa..b08bbbd 100644 (file)
@@ -541,7 +541,7 @@ static void dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
                int ret;
 
                /* Create a new chunk work */
-               cw = kmalloc(sizeof(struct dm_chunk_work), GFP_NOFS);
+               cw = kmalloc(sizeof(struct dm_chunk_work), GFP_NOIO);
                if (!cw)
                        goto out;
 
@@ -588,7 +588,7 @@ static int dmz_map(struct dm_target *ti, struct bio *bio)
 
        bio->bi_bdev = dev->bdev;
 
-       if (!nr_sectors && (bio_op(bio) != REQ_OP_FLUSH) && (bio_op(bio) != REQ_OP_WRITE))
+       if (!nr_sectors && bio_op(bio) != REQ_OP_WRITE)
                return DM_MAPIO_REMAPPED;
 
        /* The BIO should be block aligned */
@@ -603,7 +603,7 @@ static int dmz_map(struct dm_target *ti, struct bio *bio)
        bioctx->status = BLK_STS_OK;
 
        /* Set the BIO pending in the flush list */
-       if (bio_op(bio) == REQ_OP_FLUSH || (!nr_sectors && bio_op(bio) == REQ_OP_WRITE)) {
+       if (!nr_sectors && bio_op(bio) == REQ_OP_WRITE) {
                spin_lock(&dmz->flush_lock);
                bio_list_add(&dmz->flush_list, bio);
                spin_unlock(&dmz->flush_lock);
@@ -785,7 +785,7 @@ static int dmz_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        /* Chunk BIO work */
        mutex_init(&dmz->chunk_lock);
-       INIT_RADIX_TREE(&dmz->chunk_rxtree, GFP_NOFS);
+       INIT_RADIX_TREE(&dmz->chunk_rxtree, GFP_KERNEL);
        dmz->chunk_wq = alloc_workqueue("dmz_cwq_%s", WQ_MEM_RECLAIM | WQ_UNBOUND,
                                        0, dev->name);
        if (!dmz->chunk_wq) {
index 8cdca02..c996346 100644 (file)
@@ -2287,7 +2287,7 @@ static void export_array(struct mddev *mddev)
 
 static bool set_in_sync(struct mddev *mddev)
 {
-       WARN_ON_ONCE(!spin_is_locked(&mddev->lock));
+       WARN_ON_ONCE(NR_CPUS != 1 && !spin_is_locked(&mddev->lock));
        if (!mddev->in_sync) {
                mddev->sync_checkers++;
                spin_unlock(&mddev->lock);
index 991f0fe..09db034 100644 (file)
@@ -134,7 +134,9 @@ enum flag_bits {
        Faulty,                 /* device is known to have a fault */
        In_sync,                /* device is in_sync with rest of array */
        Bitmap_sync,            /* ..actually, not quite In_sync.  Need a
-                                * bitmap-based recovery to get fully in sync
+                                * bitmap-based recovery to get fully in sync.
+                                * The bit is only meaningful before device
+                                * has been passed to pers->hot_add_disk.
                                 */
        WriteMostly,            /* Avoid reading if at all possible */
        AutoDetected,           /* added by auto-detect */
@@ -729,58 +731,4 @@ static inline void mddev_check_write_zeroes(struct mddev *mddev, struct bio *bio
            !bdev_get_queue(bio->bi_bdev)->limits.max_write_zeroes_sectors)
                mddev->queue->limits.max_write_zeroes_sectors = 0;
 }
-
-/* Maximum size of each resync request */
-#define RESYNC_BLOCK_SIZE (64*1024)
-#define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE)
-
-/* for managing resync I/O pages */
-struct resync_pages {
-       unsigned        idx;    /* for get/put page from the pool */
-       void            *raid_bio;
-       struct page     *pages[RESYNC_PAGES];
-};
-
-static inline int resync_alloc_pages(struct resync_pages *rp,
-                                    gfp_t gfp_flags)
-{
-       int i;
-
-       for (i = 0; i < RESYNC_PAGES; i++) {
-               rp->pages[i] = alloc_page(gfp_flags);
-               if (!rp->pages[i])
-                       goto out_free;
-       }
-
-       return 0;
-
-out_free:
-       while (--i >= 0)
-               put_page(rp->pages[i]);
-       return -ENOMEM;
-}
-
-static inline void resync_free_pages(struct resync_pages *rp)
-{
-       int i;
-
-       for (i = 0; i < RESYNC_PAGES; i++)
-               put_page(rp->pages[i]);
-}
-
-static inline void resync_get_all_pages(struct resync_pages *rp)
-{
-       int i;
-
-       for (i = 0; i < RESYNC_PAGES; i++)
-               get_page(rp->pages[i]);
-}
-
-static inline struct page *resync_fetch_page(struct resync_pages *rp,
-                                            unsigned idx)
-{
-       if (WARN_ON_ONCE(idx >= RESYNC_PAGES))
-               return NULL;
-       return rp->pages[idx];
-}
 #endif /* _MD_MD_H */
diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
new file mode 100644 (file)
index 0000000..9f2670b
--- /dev/null
@@ -0,0 +1,81 @@
+/* Maximum size of each resync request */
+#define RESYNC_BLOCK_SIZE (64*1024)
+#define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE)
+
+/* for managing resync I/O pages */
+struct resync_pages {
+       void            *raid_bio;
+       struct page     *pages[RESYNC_PAGES];
+};
+
+static inline int resync_alloc_pages(struct resync_pages *rp,
+                                    gfp_t gfp_flags)
+{
+       int i;
+
+       for (i = 0; i < RESYNC_PAGES; i++) {
+               rp->pages[i] = alloc_page(gfp_flags);
+               if (!rp->pages[i])
+                       goto out_free;
+       }
+
+       return 0;
+
+out_free:
+       while (--i >= 0)
+               put_page(rp->pages[i]);
+       return -ENOMEM;
+}
+
+static inline void resync_free_pages(struct resync_pages *rp)
+{
+       int i;
+
+       for (i = 0; i < RESYNC_PAGES; i++)
+               put_page(rp->pages[i]);
+}
+
+static inline void resync_get_all_pages(struct resync_pages *rp)
+{
+       int i;
+
+       for (i = 0; i < RESYNC_PAGES; i++)
+               get_page(rp->pages[i]);
+}
+
+static inline struct page *resync_fetch_page(struct resync_pages *rp,
+                                            unsigned idx)
+{
+       if (WARN_ON_ONCE(idx >= RESYNC_PAGES))
+               return NULL;
+       return rp->pages[idx];
+}
+
+/*
+ * 'strct resync_pages' stores actual pages used for doing the resync
+ *  IO, and it is per-bio, so make .bi_private points to it.
+ */
+static inline struct resync_pages *get_resync_pages(struct bio *bio)
+{
+       return bio->bi_private;
+}
+
+/* generally called after bio_reset() for reseting bvec */
+static void md_bio_reset_resync_pages(struct bio *bio, struct resync_pages *rp,
+                              int size)
+{
+       int idx = 0;
+
+       /* initialize bvec table again */
+       do {
+               struct page *page = resync_fetch_page(rp, idx);
+               int len = min_t(int, size, PAGE_SIZE);
+
+               /*
+                * won't fail because the vec table is big
+                * enough to hold all these pages
+                */
+               bio_add_page(bio, page, len, 0);
+               size -= len;
+       } while (idx++ < RESYNC_PAGES && size > 0);
+}
index 3febfc8..f50958d 100644 (file)
@@ -81,14 +81,7 @@ static void lower_barrier(struct r1conf *conf, sector_t sector_nr);
 #define raid1_log(md, fmt, args...)                            \
        do { if ((md)->queue) blk_add_trace_msg((md)->queue, "raid1 " fmt, ##args); } while (0)
 
-/*
- * 'strct resync_pages' stores actual pages used for doing the resync
- *  IO, and it is per-bio, so make .bi_private points to it.
- */
-static inline struct resync_pages *get_resync_pages(struct bio *bio)
-{
-       return bio->bi_private;
-}
+#include "raid1-10.c"
 
 /*
  * for resync bio, r1bio pointer can be retrieved from the per-bio
@@ -170,7 +163,6 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
                        resync_get_all_pages(rp);
                }
 
-               rp->idx = 0;
                rp->raid_bio = r1_bio;
                bio->bi_private = rp;
        }
@@ -492,10 +484,6 @@ static void raid1_end_write_request(struct bio *bio)
        }
 
        if (behind) {
-               /* we release behind master bio when all write are done */
-               if (r1_bio->behind_master_bio == bio)
-                       to_put = NULL;
-
                if (test_bit(WriteMostly, &rdev->flags))
                        atomic_dec(&r1_bio->behind_remaining);
 
@@ -802,8 +790,7 @@ static void flush_bio_list(struct r1conf *conf, struct bio *bio)
                bio->bi_next = NULL;
                bio->bi_bdev = rdev->bdev;
                if (test_bit(Faulty, &rdev->flags)) {
-                       bio->bi_status = BLK_STS_IOERR;
-                       bio_endio(bio);
+                       bio_io_error(bio);
                } else if (unlikely((bio_op(bio) == REQ_OP_DISCARD) &&
                                    !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
                        /* Just ignore it */
@@ -1088,7 +1075,7 @@ static void unfreeze_array(struct r1conf *conf)
        wake_up(&conf->wait_barrier);
 }
 
-static struct bio *alloc_behind_master_bio(struct r1bio *r1_bio,
+static void alloc_behind_master_bio(struct r1bio *r1_bio,
                                           struct bio *bio)
 {
        int size = bio->bi_iter.bi_size;
@@ -1098,11 +1085,13 @@ static struct bio *alloc_behind_master_bio(struct r1bio *r1_bio,
 
        behind_bio = bio_alloc_mddev(GFP_NOIO, vcnt, r1_bio->mddev);
        if (!behind_bio)
-               goto fail;
+               return;
 
        /* discard op, we don't support writezero/writesame yet */
-       if (!bio_has_data(bio))
+       if (!bio_has_data(bio)) {
+               behind_bio->bi_iter.bi_size = size;
                goto skip_copy;
+       }
 
        while (i < vcnt && size) {
                struct page *page;
@@ -1123,14 +1112,13 @@ skip_copy:
        r1_bio->behind_master_bio = behind_bio;;
        set_bit(R1BIO_BehindIO, &r1_bio->state);
 
-       return behind_bio;
+       return;
 
 free_pages:
        pr_debug("%dB behind alloc failed, doing sync I/O\n",
                 bio->bi_iter.bi_size);
        bio_free_pages(behind_bio);
-fail:
-       return behind_bio;
+       bio_put(behind_bio);
 }
 
 struct raid1_plug_cb {
@@ -1483,7 +1471,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
                            (atomic_read(&bitmap->behind_writes)
                             < mddev->bitmap_info.max_write_behind) &&
                            !waitqueue_active(&bitmap->behind_wait)) {
-                               mbio = alloc_behind_master_bio(r1_bio, bio);
+                               alloc_behind_master_bio(r1_bio, bio);
                        }
 
                        bitmap_startwrite(bitmap, r1_bio->sector,
@@ -1493,14 +1481,11 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
                        first_clone = 0;
                }
 
-               if (!mbio) {
-                       if (r1_bio->behind_master_bio)
-                               mbio = bio_clone_fast(r1_bio->behind_master_bio,
-                                                     GFP_NOIO,
-                                                     mddev->bio_set);
-                       else
-                               mbio = bio_clone_fast(bio, GFP_NOIO, mddev->bio_set);
-               }
+               if (r1_bio->behind_master_bio)
+                       mbio = bio_clone_fast(r1_bio->behind_master_bio,
+                                             GFP_NOIO, mddev->bio_set);
+               else
+                       mbio = bio_clone_fast(bio, GFP_NOIO, mddev->bio_set);
 
                if (r1_bio->behind_master_bio) {
                        if (test_bit(WriteMostly, &conf->mirrors[i].rdev->flags))
@@ -2086,10 +2071,7 @@ static void process_checks(struct r1bio *r1_bio)
        /* Fix variable parts of all bios */
        vcnt = (r1_bio->sectors + PAGE_SIZE / 512 - 1) >> (PAGE_SHIFT - 9);
        for (i = 0; i < conf->raid_disks * 2; i++) {
-               int j;
-               int size;
                blk_status_t status;
-               struct bio_vec *bi;
                struct bio *b = r1_bio->bios[i];
                struct resync_pages *rp = get_resync_pages(b);
                if (b->bi_end_io != end_sync_read)
@@ -2098,8 +2080,6 @@ static void process_checks(struct r1bio *r1_bio)
                status = b->bi_status;
                bio_reset(b);
                b->bi_status = status;
-               b->bi_vcnt = vcnt;
-               b->bi_iter.bi_size = r1_bio->sectors << 9;
                b->bi_iter.bi_sector = r1_bio->sector +
                        conf->mirrors[i].rdev->data_offset;
                b->bi_bdev = conf->mirrors[i].rdev->bdev;
@@ -2107,15 +2087,8 @@ static void process_checks(struct r1bio *r1_bio)
                rp->raid_bio = r1_bio;
                b->bi_private = rp;
 
-               size = b->bi_iter.bi_size;
-               bio_for_each_segment_all(bi, b, j) {
-                       bi->bv_offset = 0;
-                       if (size > PAGE_SIZE)
-                               bi->bv_len = PAGE_SIZE;
-                       else
-                               bi->bv_len = size;
-                       size -= PAGE_SIZE;
-               }
+               /* initialize bvec table again */
+               md_bio_reset_resync_pages(b, rp, r1_bio->sectors << 9);
        }
        for (primary = 0; primary < conf->raid_disks * 2; primary++)
                if (r1_bio->bios[primary]->bi_end_io == end_sync_read &&
@@ -2366,8 +2339,6 @@ static int narrow_write_error(struct r1bio *r1_bio, int i)
                        wbio = bio_clone_fast(r1_bio->behind_master_bio,
                                              GFP_NOIO,
                                              mddev->bio_set);
-                       /* We really need a _all clone */
-                       wbio->bi_iter = (struct bvec_iter){ 0 };
                } else {
                        wbio = bio_clone_fast(r1_bio->master_bio, GFP_NOIO,
                                              mddev->bio_set);
@@ -2619,6 +2590,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
        int good_sectors = RESYNC_SECTORS;
        int min_bad = 0; /* number of sectors that are bad in all devices */
        int idx = sector_to_idx(sector_nr);
+       int page_idx = 0;
 
        if (!conf->r1buf_pool)
                if (init_resync(conf))
@@ -2846,7 +2818,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
                        bio = r1_bio->bios[i];
                        rp = get_resync_pages(bio);
                        if (bio->bi_end_io) {
-                               page = resync_fetch_page(rp, rp->idx++);
+                               page = resync_fetch_page(rp, page_idx);
 
                                /*
                                 * won't fail because the vec table is big
@@ -2858,7 +2830,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
                nr_sectors += len>>9;
                sector_nr += len>>9;
                sync_blocks -= (len>>9);
-       } while (get_resync_pages(r1_bio->bios[disk]->bi_private)->idx < RESYNC_PAGES);
+       } while (++page_idx < RESYNC_PAGES);
 
        r1_bio->sectors = nr_sectors;
 
index 5026e7a..f55d4cc 100644 (file)
@@ -110,14 +110,7 @@ static void end_reshape(struct r10conf *conf);
 #define raid10_log(md, fmt, args...)                           \
        do { if ((md)->queue) blk_add_trace_msg((md)->queue, "raid10 " fmt, ##args); } while (0)
 
-/*
- * 'strct resync_pages' stores actual pages used for doing the resync
- *  IO, and it is per-bio, so make .bi_private points to it.
- */
-static inline struct resync_pages *get_resync_pages(struct bio *bio)
-{
-       return bio->bi_private;
-}
+#include "raid1-10.c"
 
 /*
  * for resync bio, r10bio pointer can be retrieved from the per-bio
@@ -221,7 +214,6 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
                        resync_get_all_pages(rp);
                }
 
-               rp->idx = 0;
                rp->raid_bio = r10_bio;
                bio->bi_private = rp;
                if (rbio) {
@@ -913,8 +905,7 @@ static void flush_pending_writes(struct r10conf *conf)
                        bio->bi_next = NULL;
                        bio->bi_bdev = rdev->bdev;
                        if (test_bit(Faulty, &rdev->flags)) {
-                               bio->bi_status = BLK_STS_IOERR;
-                               bio_endio(bio);
+                               bio_io_error(bio);
                        } else if (unlikely((bio_op(bio) ==  REQ_OP_DISCARD) &&
                                            !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
                                /* Just ignore it */
@@ -1098,8 +1089,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)
                bio->bi_next = NULL;
                bio->bi_bdev = rdev->bdev;
                if (test_bit(Faulty, &rdev->flags)) {
-                       bio->bi_status = BLK_STS_IOERR;
-                       bio_endio(bio);
+                       bio_io_error(bio);
                } else if (unlikely((bio_op(bio) ==  REQ_OP_DISCARD) &&
                                    !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
                        /* Just ignore it */
@@ -2087,8 +2077,8 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
                rp = get_resync_pages(tbio);
                bio_reset(tbio);
 
-               tbio->bi_vcnt = vcnt;
-               tbio->bi_iter.bi_size = fbio->bi_iter.bi_size;
+               md_bio_reset_resync_pages(tbio, rp, fbio->bi_iter.bi_size);
+
                rp->raid_bio = r10_bio;
                tbio->bi_private = rp;
                tbio->bi_iter.bi_sector = r10_bio->devs[i].addr;
@@ -2853,6 +2843,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
        sector_t sectors_skipped = 0;
        int chunks_skipped = 0;
        sector_t chunk_mask = conf->geo.chunk_mask;
+       int page_idx = 0;
 
        if (!conf->r10buf_pool)
                if (init_resync(conf))
@@ -3355,7 +3346,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                        break;
                for (bio= biolist ; bio ; bio=bio->bi_next) {
                        struct resync_pages *rp = get_resync_pages(bio);
-                       page = resync_fetch_page(rp, rp->idx++);
+                       page = resync_fetch_page(rp, page_idx);
                        /*
                         * won't fail because the vec table is big enough
                         * to hold all these pages
@@ -3364,7 +3355,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                }
                nr_sectors += len>>9;
                sector_nr += len>>9;
-       } while (get_resync_pages(biolist)->idx < RESYNC_PAGES);
+       } while (++page_idx < RESYNC_PAGES);
        r10_bio->sectors = nr_sectors;
 
        while (biolist) {
index 77cce35..44ad5ba 100644 (file)
@@ -1150,7 +1150,7 @@ int ppl_init_log(struct r5conf *conf)
                goto err;
        }
 
-       ppl_conf->bs = bioset_create(conf->raid_disks, 0, 0);
+       ppl_conf->bs = bioset_create(conf->raid_disks, 0, BIOSET_NEED_BVECS);
        if (!ppl_conf->bs) {
                ret = -ENOMEM;
                goto err;
index 2ceb338..0fc2748 100644 (file)
@@ -3381,9 +3381,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
                        sh->dev[i].sector + STRIPE_SECTORS) {
                        struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
 
-                       bi->bi_status = BLK_STS_IOERR;
                        md_write_end(conf->mddev);
-                       bio_endio(bi);
+                       bio_io_error(bi);
                        bi = nextbi;
                }
                if (bitmap_end)
@@ -3403,9 +3402,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
                       sh->dev[i].sector + STRIPE_SECTORS) {
                        struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector);
 
-                       bi->bi_status = BLK_STS_IOERR;
                        md_write_end(conf->mddev);
-                       bio_endio(bi);
+                       bio_io_error(bi);
                        bi = bi2;
                }
 
@@ -3429,8 +3427,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
                                struct bio *nextbi =
                                        r5_next_bio(bi, sh->dev[i].sector);
 
-                               bi->bi_status = BLK_STS_IOERR;
-                               bio_endio(bi);
+                               bio_io_error(bi);
                                bi = nextbi;
                        }
                }
@@ -6237,6 +6234,8 @@ static void raid5_do_work(struct work_struct *work)
        pr_debug("%d stripes handled\n", handled);
 
        spin_unlock_irq(&conf->device_lock);
+
+       async_tx_issue_pending_all();
        blk_finish_plug(&plug);
 
        pr_debug("--- raid5worker inactive\n");
@@ -7951,12 +7950,10 @@ static void end_reshape(struct r5conf *conf)
 {
 
        if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) {
-               struct md_rdev *rdev;
 
                spin_lock_irq(&conf->device_lock);
                conf->previous_raid_disks = conf->raid_disks;
-               rdev_for_each(rdev, conf->mddev)
-                       rdev->data_offset = rdev->new_data_offset;
+               md_finish_reshape(conf->mddev);
                smp_wmb();
                conf->reshape_progress = MaxSector;
                conf->mddev->reshape_position = MaxSector;
index 0cfac2d..8ac59dc 100644 (file)
@@ -637,6 +637,9 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
                           sizeof(num_of_cmds)))
                return -EFAULT;
 
+       if (!num_of_cmds)
+               return 0;
+
        if (num_of_cmds > MMC_IOC_MAX_CMDS)
                return -EINVAL;
 
@@ -1182,7 +1185,7 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
 
        switch (mq_rq->drv_op) {
        case MMC_DRV_OP_IOCTL:
-               for (i = 0; i < mq_rq->ioc_count; i++) {
+               for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) {
                        ret = __mmc_blk_ioctl_cmd(card, md, mq_rq->idata[i]);
                        if (ret)
                                break;
@@ -2167,6 +2170,7 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
                 * from being accepted.
                 */
                card = md->queue.card;
+               blk_set_queue_dying(md->queue.queue);
                mmc_cleanup_queue(&md->queue);
                if (md->disk->flags & GENHD_FL_UP) {
                        device_remove_file(disk_to_dev(md->disk), &md->force_ro);
index a9dfb26..250dc6e 100644 (file)
@@ -2957,7 +2957,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
        }
 
        /* find out number of slots supported */
-       if (device_property_read_u32(dev, "num-slots", &pdata->num_slots))
+       if (!device_property_read_u32(dev, "num-slots", &pdata->num_slots))
                dev_info(dev, "'num-slots' was deprecated.\n");
 
        if (device_property_read_u32(dev, "fifo-depth", &pdata->fifo_depth))
index 7c12f37..04ff3c9 100644 (file)
@@ -356,9 +356,6 @@ static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on,
        struct mmc_host *mmc = host->mmc;
        int ret = 0;
 
-       if (mmc_pdata(host)->set_power)
-               return mmc_pdata(host)->set_power(host->dev, power_on, vdd);
-
        /*
         * If we don't see a Vcc regulator, assume it's a fixed
         * voltage always-on regulator.
@@ -366,9 +363,6 @@ static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on,
        if (IS_ERR(mmc->supply.vmmc))
                return 0;
 
-       if (mmc_pdata(host)->before_set_reg)
-               mmc_pdata(host)->before_set_reg(host->dev, power_on, vdd);
-
        ret = omap_hsmmc_set_pbias(host, false, 0);
        if (ret)
                return ret;
@@ -400,9 +394,6 @@ static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on,
                        return ret;
        }
 
-       if (mmc_pdata(host)->after_set_reg)
-               mmc_pdata(host)->after_set_reg(host->dev, power_on, vdd);
-
        return 0;
 
 err_set_voltage:
@@ -469,8 +460,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
        int ret;
        struct mmc_host *mmc = host->mmc;
 
-       if (mmc_pdata(host)->set_power)
-               return 0;
 
        ret = mmc_regulator_get_supply(mmc);
        if (ret == -EPROBE_DEFER)
index cf66a3d..ac678e9 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
 #include <asm/iosf_mbi.h>
+#include <linux/pci.h>
 #endif
 
 #include "sdhci.h"
@@ -134,6 +135,16 @@ static bool sdhci_acpi_byt(void)
        return x86_match_cpu(byt);
 }
 
+static bool sdhci_acpi_cht(void)
+{
+       static const struct x86_cpu_id cht[] = {
+               { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT },
+               {}
+       };
+
+       return x86_match_cpu(cht);
+}
+
 #define BYT_IOSF_SCCEP                 0x63
 #define BYT_IOSF_OCP_NETCTRL0          0x1078
 #define BYT_IOSF_OCP_TIMEOUT_BASE      GENMASK(10, 8)
@@ -178,6 +189,45 @@ static bool sdhci_acpi_byt_defer(struct device *dev)
        return false;
 }
 
+static bool sdhci_acpi_cht_pci_wifi(unsigned int vendor, unsigned int device,
+                                   unsigned int slot, unsigned int parent_slot)
+{
+       struct pci_dev *dev, *parent, *from = NULL;
+
+       while (1) {
+               dev = pci_get_device(vendor, device, from);
+               pci_dev_put(from);
+               if (!dev)
+                       break;
+               parent = pci_upstream_bridge(dev);
+               if (ACPI_COMPANION(&dev->dev) && PCI_SLOT(dev->devfn) == slot &&
+                   parent && PCI_SLOT(parent->devfn) == parent_slot &&
+                   !pci_upstream_bridge(parent)) {
+                       pci_dev_put(dev);
+                       return true;
+               }
+               from = dev;
+       }
+
+       return false;
+}
+
+/*
+ * GPDwin uses PCI wifi which conflicts with SDIO's use of
+ * acpi_device_fix_up_power() on child device nodes. Identifying GPDwin is
+ * problematic, but since SDIO is only used for wifi, the presence of the PCI
+ * wifi card in the expected slot with an ACPI companion node, is used to
+ * indicate that acpi_device_fix_up_power() should be avoided.
+ */
+static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
+                                                  const char *uid)
+{
+       return sdhci_acpi_cht() &&
+              !strcmp(hid, "80860F14") &&
+              !strcmp(uid, "2") &&
+              sdhci_acpi_cht_pci_wifi(0x14e4, 0x43ec, 0, 28);
+}
+
 #else
 
 static inline void sdhci_acpi_byt_setting(struct device *dev)
@@ -189,6 +239,12 @@ static inline bool sdhci_acpi_byt_defer(struct device *dev)
        return false;
 }
 
+static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
+                                                  const char *uid)
+{
+       return false;
+}
+
 #endif
 
 static int bxt_get_cd(struct mmc_host *mmc)
@@ -389,18 +445,20 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        if (acpi_bus_get_device(handle, &device))
                return -ENODEV;
 
+       hid = acpi_device_hid(device);
+       uid = device->pnp.unique_id;
+
        /* Power on the SDHCI controller and its children */
        acpi_device_fix_up_power(device);
-       list_for_each_entry(child, &device->children, node)
-               if (child->status.present && child->status.enabled)
-                       acpi_device_fix_up_power(child);
+       if (!sdhci_acpi_no_fixup_child_power(hid, uid)) {
+               list_for_each_entry(child, &device->children, node)
+                       if (child->status.present && child->status.enabled)
+                               acpi_device_fix_up_power(child);
+       }
 
        if (sdhci_acpi_byt_defer(dev))
                return -EPROBE_DEFER;
 
-       hid = acpi_device_hid(device);
-       uid = device->pnp.unique_id;
-
        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!iomem)
                return -ENOMEM;
index d6fa221..0fb4e4c 100644 (file)
@@ -793,8 +793,12 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
        }
        mmc_writel(host, REG_CLKCR, rval);
 
-       if (host->cfg->needs_new_timings)
-               mmc_writel(host, REG_SD_NTSR, SDXC_2X_TIMING_MODE);
+       if (host->cfg->needs_new_timings) {
+               /* Don't touch the delay bits */
+               rval = mmc_readl(host, REG_SD_NTSR);
+               rval |= SDXC_2X_TIMING_MODE;
+               mmc_writel(host, REG_SD_NTSR, rval);
+       }
 
        ret = sunxi_mmc_clk_set_phase(host, ios, rate);
        if (ret)
index 82b80d4..88a9435 100644 (file)
@@ -409,30 +409,29 @@ static void tmio_mmc_transfer_data(struct tmio_mmc_host *host,
         * Transfer the data
         */
        if (host->pdata->flags & TMIO_MMC_32BIT_DATA_PORT) {
-               u8 data[4] = { };
+               u32 data = 0;
+               u32 *buf32 = (u32 *)buf;
 
                if (is_read)
-                       sd_ctrl_read32_rep(host, CTL_SD_DATA_PORT, (u32 *)buf,
+                       sd_ctrl_read32_rep(host, CTL_SD_DATA_PORT, buf32,
                                           count >> 2);
                else
-                       sd_ctrl_write32_rep(host, CTL_SD_DATA_PORT, (u32 *)buf,
+                       sd_ctrl_write32_rep(host, CTL_SD_DATA_PORT, buf32,
                                            count >> 2);
 
                /* if count was multiple of 4 */
                if (!(count & 0x3))
                        return;
 
-               buf8 = (u8 *)(buf + (count >> 2));
+               buf32 += count >> 2;
                count %= 4;
 
                if (is_read) {
-                       sd_ctrl_read32_rep(host, CTL_SD_DATA_PORT,
-                                          (u32 *)data, 1);
-                       memcpy(buf8, data, count);
+                       sd_ctrl_read32_rep(host, CTL_SD_DATA_PORT, &data, 1);
+                       memcpy(buf32, &data, count);
                } else {
-                       memcpy(data, buf8, count);
-                       sd_ctrl_write32_rep(host, CTL_SD_DATA_PORT,
-                                           (u32 *)data, 1);
+                       memcpy(&data, buf32, count);
+                       sd_ctrl_write32_rep(host, CTL_SD_DATA_PORT, &data, 1);
                }
 
                return;
index e15a973..9668616 100644 (file)
@@ -1386,7 +1386,7 @@ static void wbsd_request_dma(struct wbsd_host *host, int dma)
         * order for ISA to be able to DMA to it.
         */
        host->dma_buffer = kmalloc(WBSD_DMA_SIZE,
-               GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN);
+               GFP_NOIO | GFP_DMA | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
        if (!host->dma_buffer)
                goto free;
 
index e83a279..5a2d717 100644 (file)
@@ -155,6 +155,10 @@ config MTD_BCM47XX_PARTS
          This provides partitions parser for devices based on BCM47xx
          boards.
 
+menu "Partition parsers"
+source "drivers/mtd/parsers/Kconfig"
+endmenu
+
 comment "User Modules And Translation Layers"
 
 #
index 99bb9a1..151d60d 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_AFS_PARTS)   += afs.o
 obj-$(CONFIG_MTD_AR7_PARTS)    += ar7part.o
 obj-$(CONFIG_MTD_BCM63XX_PARTS)        += bcm63xxpart.o
 obj-$(CONFIG_MTD_BCM47XX_PARTS)        += bcm47xxpart.o
+obj-y                          += parsers/
 
 # 'Users' - code which presents functionality to userspace.
 obj-$(CONFIG_MTD_BLKDEVS)      += mtd_blkdevs.o
index d10fa6c..fe2581d 100644 (file)
@@ -43,7 +43,8 @@
 #define ML_MAGIC2                      0x26594131
 #define TRX_MAGIC                      0x30524448
 #define SHSQ_MAGIC                     0x71736873      /* shsq (weird ZTE H218N endianness) */
-#define UBI_EC_MAGIC                   0x23494255      /* UBI# */
+
+static const char * const trx_types[] = { "trx", NULL };
 
 struct trx_header {
        uint32_t magic;
@@ -62,89 +63,6 @@ static void bcm47xxpart_add_part(struct mtd_partition *part, const char *name,
        part->mask_flags = mask_flags;
 }
 
-static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
-                                                 size_t offset)
-{
-       uint32_t buf;
-       size_t bytes_read;
-       int err;
-
-       err  = mtd_read(master, offset, sizeof(buf), &bytes_read,
-                       (uint8_t *)&buf);
-       if (err && !mtd_is_bitflip(err)) {
-               pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
-                       offset, err);
-               goto out_default;
-       }
-
-       if (buf == UBI_EC_MAGIC)
-               return "ubi";
-
-out_default:
-       return "rootfs";
-}
-
-static int bcm47xxpart_parse_trx(struct mtd_info *master,
-                                struct mtd_partition *trx,
-                                struct mtd_partition *parts,
-                                size_t parts_len)
-{
-       struct trx_header header;
-       size_t bytes_read;
-       int curr_part = 0;
-       int i, err;
-
-       if (parts_len < 3) {
-               pr_warn("No enough space to add TRX partitions!\n");
-               return -ENOMEM;
-       }
-
-       err = mtd_read(master, trx->offset, sizeof(header), &bytes_read,
-                      (uint8_t *)&header);
-       if (err && !mtd_is_bitflip(err)) {
-               pr_err("mtd_read error while reading TRX header: %d\n", err);
-               return err;
-       }
-
-       i = 0;
-
-       /* We have LZMA loader if offset[2] points to sth */
-       if (header.offset[2]) {
-               bcm47xxpart_add_part(&parts[curr_part++], "loader",
-                                    trx->offset + header.offset[i], 0);
-               i++;
-       }
-
-       if (header.offset[i]) {
-               bcm47xxpart_add_part(&parts[curr_part++], "linux",
-                                    trx->offset + header.offset[i], 0);
-               i++;
-       }
-
-       if (header.offset[i]) {
-               size_t offset = trx->offset + header.offset[i];
-               const char *name = bcm47xxpart_trx_data_part_name(master,
-                                                                 offset);
-
-               bcm47xxpart_add_part(&parts[curr_part++], name, offset, 0);
-               i++;
-       }
-
-       /*
-        * Assume that every partition ends at the beginning of the one it is
-        * followed by.
-        */
-       for (i = 0; i < curr_part; i++) {
-               u64 next_part_offset = (i < curr_part - 1) ?
-                                       parts[i + 1].offset :
-                                       trx->offset + trx->size;
-
-               parts[i].size = next_part_offset - parts[i].offset;
-       }
-
-       return curr_part;
-}
-
 /**
  * bcm47xxpart_bootpartition - gets index of TRX partition used by bootloader
  *
@@ -362,17 +280,10 @@ static int bcm47xxpart_parse(struct mtd_info *master,
        for (i = 0; i < trx_num; i++) {
                struct mtd_partition *trx = &parts[trx_parts[i]];
 
-               if (i == bcm47xxpart_bootpartition()) {
-                       int num_parts;
-
-                       num_parts = bcm47xxpart_parse_trx(master, trx,
-                                                         parts + curr_part,
-                                                         BCM47XXPART_MAX_PARTS - curr_part);
-                       if (num_parts > 0)
-                               curr_part += num_parts;
-               } else {
+               if (i == bcm47xxpart_bootpartition())
+                       trx->types = trx_types;
+               else
                        trx->name = "failsafe";
-               }
        }
 
        *pparts = parts;
index 94d3eb4..7d34296 100644 (file)
@@ -666,7 +666,7 @@ cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs,
        size_t   totlen = 0, thislen;
        int      ret = 0;
        size_t   buflen = 0;
-       static char *buffer;
+       char *buffer;
 
        if (!ECCBUF_SIZE) {
                /* We should fall back to a general writev implementation.
index 58329d2..6def544 100644 (file)
@@ -95,6 +95,16 @@ config MTD_M25P80
          if you want to specify device partitioning or to use a device which
          doesn't support the JEDEC ID instruction.
 
+config MTD_MCHP23K256
+       tristate "Microchip 23K256 SRAM"
+       depends on SPI_MASTER
+       help
+         This enables access to Microchip 23K256 SRAM chips, using SPI.
+
+         Set up your spi devices with the right board-specific
+         platform data, or a device tree description if you want to
+         specify device partitioning
+
 config MTD_SPEAR_SMI
        tristate "SPEAR MTD NOR Support through SMI controller"
        depends on PLAT_SPEAR
index 7912d3a..f0f7676 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_MTD_LART)                += lart.o
 obj-$(CONFIG_MTD_BLOCK2MTD)    += block2mtd.o
 obj-$(CONFIG_MTD_DATAFLASH)    += mtd_dataflash.o
 obj-$(CONFIG_MTD_M25P80)       += m25p80.o
+obj-$(CONFIG_MTD_MCHP23K256)   += mchp23k256.o
 obj-$(CONFIG_MTD_SPEAR_SMI)    += spear_smi.o
 obj-$(CONFIG_MTD_SST25L)       += sst25l.o
 obj-$(CONFIG_MTD_BCM47XXSFLASH)        += bcm47xxsflash.o
index c4df3b1..00eea6f 100644 (file)
@@ -78,11 +78,17 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
 {
        struct m25p *flash = nor->priv;
        struct spi_device *spi = flash->spi;
-       struct spi_transfer t[2] = {};
+       unsigned int inst_nbits, addr_nbits, data_nbits, data_idx;
+       struct spi_transfer t[3] = {};
        struct spi_message m;
        int cmd_sz = m25p_cmdsz(nor);
        ssize_t ret;
 
+       /* get transfer protocols. */
+       inst_nbits = spi_nor_get_protocol_inst_nbits(nor->write_proto);
+       addr_nbits = spi_nor_get_protocol_addr_nbits(nor->write_proto);
+       data_nbits = spi_nor_get_protocol_data_nbits(nor->write_proto);
+
        spi_message_init(&m);
 
        if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
@@ -92,12 +98,27 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
        m25p_addr2cmd(nor, to, flash->command);
 
        t[0].tx_buf = flash->command;
+       t[0].tx_nbits = inst_nbits;
        t[0].len = cmd_sz;
        spi_message_add_tail(&t[0], &m);
 
-       t[1].tx_buf = buf;
-       t[1].len = len;
-       spi_message_add_tail(&t[1], &m);
+       /* split the op code and address bytes into two transfers if needed. */
+       data_idx = 1;
+       if (addr_nbits != inst_nbits) {
+               t[0].len = 1;
+
+               t[1].tx_buf = &flash->command[1];
+               t[1].tx_nbits = addr_nbits;
+               t[1].len = cmd_sz - 1;
+               spi_message_add_tail(&t[1], &m);
+
+               data_idx = 2;
+       }
+
+       t[data_idx].tx_buf = buf;
+       t[data_idx].tx_nbits = data_nbits;
+       t[data_idx].len = len;
+       spi_message_add_tail(&t[data_idx], &m);
 
        ret = spi_sync(spi, &m);
        if (ret)
@@ -109,18 +130,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
        return ret;
 }
 
-static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
-{
-       switch (nor->flash_read) {
-       case SPI_NOR_DUAL:
-               return 2;
-       case SPI_NOR_QUAD:
-               return 4;
-       default:
-               return 0;
-       }
-}
-
 /*
  * Read an address range from the nor chip.  The address range
  * may be any size provided it is within the physical boundaries.
@@ -130,13 +139,20 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 {
        struct m25p *flash = nor->priv;
        struct spi_device *spi = flash->spi;
-       struct spi_transfer t[2];
+       unsigned int inst_nbits, addr_nbits, data_nbits, data_idx;
+       struct spi_transfer t[3];
        struct spi_message m;
        unsigned int dummy = nor->read_dummy;
        ssize_t ret;
+       int cmd_sz;
+
+       /* get transfer protocols. */
+       inst_nbits = spi_nor_get_protocol_inst_nbits(nor->read_proto);
+       addr_nbits = spi_nor_get_protocol_addr_nbits(nor->read_proto);
+       data_nbits = spi_nor_get_protocol_data_nbits(nor->read_proto);
 
        /* convert the dummy cycles to the number of bytes */
-       dummy /= 8;
+       dummy = (dummy * addr_nbits) / 8;
 
        if (spi_flash_read_supported(spi)) {
                struct spi_flash_read_message msg;
@@ -149,10 +165,9 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
                msg.read_opcode = nor->read_opcode;
                msg.addr_width = nor->addr_width;
                msg.dummy_bytes = dummy;
-               /* TODO: Support other combinations */
-               msg.opcode_nbits = SPI_NBITS_SINGLE;
-               msg.addr_nbits = SPI_NBITS_SINGLE;
-               msg.data_nbits = m25p80_rx_nbits(nor);
+               msg.opcode_nbits = inst_nbits;
+               msg.addr_nbits = addr_nbits;
+               msg.data_nbits = data_nbits;
 
                ret = spi_flash_read(spi, &msg);
                if (ret < 0)
@@ -167,20 +182,45 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
        m25p_addr2cmd(nor, from, flash->command);
 
        t[0].tx_buf = flash->command;
+       t[0].tx_nbits = inst_nbits;
        t[0].len = m25p_cmdsz(nor) + dummy;
        spi_message_add_tail(&t[0], &m);
 
-       t[1].rx_buf = buf;
-       t[1].rx_nbits = m25p80_rx_nbits(nor);
-       t[1].len = min3(len, spi_max_transfer_size(spi),
-                       spi_max_message_size(spi) - t[0].len);
-       spi_message_add_tail(&t[1], &m);
+       /*
+        * Set all dummy/mode cycle bits to avoid sending some manufacturer
+        * specific pattern, which might make the memory enter its Continuous
+        * Read mode by mistake.
+        * Based on the different mode cycle bit patterns listed and described
+        * in the JESD216B specification, the 0xff value works for all memories
+        * and all manufacturers.
+        */
+       cmd_sz = t[0].len;
+       memset(flash->command + cmd_sz - dummy, 0xff, dummy);
+
+       /* split the op code and address bytes into two transfers if needed. */
+       data_idx = 1;
+       if (addr_nbits != inst_nbits) {
+               t[0].len = 1;
+
+               t[1].tx_buf = &flash->command[1];
+               t[1].tx_nbits = addr_nbits;
+               t[1].len = cmd_sz - 1;
+               spi_message_add_tail(&t[1], &m);
+
+               data_idx = 2;
+       }
+
+       t[data_idx].rx_buf = buf;
+       t[data_idx].rx_nbits = data_nbits;
+       t[data_idx].len = min3(len, spi_max_transfer_size(spi),
+                              spi_max_message_size(spi) - cmd_sz);
+       spi_message_add_tail(&t[data_idx], &m);
 
        ret = spi_sync(spi, &m);
        if (ret)
                return ret;
 
-       ret = m.actual_length - m25p_cmdsz(nor) - dummy;
+       ret = m.actual_length - cmd_sz;
        if (ret < 0)
                return -EIO;
        return ret;
@@ -196,7 +236,11 @@ static int m25p_probe(struct spi_device *spi)
        struct flash_platform_data      *data;
        struct m25p *flash;
        struct spi_nor *nor;
-       enum read_mode mode = SPI_NOR_NORMAL;
+       struct spi_nor_hwcaps hwcaps = {
+               .mask = SNOR_HWCAPS_READ |
+                       SNOR_HWCAPS_READ_FAST |
+                       SNOR_HWCAPS_PP,
+       };
        char *flash_name;
        int ret;
 
@@ -221,10 +265,19 @@ static int m25p_probe(struct spi_device *spi)
        spi_set_drvdata(spi, flash);
        flash->spi = spi;
 
-       if (spi->mode & SPI_RX_QUAD)
-               mode = SPI_NOR_QUAD;
-       else if (spi->mode & SPI_RX_DUAL)
-               mode = SPI_NOR_DUAL;
+       if (spi->mode & SPI_RX_QUAD) {
+               hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
+
+               if (spi->mode & SPI_TX_QUAD)
+                       hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 |
+                                       SNOR_HWCAPS_PP_1_1_4 |
+                                       SNOR_HWCAPS_PP_1_4_4);
+       } else if (spi->mode & SPI_RX_DUAL) {
+               hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
+
+               if (spi->mode & SPI_TX_DUAL)
+                       hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2;
+       }
 
        if (data && data->name)
                nor->mtd.name = data->name;
@@ -241,7 +294,7 @@ static int m25p_probe(struct spi_device *spi)
        else
                flash_name = spi->modalias;
 
-       ret = spi_nor_scan(nor, flash_name, mode);
+       ret = spi_nor_scan(nor, flash_name, &hwcaps);
        if (ret)
                return ret;
 
diff --git a/drivers/mtd/devices/mchp23k256.c b/drivers/mtd/devices/mchp23k256.c
new file mode 100644 (file)
index 0000000..8956b7d
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * mchp23k256.c
+ *
+ * Driver for Microchip 23k256 SPI RAM chips
+ *
+ * Copyright © 2016 Andrew Lunn <andrew@lunn.ch>
+ *
+ * This code 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/device.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/sizes.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/of_device.h>
+
+#define MAX_CMD_SIZE           4
+
+struct mchp23_caps {
+       u8 addr_width;
+       unsigned int size;
+};
+
+struct mchp23k256_flash {
+       struct spi_device       *spi;
+       struct mutex            lock;
+       struct mtd_info         mtd;
+       const struct mchp23_caps        *caps;
+};
+
+#define MCHP23K256_CMD_WRITE_STATUS    0x01
+#define MCHP23K256_CMD_WRITE           0x02
+#define MCHP23K256_CMD_READ            0x03
+#define MCHP23K256_MODE_SEQ            BIT(6)
+
+#define to_mchp23k256_flash(x) container_of(x, struct mchp23k256_flash, mtd)
+
+static void mchp23k256_addr2cmd(struct mchp23k256_flash *flash,
+                               unsigned int addr, u8 *cmd)
+{
+       int i;
+
+       /*
+        * Address is sent in big endian (MSB first) and we skip
+        * the first entry of the cmd array which contains the cmd
+        * opcode.
+        */
+       for (i = flash->caps->addr_width; i > 0; i--, addr >>= 8)
+               cmd[i] = addr;
+}
+
+static int mchp23k256_cmdsz(struct mchp23k256_flash *flash)
+{
+       return 1 + flash->caps->addr_width;
+}
+
+static int mchp23k256_write(struct mtd_info *mtd, loff_t to, size_t len,
+                           size_t *retlen, const unsigned char *buf)
+{
+       struct mchp23k256_flash *flash = to_mchp23k256_flash(mtd);
+       struct spi_transfer transfer[2] = {};
+       struct spi_message message;
+       unsigned char command[MAX_CMD_SIZE];
+
+       spi_message_init(&message);
+
+       command[0] = MCHP23K256_CMD_WRITE;
+       mchp23k256_addr2cmd(flash, to, command);
+
+       transfer[0].tx_buf = command;
+       transfer[0].len = mchp23k256_cmdsz(flash);
+       spi_message_add_tail(&transfer[0], &message);
+
+       transfer[1].tx_buf = buf;
+       transfer[1].len = len;
+       spi_message_add_tail(&transfer[1], &message);
+
+       mutex_lock(&flash->lock);
+
+       spi_sync(flash->spi, &message);
+
+       if (retlen && message.actual_length > sizeof(command))
+               *retlen += message.actual_length - sizeof(command);
+
+       mutex_unlock(&flash->lock);
+       return 0;
+}
+
+static int mchp23k256_read(struct mtd_info *mtd, loff_t from, size_t len,
+                          size_t *retlen, unsigned char *buf)
+{
+       struct mchp23k256_flash *flash = to_mchp23k256_flash(mtd);
+       struct spi_transfer transfer[2] = {};
+       struct spi_message message;
+       unsigned char command[MAX_CMD_SIZE];
+
+       spi_message_init(&message);
+
+       memset(&transfer, 0, sizeof(transfer));
+       command[0] = MCHP23K256_CMD_READ;
+       mchp23k256_addr2cmd(flash, from, command);
+
+       transfer[0].tx_buf = command;
+       transfer[0].len = mchp23k256_cmdsz(flash);
+       spi_message_add_tail(&transfer[0], &message);
+
+       transfer[1].rx_buf = buf;
+       transfer[1].len = len;
+       spi_message_add_tail(&transfer[1], &message);
+
+       mutex_lock(&flash->lock);
+
+       spi_sync(flash->spi, &message);
+
+       if (retlen && message.actual_length > sizeof(command))
+               *retlen += message.actual_length - sizeof(command);
+
+       mutex_unlock(&flash->lock);
+       return 0;
+}
+
+/*
+ * Set the device into sequential mode. This allows read/writes to the
+ * entire SRAM in a single operation
+ */
+static int mchp23k256_set_mode(struct spi_device *spi)
+{
+       struct spi_transfer transfer = {};
+       struct spi_message message;
+       unsigned char command[2];
+
+       spi_message_init(&message);
+
+       command[0] = MCHP23K256_CMD_WRITE_STATUS;
+       command[1] = MCHP23K256_MODE_SEQ;
+
+       transfer.tx_buf = command;
+       transfer.len = sizeof(command);
+       spi_message_add_tail(&transfer, &message);
+
+       return spi_sync(spi, &message);
+}
+
+static const struct mchp23_caps mchp23k256_caps = {
+       .size = SZ_32K,
+       .addr_width = 2,
+};
+
+static const struct mchp23_caps mchp23lcv1024_caps = {
+       .size = SZ_128K,
+       .addr_width = 3,
+};
+
+static int mchp23k256_probe(struct spi_device *spi)
+{
+       struct mchp23k256_flash *flash;
+       struct flash_platform_data *data;
+       int err;
+
+       flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
+       if (!flash)
+               return -ENOMEM;
+
+       flash->spi = spi;
+       mutex_init(&flash->lock);
+       spi_set_drvdata(spi, flash);
+
+       err = mchp23k256_set_mode(spi);
+       if (err)
+               return err;
+
+       data = dev_get_platdata(&spi->dev);
+
+       flash->caps = of_device_get_match_data(&spi->dev);
+       if (!flash->caps)
+               flash->caps = &mchp23k256_caps;
+
+       mtd_set_of_node(&flash->mtd, spi->dev.of_node);
+       flash->mtd.dev.parent   = &spi->dev;
+       flash->mtd.type         = MTD_RAM;
+       flash->mtd.flags        = MTD_CAP_RAM;
+       flash->mtd.writesize    = 1;
+       flash->mtd.size         = flash->caps->size;
+       flash->mtd._read        = mchp23k256_read;
+       flash->mtd._write       = mchp23k256_write;
+
+       err = mtd_device_register(&flash->mtd, data ? data->parts : NULL,
+                                 data ? data->nr_parts : 0);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int mchp23k256_remove(struct spi_device *spi)
+{
+       struct mchp23k256_flash *flash = spi_get_drvdata(spi);
+
+       return mtd_device_unregister(&flash->mtd);
+}
+
+static const struct of_device_id mchp23k256_of_table[] = {
+       {
+               .compatible = "microchip,mchp23k256",
+               .data = &mchp23k256_caps,
+       },
+       {
+               .compatible = "microchip,mchp23lcv1024",
+               .data = &mchp23lcv1024_caps,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mchp23k256_of_table);
+
+static struct spi_driver mchp23k256_driver = {
+       .driver = {
+               .name   = "mchp23k256",
+               .of_match_table = of_match_ptr(mchp23k256_of_table),
+       },
+       .probe          = mchp23k256_probe,
+       .remove         = mchp23k256_remove,
+};
+
+module_spi_driver(mchp23k256_driver);
+
+MODULE_DESCRIPTION("MTD SPI driver for MCHP23K256 RAM chips");
+MODULE_AUTHOR("Andrew Lunn <andre@lunn.ch>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:mchp23k256");
index f9e9bd1..5dc8bd0 100644 (file)
 #define OP_WRITE_SECURITY_REVC 0x9A
 #define OP_WRITE_SECURITY      0x9B    /* revision D */
 
+#define CFI_MFR_ATMEL          0x1F
+
+#define DATAFLASH_SHIFT_EXTID  24
+#define DATAFLASH_SHIFT_ID     40
 
 struct dataflash {
-       uint8_t                 command[4];
+       u8                      command[4];
        char                    name[24];
 
        unsigned short          page_offset;    /* offset in flash address */
@@ -129,8 +133,7 @@ static int dataflash_waitready(struct spi_device *spi)
        for (;;) {
                status = dataflash_status(spi);
                if (status < 0) {
-                       pr_debug("%s: status %d?\n",
-                                       dev_name(&spi->dev), status);
+                       dev_dbg(&spi->dev, "status %d?\n", status);
                        status = 0;
                }
 
@@ -153,12 +156,11 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
        struct spi_transfer     x = { };
        struct spi_message      msg;
        unsigned                blocksize = priv->page_size << 3;
-       uint8_t                 *command;
-       uint32_t                rem;
+       u8                      *command;
+       u32                     rem;
 
-       pr_debug("%s: erase addr=0x%llx len 0x%llx\n",
-             dev_name(&spi->dev), (long long)instr->addr,
-             (long long)instr->len);
+       dev_dbg(&spi->dev, "erase addr=0x%llx len 0x%llx\n",
+               (long long)instr->addr, (long long)instr->len);
 
        div_u64_rem(instr->len, priv->page_size, &rem);
        if (rem)
@@ -187,11 +189,11 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
                pageaddr = pageaddr << priv->page_offset;
 
                command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE;
-               command[1] = (uint8_t)(pageaddr >> 16);
-               command[2] = (uint8_t)(pageaddr >> 8);
+               command[1] = (u8)(pageaddr >> 16);
+               command[2] = (u8)(pageaddr >> 8);
                command[3] = 0;
 
-               pr_debug("ERASE %s: (%x) %x %x %x [%i]\n",
+               dev_dbg(&spi->dev, "ERASE %s: (%x) %x %x %x [%i]\n",
                        do_block ? "block" : "page",
                        command[0], command[1], command[2], command[3],
                        pageaddr);
@@ -200,8 +202,8 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
                (void) dataflash_waitready(spi);
 
                if (status < 0) {
-                       printk(KERN_ERR "%s: erase %x, err %d\n",
-                               dev_name(&spi->dev), pageaddr, status);
+                       dev_err(&spi->dev, "erase %x, err %d\n",
+                               pageaddr, status);
                        /* REVISIT:  can retry instr->retries times; or
                         * giveup and instr->fail_addr = instr->addr;
                         */
@@ -239,11 +241,11 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
        struct spi_transfer     x[2] = { };
        struct spi_message      msg;
        unsigned int            addr;
-       uint8_t                 *command;
+       u8                      *command;
        int                     status;
 
-       pr_debug("%s: read 0x%x..0x%x\n", dev_name(&priv->spi->dev),
-                       (unsigned)from, (unsigned)(from + len));
+       dev_dbg(&priv->spi->dev, "read 0x%x..0x%x\n",
+                 (unsigned int)from, (unsigned int)(from + len));
 
        /* Calculate flash page/byte address */
        addr = (((unsigned)from / priv->page_size) << priv->page_offset)
@@ -251,7 +253,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
 
        command = priv->command;
 
-       pr_debug("READ: (%x) %x %x %x\n",
+       dev_dbg(&priv->spi->dev, "READ: (%x) %x %x %x\n",
                command[0], command[1], command[2], command[3]);
 
        spi_message_init(&msg);
@@ -271,9 +273,9 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
         * fewer "don't care" bytes.  Both buffers stay unchanged.
         */
        command[0] = OP_READ_CONTINUOUS;
-       command[1] = (uint8_t)(addr >> 16);
-       command[2] = (uint8_t)(addr >> 8);
-       command[3] = (uint8_t)(addr >> 0);
+       command[1] = (u8)(addr >> 16);
+       command[2] = (u8)(addr >> 8);
+       command[3] = (u8)(addr >> 0);
        /* plus 4 "don't care" bytes */
 
        status = spi_sync(priv->spi, &msg);
@@ -283,8 +285,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
                *retlen = msg.actual_length - 8;
                status = 0;
        } else
-               pr_debug("%s: read %x..%x --> %d\n",
-                       dev_name(&priv->spi->dev),
+               dev_dbg(&priv->spi->dev, "read %x..%x --> %d\n",
                        (unsigned)from, (unsigned)(from + len),
                        status);
        return status;
@@ -308,10 +309,10 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
        size_t                  remaining = len;
        u_char                  *writebuf = (u_char *) buf;
        int                     status = -EINVAL;
-       uint8_t                 *command;
+       u8                      *command;
 
-       pr_debug("%s: write 0x%x..0x%x\n",
-               dev_name(&spi->dev), (unsigned)to, (unsigned)(to + len));
+       dev_dbg(&spi->dev, "write 0x%x..0x%x\n",
+               (unsigned int)to, (unsigned int)(to + len));
 
        spi_message_init(&msg);
 
@@ -328,7 +329,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
 
        mutex_lock(&priv->lock);
        while (remaining > 0) {
-               pr_debug("write @ %i:%i len=%i\n",
+               dev_dbg(&spi->dev, "write @ %i:%i len=%i\n",
                        pageaddr, offset, writelen);
 
                /* REVISIT:
@@ -356,13 +357,13 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
                        command[2] = (addr & 0x0000FF00) >> 8;
                        command[3] = 0;
 
-                       pr_debug("TRANSFER: (%x) %x %x %x\n",
+                       dev_dbg(&spi->dev, "TRANSFER: (%x) %x %x %x\n",
                                command[0], command[1], command[2], command[3]);
 
                        status = spi_sync(spi, &msg);
                        if (status < 0)
-                               pr_debug("%s: xfer %u -> %d\n",
-                                       dev_name(&spi->dev), addr, status);
+                               dev_dbg(&spi->dev, "xfer %u -> %d\n",
+                                       addr, status);
 
                        (void) dataflash_waitready(priv->spi);
                }
@@ -374,7 +375,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
                command[2] = (addr & 0x0000FF00) >> 8;
                command[3] = (addr & 0x000000FF);
 
-               pr_debug("PROGRAM: (%x) %x %x %x\n",
+               dev_dbg(&spi->dev, "PROGRAM: (%x) %x %x %x\n",
                        command[0], command[1], command[2], command[3]);
 
                x[1].tx_buf = writebuf;
@@ -383,8 +384,8 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
                status = spi_sync(spi, &msg);
                spi_transfer_del(x + 1);
                if (status < 0)
-                       pr_debug("%s: pgm %u/%u -> %d\n",
-                               dev_name(&spi->dev), addr, writelen, status);
+                       dev_dbg(&spi->dev, "pgm %u/%u -> %d\n",
+                               addr, writelen, status);
 
                (void) dataflash_waitready(priv->spi);
 
@@ -398,20 +399,20 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
                command[2] = (addr & 0x0000FF00) >> 8;
                command[3] = 0;
 
-               pr_debug("COMPARE: (%x) %x %x %x\n",
+               dev_dbg(&spi->dev, "COMPARE: (%x) %x %x %x\n",
                        command[0], command[1], command[2], command[3]);
 
                status = spi_sync(spi, &msg);
                if (status < 0)
-                       pr_debug("%s: compare %u -> %d\n",
-                               dev_name(&spi->dev), addr, status);
+                       dev_dbg(&spi->dev, "compare %u -> %d\n",
+                               addr, status);
 
                status = dataflash_waitready(priv->spi);
 
                /* Check result of the compare operation */
                if (status & (1 << 6)) {
-                       printk(KERN_ERR "%s: compare page %u, err %d\n",
-                               dev_name(&spi->dev), pageaddr, status);
+                       dev_err(&spi->dev, "compare page %u, err %d\n",
+                               pageaddr, status);
                        remaining = 0;
                        status = -EIO;
                        break;
@@ -455,11 +456,11 @@ static int dataflash_get_otp_info(struct mtd_info *mtd, size_t len,
 }
 
 static ssize_t otp_read(struct spi_device *spi, unsigned base,
-               uint8_t *buf, loff_t off, size_t len)
+               u8 *buf, loff_t off, size_t len)
 {
        struct spi_message      m;
        size_t                  l;
-       uint8_t                 *scratch;
+       u8                      *scratch;
        struct spi_transfer     t;
        int                     status;
 
@@ -538,7 +539,7 @@ static int dataflash_write_user_otp(struct mtd_info *mtd,
 {
        struct spi_message      m;
        const size_t            l = 4 + 64;
-       uint8_t                 *scratch;
+       u8                      *scratch;
        struct spi_transfer     t;
        struct dataflash        *priv = mtd->priv;
        int                     status;
@@ -689,14 +690,15 @@ struct flash_info {
        /* JEDEC id has a high byte of zero plus three data bytes:
         * the manufacturer id, then a two byte device id.
         */
-       uint32_t        jedec_id;
+       u64             jedec_id;
 
        /* The size listed here is what works with OP_ERASE_PAGE. */
        unsigned        nr_pages;
-       uint16_t        pagesize;
-       uint16_t        pageoffset;
+       u16             pagesize;
+       u16             pageoffset;
 
-       uint16_t        flags;
+       u16             flags;
+#define SUP_EXTID      0x0004          /* supports extended ID data */
 #define SUP_POW2PS     0x0002          /* supports 2^N byte pages */
 #define IS_POW2PS      0x0001          /* uses 2^N byte pages */
 };
@@ -734,54 +736,32 @@ static struct flash_info dataflash_data[] = {
 
        { "AT45DB642x",  0x1f2800, 8192, 1056, 11, SUP_POW2PS},
        { "at45db642d",  0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS},
+
+       { "AT45DB641E",  0x1f28000100, 32768, 264, 9, SUP_EXTID | SUP_POW2PS},
+       { "at45db641e",  0x1f28000100, 32768, 256, 8, SUP_EXTID | SUP_POW2PS | IS_POW2PS},
 };
 
-static struct flash_info *jedec_probe(struct spi_device *spi)
+static struct flash_info *jedec_lookup(struct spi_device *spi,
+                                      u64 jedec, bool use_extid)
 {
-       int                     tmp;
-       uint8_t                 code = OP_READ_ID;
-       uint8_t                 id[3];
-       uint32_t                jedec;
-       struct flash_info       *info;
+       struct flash_info *info;
        int status;
 
-       /* JEDEC also defines an optional "extended device information"
-        * string for after vendor-specific data, after the three bytes
-        * we use here.  Supporting some chips might require using it.
-        *
-        * If the vendor ID isn't Atmel's (0x1f), assume this call failed.
-        * That's not an error; only rev C and newer chips handle it, and
-        * only Atmel sells these chips.
-        */
-       tmp = spi_write_then_read(spi, &code, 1, id, 3);
-       if (tmp < 0) {
-               pr_debug("%s: error %d reading JEDEC ID\n",
-                       dev_name(&spi->dev), tmp);
-               return ERR_PTR(tmp);
-       }
-       if (id[0] != 0x1f)
-               return NULL;
-
-       jedec = id[0];
-       jedec = jedec << 8;
-       jedec |= id[1];
-       jedec = jedec << 8;
-       jedec |= id[2];
+       for (info = dataflash_data;
+            info < dataflash_data + ARRAY_SIZE(dataflash_data);
+            info++) {
+               if (use_extid && !(info->flags & SUP_EXTID))
+                       continue;
 
-       for (tmp = 0, info = dataflash_data;
-                       tmp < ARRAY_SIZE(dataflash_data);
-                       tmp++, info++) {
                if (info->jedec_id == jedec) {
-                       pr_debug("%s: OTP, sector protect%s\n",
-                               dev_name(&spi->dev),
-                               (info->flags & SUP_POW2PS)
-                                       ? ", binary pagesize" : ""
-                               );
+                       dev_dbg(&spi->dev, "OTP, sector protect%s\n",
+                               (info->flags & SUP_POW2PS) ?
+                               ", binary pagesize" : "");
                        if (info->flags & SUP_POW2PS) {
                                status = dataflash_status(spi);
                                if (status < 0) {
-                                       pr_debug("%s: status error %d\n",
-                                               dev_name(&spi->dev), status);
+                                       dev_dbg(&spi->dev, "status error %d\n",
+                                               status);
                                        return ERR_PTR(status);
                                }
                                if (status & 0x1) {
@@ -796,12 +776,58 @@ static struct flash_info *jedec_probe(struct spi_device *spi)
                }
        }
 
+       return ERR_PTR(-ENODEV);
+}
+
+static struct flash_info *jedec_probe(struct spi_device *spi)
+{
+       int ret;
+       u8 code = OP_READ_ID;
+       u64 jedec;
+       u8 id[sizeof(jedec)] = {0};
+       const unsigned int id_size = 5;
+       struct flash_info *info;
+
+       /*
+        * JEDEC also defines an optional "extended device information"
+        * string for after vendor-specific data, after the three bytes
+        * we use here.  Supporting some chips might require using it.
+        *
+        * If the vendor ID isn't Atmel's (0x1f), assume this call failed.
+        * That's not an error; only rev C and newer chips handle it, and
+        * only Atmel sells these chips.
+        */
+       ret = spi_write_then_read(spi, &code, 1, id, id_size);
+       if (ret < 0) {
+               dev_dbg(&spi->dev, "error %d reading JEDEC ID\n", ret);
+               return ERR_PTR(ret);
+       }
+
+       if (id[0] != CFI_MFR_ATMEL)
+               return NULL;
+
+       jedec = be64_to_cpup((__be64 *)id);
+
+       /*
+        * First, try to match device using extended device
+        * information
+        */
+       info = jedec_lookup(spi, jedec >> DATAFLASH_SHIFT_EXTID, true);
+       if (!IS_ERR(info))
+               return info;
+       /*
+        * If that fails, make another pass using regular ID
+        * information
+        */
+       info = jedec_lookup(spi, jedec >> DATAFLASH_SHIFT_ID, false);
+       if (!IS_ERR(info))
+               return info;
        /*
         * Treat other chips as errors ... we won't know the right page
         * size (it might be binary) even when we can tell which density
         * class is involved (legacy chip id scheme).
         */
-       dev_warn(&spi->dev, "JEDEC id %06x not handled\n", jedec);
+       dev_warn(&spi->dev, "JEDEC id %016llx not handled\n", jedec);
        return ERR_PTR(-ENODEV);
 }
 
@@ -845,8 +871,7 @@ static int dataflash_probe(struct spi_device *spi)
         */
        status = dataflash_status(spi);
        if (status <= 0 || status == 0xff) {
-               pr_debug("%s: status error %d\n",
-                               dev_name(&spi->dev), status);
+               dev_dbg(&spi->dev, "status error %d\n", status);
                if (status == 0 || status == 0xff)
                        status = -ENODEV;
                return status;
@@ -887,8 +912,7 @@ static int dataflash_probe(struct spi_device *spi)
        }
 
        if (status < 0)
-               pr_debug("%s: add_dataflash --> %d\n", dev_name(&spi->dev),
-                               status);
+               dev_dbg(&spi->dev, "add_dataflash --> %d\n", status);
 
        return status;
 }
@@ -898,7 +922,7 @@ static int dataflash_remove(struct spi_device *spi)
        struct dataflash        *flash = spi_get_drvdata(spi);
        int                     status;
 
-       pr_debug("%s: remove\n", dev_name(&spi->dev));
+       dev_dbg(&spi->dev, "remove\n");
 
        status = mtd_device_unregister(&flash->mtd);
        if (status == 0)
index 8b81e15..eba125c 100644 (file)
@@ -13,7 +13,6 @@
 #define _MTD_SERIAL_FLASH_CMDS_H
 
 /* Generic Flash Commands/OPCODEs */
-#define SPINOR_OP_RDSR2                0x35
 #define SPINOR_OP_WRVCR                0x81
 #define SPINOR_OP_RDVCR                0x85
 
index 804313a..21afd94 100644 (file)
@@ -1445,7 +1445,7 @@ static int stfsm_s25fl_config(struct stfsm *fsm)
        }
 
        /* Check status of 'QE' bit, update if required. */
-       stfsm_read_status(fsm, SPINOR_OP_RDSR2, &cr1, 1);
+       stfsm_read_status(fsm, SPINOR_OP_RDCR, &cr1, 1);
        data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
        if (data_pads == 4) {
                if (!(cr1 & STFSM_S25FL_CONFIG_QE)) {
@@ -1490,7 +1490,7 @@ static int stfsm_w25q_config(struct stfsm *fsm)
                return ret;
 
        /* Check status of 'QE' bit, update if required. */
-       stfsm_read_status(fsm, SPINOR_OP_RDSR2, &sr2, 1);
+       stfsm_read_status(fsm, SPINOR_OP_RDCR, &sr2, 1);
        data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
        if (data_pads == 4) {
                if (!(sr2 & W25Q_STATUS_QE)) {
index 9d371cd..05b286b 100644 (file)
@@ -59,7 +59,7 @@ int of_flash_probe_gemini(struct platform_device *pdev,
                          struct device_node *np,
                          struct map_info *map)
 {
-       static struct regmap *rmap;
+       struct regmap *rmap;
        struct device *dev = &pdev->dev;
        u32 val;
        int ret;
index 1517da3..956382c 100644 (file)
@@ -991,7 +991,7 @@ EXPORT_SYMBOL_GPL(mtd_point);
 /* We probably shouldn't allow XIP if the unpoint isn't a NULL */
 int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
-       if (!mtd->_point)
+       if (!mtd->_unpoint)
                return -EOPNOTSUPP;
        if (from < 0 || from >= mtd->size || len > mtd->size - from)
                return -EINVAL;
index ea5e530..5736b0c 100644 (file)
 static LIST_HEAD(mtd_partitions);
 static DEFINE_MUTEX(mtd_partitions_mutex);
 
-/* Our partition node structure */
+/**
+ * struct mtd_part - our partition node structure
+ *
+ * @mtd: struct holding partition details
+ * @parent: parent mtd - flash device or another partition
+ * @offset: partition offset relative to the *flash device*
+ */
 struct mtd_part {
        struct mtd_info mtd;
-       struct mtd_info *master;
+       struct mtd_info *parent;
        uint64_t offset;
        struct list_head list;
 };
@@ -67,15 +73,15 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
        struct mtd_ecc_stats stats;
        int res;
 
-       stats = part->master->ecc_stats;
-       res = part->master->_read(part->master, from + part->offset, len,
+       stats = part->parent->ecc_stats;
+       res = part->parent->_read(part->parent, from + part->offset, len,
                                  retlen, buf);
        if (unlikely(mtd_is_eccerr(res)))
                mtd->ecc_stats.failed +=
-                       part->master->ecc_stats.failed - stats.failed;
+                       part->parent->ecc_stats.failed - stats.failed;
        else
                mtd->ecc_stats.corrected +=
-                       part->master->ecc_stats.corrected - stats.corrected;
+                       part->parent->ecc_stats.corrected - stats.corrected;
        return res;
 }
 
@@ -84,7 +90,7 @@ static int part_point(struct mtd_info *mtd, loff_t from, size_t len,
 {
        struct mtd_part *part = mtd_to_part(mtd);
 
-       return part->master->_point(part->master, from + part->offset, len,
+       return part->parent->_point(part->parent, from + part->offset, len,
                                    retlen, virt, phys);
 }
 
@@ -92,7 +98,7 @@ static int part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
        struct mtd_part *part = mtd_to_part(mtd);
 
-       return part->master->_unpoint(part->master, from + part->offset, len);
+       return part->parent->_unpoint(part->parent, from + part->offset, len);
 }
 
 static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
@@ -103,7 +109,7 @@ static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
        struct mtd_part *part = mtd_to_part(mtd);
 
        offset += part->offset;
-       return part->master->_get_unmapped_area(part->master, len, offset,
+       return part->parent->_get_unmapped_area(part->parent, len, offset,
                                                flags);
 }
 
@@ -132,7 +138,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
                        return -EINVAL;
        }
 
-       res = part->master->_read_oob(part->master, from + part->offset, ops);
+       res = part->parent->_read_oob(part->parent, from + part->offset, ops);
        if (unlikely(res)) {
                if (mtd_is_bitflip(res))
                        mtd->ecc_stats.corrected++;
@@ -146,7 +152,7 @@ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
                size_t len, size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_read_user_prot_reg(part->master, from, len,
+       return part->parent->_read_user_prot_reg(part->parent, from, len,
                                                 retlen, buf);
 }
 
@@ -154,7 +160,7 @@ static int part_get_user_prot_info(struct mtd_info *mtd, size_t len,
                                   size_t *retlen, struct otp_info *buf)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_get_user_prot_info(part->master, len, retlen,
+       return part->parent->_get_user_prot_info(part->parent, len, retlen,
                                                 buf);
 }
 
@@ -162,7 +168,7 @@ static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
                size_t len, size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_read_fact_prot_reg(part->master, from, len,
+       return part->parent->_read_fact_prot_reg(part->parent, from, len,
                                                 retlen, buf);
 }
 
@@ -170,7 +176,7 @@ static int part_get_fact_prot_info(struct mtd_info *mtd, size_t len,
                                   size_t *retlen, struct otp_info *buf)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_get_fact_prot_info(part->master, len, retlen,
+       return part->parent->_get_fact_prot_info(part->parent, len, retlen,
                                                 buf);
 }
 
@@ -178,7 +184,7 @@ static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
                size_t *retlen, const u_char *buf)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_write(part->master, to + part->offset, len,
+       return part->parent->_write(part->parent, to + part->offset, len,
                                    retlen, buf);
 }
 
@@ -186,7 +192,7 @@ static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
                size_t *retlen, const u_char *buf)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_panic_write(part->master, to + part->offset, len,
+       return part->parent->_panic_write(part->parent, to + part->offset, len,
                                          retlen, buf);
 }
 
@@ -199,14 +205,14 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to,
                return -EINVAL;
        if (ops->datbuf && to + ops->len > mtd->size)
                return -EINVAL;
-       return part->master->_write_oob(part->master, to + part->offset, ops);
+       return part->parent->_write_oob(part->parent, to + part->offset, ops);
 }
 
 static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
                size_t len, size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_write_user_prot_reg(part->master, from, len,
+       return part->parent->_write_user_prot_reg(part->parent, from, len,
                                                  retlen, buf);
 }
 
@@ -214,14 +220,14 @@ static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
                size_t len)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_lock_user_prot_reg(part->master, from, len);
+       return part->parent->_lock_user_prot_reg(part->parent, from, len);
 }
 
 static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,
                unsigned long count, loff_t to, size_t *retlen)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_writev(part->master, vecs, count,
+       return part->parent->_writev(part->parent, vecs, count,
                                     to + part->offset, retlen);
 }
 
@@ -231,7 +237,7 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
        int ret;
 
        instr->addr += part->offset;
-       ret = part->master->_erase(part->master, instr);
+       ret = part->parent->_erase(part->parent, instr);
        if (ret) {
                if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
                        instr->fail_addr -= part->offset;
@@ -257,51 +263,51 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback);
 static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_lock(part->master, ofs + part->offset, len);
+       return part->parent->_lock(part->parent, ofs + part->offset, len);
 }
 
 static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_unlock(part->master, ofs + part->offset, len);
+       return part->parent->_unlock(part->parent, ofs + part->offset, len);
 }
 
 static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_is_locked(part->master, ofs + part->offset, len);
+       return part->parent->_is_locked(part->parent, ofs + part->offset, len);
 }
 
 static void part_sync(struct mtd_info *mtd)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       part->master->_sync(part->master);
+       part->parent->_sync(part->parent);
 }
 
 static int part_suspend(struct mtd_info *mtd)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_suspend(part->master);
+       return part->parent->_suspend(part->parent);
 }
 
 static void part_resume(struct mtd_info *mtd)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       part->master->_resume(part->master);
+       part->parent->_resume(part->parent);
 }
 
 static int part_block_isreserved(struct mtd_info *mtd, loff_t ofs)
 {
        struct mtd_part *part = mtd_to_part(mtd);
        ofs += part->offset;
-       return part->master->_block_isreserved(part->master, ofs);
+       return part->parent->_block_isreserved(part->parent, ofs);
 }
 
 static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
 {
        struct mtd_part *part = mtd_to_part(mtd);
        ofs += part->offset;
-       return part->master->_block_isbad(part->master, ofs);
+       return part->parent->_block_isbad(part->parent, ofs);
 }
 
 static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
@@ -310,7 +316,7 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
        int res;
 
        ofs += part->offset;
-       res = part->master->_block_markbad(part->master, ofs);
+       res = part->parent->_block_markbad(part->parent, ofs);
        if (!res)
                mtd->ecc_stats.badblocks++;
        return res;
@@ -319,13 +325,13 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
 static int part_get_device(struct mtd_info *mtd)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       return part->master->_get_device(part->master);
+       return part->parent->_get_device(part->parent);
 }
 
 static void part_put_device(struct mtd_info *mtd)
 {
        struct mtd_part *part = mtd_to_part(mtd);
-       part->master->_put_device(part->master);
+       part->parent->_put_device(part->parent);
 }
 
 static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
@@ -333,7 +339,7 @@ static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
 {
        struct mtd_part *part = mtd_to_part(mtd);
 
-       return mtd_ooblayout_ecc(part->master, section, oobregion);
+       return mtd_ooblayout_ecc(part->parent, section, oobregion);
 }
 
 static int part_ooblayout_free(struct mtd_info *mtd, int section,
@@ -341,7 +347,7 @@ static int part_ooblayout_free(struct mtd_info *mtd, int section,
 {
        struct mtd_part *part = mtd_to_part(mtd);
 
-       return mtd_ooblayout_free(part->master, section, oobregion);
+       return mtd_ooblayout_free(part->parent, section, oobregion);
 }
 
 static const struct mtd_ooblayout_ops part_ooblayout_ops = {
@@ -353,7 +359,7 @@ static int part_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
 {
        struct mtd_part *part = mtd_to_part(mtd);
 
-       return part->master->_max_bad_blocks(part->master,
+       return part->parent->_max_bad_blocks(part->parent,
                                             ofs + part->offset, len);
 }
 
@@ -363,63 +369,70 @@ static inline void free_partition(struct mtd_part *p)
        kfree(p);
 }
 
-/*
- * This function unregisters and destroy all slave MTD objects which are
- * attached to the given master MTD object.
+/**
+ * mtd_parse_part - parse MTD partition looking for subpartitions
+ *
+ * @slave: part that is supposed to be a container and should be parsed
+ * @types: NULL-terminated array with names of partition parsers to try
+ *
+ * Some partitions are kind of containers with extra subpartitions (volumes).
+ * There can be various formats of such containers. This function tries to use
+ * specified parsers to analyze given partition and registers found
+ * subpartitions on success.
  */
-
-int del_mtd_partitions(struct mtd_info *master)
+static int mtd_parse_part(struct mtd_part *slave, const char *const *types)
 {
-       struct mtd_part *slave, *next;
-       int ret, err = 0;
+       struct mtd_partitions parsed;
+       int err;
 
-       mutex_lock(&mtd_partitions_mutex);
-       list_for_each_entry_safe(slave, next, &mtd_partitions, list)
-               if (slave->master == master) {
-                       ret = del_mtd_device(&slave->mtd);
-                       if (ret < 0) {
-                               err = ret;
-                               continue;
-                       }
-                       list_del(&slave->list);
-                       free_partition(slave);
-               }
-       mutex_unlock(&mtd_partitions_mutex);
+       err = parse_mtd_partitions(&slave->mtd, types, &parsed, NULL);
+       if (err)
+               return err;
+       else if (!parsed.nr_parts)
+               return -ENOENT;
+
+       err = add_mtd_partitions(&slave->mtd, parsed.parts, parsed.nr_parts);
+
+       mtd_part_parser_cleanup(&parsed);
 
        return err;
 }
 
-static struct mtd_part *allocate_partition(struct mtd_info *master,
+static struct mtd_part *allocate_partition(struct mtd_info *parent,
                        const struct mtd_partition *part, int partno,
                        uint64_t cur_offset)
 {
+       int wr_alignment = (parent->flags & MTD_NO_ERASE) ? parent->writesize :
+                                                           parent->erasesize;
        struct mtd_part *slave;
+       u32 remainder;
        char *name;
+       u64 tmp;
 
        /* allocate the partition structure */
        slave = kzalloc(sizeof(*slave), GFP_KERNEL);
        name = kstrdup(part->name, GFP_KERNEL);
        if (!name || !slave) {
                printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n",
-                      master->name);
+                      parent->name);
                kfree(name);
                kfree(slave);
                return ERR_PTR(-ENOMEM);
        }
 
        /* set up the MTD object for this partition */
-       slave->mtd.type = master->type;
-       slave->mtd.flags = master->flags & ~part->mask_flags;
+       slave->mtd.type = parent->type;
+       slave->mtd.flags = parent->flags & ~part->mask_flags;
        slave->mtd.size = part->size;
-       slave->mtd.writesize = master->writesize;
-       slave->mtd.writebufsize = master->writebufsize;
-       slave->mtd.oobsize = master->oobsize;
-       slave->mtd.oobavail = master->oobavail;
-       slave->mtd.subpage_sft = master->subpage_sft;
-       slave->mtd.pairing = master->pairing;
+       slave->mtd.writesize = parent->writesize;
+       slave->mtd.writebufsize = parent->writebufsize;
+       slave->mtd.oobsize = parent->oobsize;
+       slave->mtd.oobavail = parent->oobavail;
+       slave->mtd.subpage_sft = parent->subpage_sft;
+       slave->mtd.pairing = parent->pairing;
 
        slave->mtd.name = name;
-       slave->mtd.owner = master->owner;
+       slave->mtd.owner = parent->owner;
 
        /* NOTE: Historically, we didn't arrange MTDs as a tree out of
         * concern for showing the same data in multiple partitions.
@@ -429,80 +442,81 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
         * parent conditional on that option. Note, this is a way to
         * distinguish between the master and the partition in sysfs.
         */
-       slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) ?
-                               &master->dev :
-                               master->dev.parent;
+       slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) || mtd_is_partition(parent) ?
+                               &parent->dev :
+                               parent->dev.parent;
        slave->mtd.dev.of_node = part->of_node;
 
        slave->mtd._read = part_read;
        slave->mtd._write = part_write;
 
-       if (master->_panic_write)
+       if (parent->_panic_write)
                slave->mtd._panic_write = part_panic_write;
 
-       if (master->_point && master->_unpoint) {
+       if (parent->_point && parent->_unpoint) {
                slave->mtd._point = part_point;
                slave->mtd._unpoint = part_unpoint;
        }
 
-       if (master->_get_unmapped_area)
+       if (parent->_get_unmapped_area)
                slave->mtd._get_unmapped_area = part_get_unmapped_area;
-       if (master->_read_oob)
+       if (parent->_read_oob)
                slave->mtd._read_oob = part_read_oob;
-       if (master->_write_oob)
+       if (parent->_write_oob)
                slave->mtd._write_oob = part_write_oob;
-       if (master->_read_user_prot_reg)
+       if (parent->_read_user_prot_reg)
                slave->mtd._read_user_prot_reg = part_read_user_prot_reg;
-       if (master->_read_fact_prot_reg)
+       if (parent->_read_fact_prot_reg)
                slave->mtd._read_fact_prot_reg = part_read_fact_prot_reg;
-       if (master->_write_user_prot_reg)
+       if (parent->_write_user_prot_reg)
                slave->mtd._write_user_prot_reg = part_write_user_prot_reg;
-       if (master->_lock_user_prot_reg)
+       if (parent->_lock_user_prot_reg)
                slave->mtd._lock_user_prot_reg = part_lock_user_prot_reg;
-       if (master->_get_user_prot_info)
+       if (parent->_get_user_prot_info)
                slave->mtd._get_user_prot_info = part_get_user_prot_info;
-       if (master->_get_fact_prot_info)
+       if (parent->_get_fact_prot_info)
                slave->mtd._get_fact_prot_info = part_get_fact_prot_info;
-       if (master->_sync)
+       if (parent->_sync)
                slave->mtd._sync = part_sync;
-       if (!partno && !master->dev.class && master->_suspend &&
-           master->_resume) {
-                       slave->mtd._suspend = part_suspend;
-                       slave->mtd._resume = part_resume;
+       if (!partno && !parent->dev.class && parent->_suspend &&
+           parent->_resume) {
+               slave->mtd._suspend = part_suspend;
+               slave->mtd._resume = part_resume;
        }
-       if (master->_writev)
+       if (parent->_writev)
                slave->mtd._writev = part_writev;
-       if (master->_lock)
+       if (parent->_lock)
                slave->mtd._lock = part_lock;
-       if (master->_unlock)
+       if (parent->_unlock)
                slave->mtd._unlock = part_unlock;
-       if (master->_is_locked)
+       if (parent->_is_locked)
                slave->mtd._is_locked = part_is_locked;
-       if (master->_block_isreserved)
+       if (parent->_block_isreserved)
                slave->mtd._block_isreserved = part_block_isreserved;
-       if (master->_block_isbad)
+       if (parent->_block_isbad)
                slave->mtd._block_isbad = part_block_isbad;
-       if (master->_block_markbad)
+       if (parent->_block_markbad)
                slave->mtd._block_markbad = part_block_markbad;
-       if (master->_max_bad_blocks)
+       if (parent->_max_bad_blocks)
                slave->mtd._max_bad_blocks = part_max_bad_blocks;
 
-       if (master->_get_device)
+       if (parent->_get_device)
                slave->mtd._get_device = part_get_device;
-       if (master->_put_device)
+       if (parent->_put_device)
                slave->mtd._put_device = part_put_device;
 
        slave->mtd._erase = part_erase;
-       slave->master = master;
+       slave->parent = parent;
        slave->offset = part->offset;
 
        if (slave->offset == MTDPART_OFS_APPEND)
                slave->offset = cur_offset;
        if (slave->offset == MTDPART_OFS_NXTBLK) {
+               tmp = cur_offset;
                slave->offset = cur_offset;
-               if (mtd_mod_by_eb(cur_offset, master) != 0) {
-                       /* Round up to next erasesize */
-                       slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
+               remainder = do_div(tmp, wr_alignment);
+               if (remainder) {
+                       slave->offset += wr_alignment - remainder;
                        printk(KERN_NOTICE "Moving partition %d: "
                               "0x%012llx -> 0x%012llx\n", partno,
                               (unsigned long long)cur_offset, (unsigned long long)slave->offset);
@@ -510,25 +524,25 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
        }
        if (slave->offset == MTDPART_OFS_RETAIN) {
                slave->offset = cur_offset;
-               if (master->size - slave->offset >= slave->mtd.size) {
-                       slave->mtd.size = master->size - slave->offset
+               if (parent->size - slave->offset >= slave->mtd.size) {
+                       slave->mtd.size = parent->size - slave->offset
                                                        - slave->mtd.size;
                } else {
                        printk(KERN_ERR "mtd partition \"%s\" doesn't have enough space: %#llx < %#llx, disabled\n",
-                               part->name, master->size - slave->offset,
+                               part->name, parent->size - slave->offset,
                                slave->mtd.size);
                        /* register to preserve ordering */
                        goto out_register;
                }
        }
        if (slave->mtd.size == MTDPART_SIZ_FULL)
-               slave->mtd.size = master->size - slave->offset;
+               slave->mtd.size = parent->size - slave->offset;
 
        printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset,
                (unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name);
 
        /* let's do some sanity checks */
-       if (slave->offset >= master->size) {
+       if (slave->offset >= parent->size) {
                /* let's register it anyway to preserve ordering */
                slave->offset = 0;
                slave->mtd.size = 0;
@@ -536,16 +550,16 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
                        part->name);
                goto out_register;
        }
-       if (slave->offset + slave->mtd.size > master->size) {
-               slave->mtd.size = master->size - slave->offset;
+       if (slave->offset + slave->mtd.size > parent->size) {
+               slave->mtd.size = parent->size - slave->offset;
                printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n",
-                       part->name, master->name, (unsigned long long)slave->mtd.size);
+                       part->name, parent->name, (unsigned long long)slave->mtd.size);
        }
-       if (master->numeraseregions > 1) {
+       if (parent->numeraseregions > 1) {
                /* Deal with variable erase size stuff */
-               int i, max = master->numeraseregions;
+               int i, max = parent->numeraseregions;
                u64 end = slave->offset + slave->mtd.size;
-               struct mtd_erase_region_info *regions = master->eraseregions;
+               struct mtd_erase_region_info *regions = parent->eraseregions;
 
                /* Find the first erase regions which is part of this
                 * partition. */
@@ -564,37 +578,40 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
                BUG_ON(slave->mtd.erasesize == 0);
        } else {
                /* Single erase size */
-               slave->mtd.erasesize = master->erasesize;
+               slave->mtd.erasesize = parent->erasesize;
        }
 
-       if ((slave->mtd.flags & MTD_WRITEABLE) &&
-           mtd_mod_by_eb(slave->offset, &slave->mtd)) {
+       tmp = slave->offset;
+       remainder = do_div(tmp, wr_alignment);
+       if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
                /* Doesn't start on a boundary of major erase size */
                /* FIXME: Let it be writable if it is on a boundary of
                 * _minor_ erase size though */
                slave->mtd.flags &= ~MTD_WRITEABLE;
-               printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
+               printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
                        part->name);
        }
-       if ((slave->mtd.flags & MTD_WRITEABLE) &&
-           mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
+
+       tmp = slave->mtd.size;
+       remainder = do_div(tmp, wr_alignment);
+       if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
                slave->mtd.flags &= ~MTD_WRITEABLE;
-               printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
+               printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
                        part->name);
        }
 
        mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
-       slave->mtd.ecc_step_size = master->ecc_step_size;
-       slave->mtd.ecc_strength = master->ecc_strength;
-       slave->mtd.bitflip_threshold = master->bitflip_threshold;
+       slave->mtd.ecc_step_size = parent->ecc_step_size;
+       slave->mtd.ecc_strength = parent->ecc_strength;
+       slave->mtd.bitflip_threshold = parent->bitflip_threshold;
 
-       if (master->_block_isbad) {
+       if (parent->_block_isbad) {
                uint64_t offs = 0;
 
                while (offs < slave->mtd.size) {
-                       if (mtd_block_isreserved(master, offs + slave->offset))
+                       if (mtd_block_isreserved(parent, offs + slave->offset))
                                slave->mtd.ecc_stats.bbtblocks++;
-                       else if (mtd_block_isbad(master, offs + slave->offset))
+                       else if (mtd_block_isbad(parent, offs + slave->offset))
                                slave->mtd.ecc_stats.badblocks++;
                        offs += slave->mtd.erasesize;
                }
@@ -628,7 +645,7 @@ static int mtd_add_partition_attrs(struct mtd_part *new)
        return ret;
 }
 
-int mtd_add_partition(struct mtd_info *master, const char *name,
+int mtd_add_partition(struct mtd_info *parent, const char *name,
                      long long offset, long long length)
 {
        struct mtd_partition part;
@@ -641,7 +658,7 @@ int mtd_add_partition(struct mtd_info *master, const char *name,
                return -EINVAL;
 
        if (length == MTDPART_SIZ_FULL)
-               length = master->size - offset;
+               length = parent->size - offset;
 
        if (length <= 0)
                return -EINVAL;
@@ -651,7 +668,7 @@ int mtd_add_partition(struct mtd_info *master, const char *name,
        part.size = length;
        part.offset = offset;
 
-       new = allocate_partition(master, &part, -1, offset);
+       new = allocate_partition(parent, &part, -1, offset);
        if (IS_ERR(new))
                return PTR_ERR(new);
 
@@ -667,23 +684,69 @@ int mtd_add_partition(struct mtd_info *master, const char *name,
 }
 EXPORT_SYMBOL_GPL(mtd_add_partition);
 
-int mtd_del_partition(struct mtd_info *master, int partno)
+/**
+ * __mtd_del_partition - delete MTD partition
+ *
+ * @priv: internal MTD struct for partition to be deleted
+ *
+ * This function must be called with the partitions mutex locked.
+ */
+static int __mtd_del_partition(struct mtd_part *priv)
+{
+       struct mtd_part *child, *next;
+       int err;
+
+       list_for_each_entry_safe(child, next, &mtd_partitions, list) {
+               if (child->parent == &priv->mtd) {
+                       err = __mtd_del_partition(child);
+                       if (err)
+                               return err;
+               }
+       }
+
+       sysfs_remove_files(&priv->mtd.dev.kobj, mtd_partition_attrs);
+
+       err = del_mtd_device(&priv->mtd);
+       if (err)
+               return err;
+
+       list_del(&priv->list);
+       free_partition(priv);
+
+       return 0;
+}
+
+/*
+ * This function unregisters and destroy all slave MTD objects which are
+ * attached to the given MTD object.
+ */
+int del_mtd_partitions(struct mtd_info *mtd)
 {
        struct mtd_part *slave, *next;
-       int ret = -EINVAL;
+       int ret, err = 0;
 
        mutex_lock(&mtd_partitions_mutex);
        list_for_each_entry_safe(slave, next, &mtd_partitions, list)
-               if ((slave->master == master) &&
-                   (slave->mtd.index == partno)) {
-                       sysfs_remove_files(&slave->mtd.dev.kobj,
-                                          mtd_partition_attrs);
-                       ret = del_mtd_device(&slave->mtd);
+               if (slave->parent == mtd) {
+                       ret = __mtd_del_partition(slave);
                        if (ret < 0)
-                               break;
+                               err = ret;
+               }
+       mutex_unlock(&mtd_partitions_mutex);
+
+       return err;
+}
+
+int mtd_del_partition(struct mtd_info *mtd, int partno)
+{
+       struct mtd_part *slave, *next;
+       int ret = -EINVAL;
 
-                       list_del(&slave->list);
-                       free_partition(slave);
+       mutex_lock(&mtd_partitions_mutex);
+       list_for_each_entry_safe(slave, next, &mtd_partitions, list)
+               if ((slave->parent == mtd) &&
+                   (slave->mtd.index == partno)) {
+                       ret = __mtd_del_partition(slave);
                        break;
                }
        mutex_unlock(&mtd_partitions_mutex);
@@ -724,6 +787,8 @@ int add_mtd_partitions(struct mtd_info *master,
 
                add_mtd_device(&slave->mtd);
                mtd_add_partition_attrs(slave);
+               if (parts[i].types)
+                       mtd_parse_part(slave, parts[i].types);
 
                cur_offset = slave->offset + slave->mtd.size;
        }
@@ -799,6 +864,27 @@ static const char * const default_mtd_part_types[] = {
        NULL
 };
 
+static int mtd_part_do_parse(struct mtd_part_parser *parser,
+                            struct mtd_info *master,
+                            struct mtd_partitions *pparts,
+                            struct mtd_part_parser_data *data)
+{
+       int ret;
+
+       ret = (*parser->parse_fn)(master, &pparts->parts, data);
+       pr_debug("%s: parser %s: %i\n", master->name, parser->name, ret);
+       if (ret <= 0)
+               return ret;
+
+       pr_notice("%d %s partitions found on MTD device %s\n", ret,
+                 parser->name, master->name);
+
+       pparts->nr_parts = ret;
+       pparts->parser = parser;
+
+       return ret;
+}
+
 /**
  * parse_mtd_partitions - parse MTD partitions
  * @master: the master partition (describes whole MTD device)
@@ -839,16 +925,10 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
                         parser ? parser->name : NULL);
                if (!parser)
                        continue;
-               ret = (*parser->parse_fn)(master, &pparts->parts, data);
-               pr_debug("%s: parser %s: %i\n",
-                        master->name, parser->name, ret);
-               if (ret > 0) {
-                       printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
-                              ret, parser->name, master->name);
-                       pparts->nr_parts = ret;
-                       pparts->parser = parser;
+               ret = mtd_part_do_parse(parser, master, pparts, data);
+               /* Found partitions! */
+               if (ret > 0)
                        return 0;
-               }
                mtd_part_parser_put(parser);
                /*
                 * Stash the first error we see; only report it if no parser
@@ -899,6 +979,6 @@ uint64_t mtd_get_device_size(const struct mtd_info *mtd)
        if (!mtd_is_partition(mtd))
                return mtd->size;
 
-       return mtd_to_part(mtd)->master->size;
+       return mtd_get_device_size(mtd_to_part(mtd)->parent);
 }
 EXPORT_SYMBOL_GPL(mtd_get_device_size);
index c302952..dbfa72d 100644 (file)
@@ -308,6 +308,7 @@ config MTD_NAND_CS553X
 config MTD_NAND_ATMEL
        tristate "Support for NAND Flash / SmartMedia on AT91"
        depends on ARCH_AT91
+       select MFD_ATMEL_SMC
        help
          Enables support for NAND Flash / Smart Media Card interface
          on Atmel AT91 processors.
@@ -542,6 +543,7 @@ config MTD_NAND_SUNXI
 
 config MTD_NAND_HISI504
        tristate "Support for NAND controller on Hisilicon SoC Hip04"
+       depends on ARCH_HISI || COMPILE_TEST
        depends on HAS_DMA
        help
          Enables support for NAND controller on Hisilicon SoC Hip04.
@@ -555,6 +557,7 @@ config MTD_NAND_QCOM
 
 config MTD_NAND_MTK
        tristate "Support for NAND controller on MTK SoCs"
+       depends on ARCH_MEDIATEK || COMPILE_TEST
        depends on HAS_DMA
        help
          Enables support for NAND controller on MTK SoCs.
index 3b24468..d922a88 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/interrupt.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/atmel-matrix.h>
+#include <linux/mfd/syscon/atmel-smc.h>
 #include <linux/module.h>
 #include <linux/mtd/nand.h>
 #include <linux/of_address.h>
@@ -64,7 +65,6 @@
 #include <linux/of_platform.h>
 #include <linux/iopoll.h>
 #include <linux/platform_device.h>
-#include <linux/platform_data/atmel.h>
 #include <linux/regmap.h>
 
 #include "pmecc.h"
@@ -151,6 +151,8 @@ struct atmel_nand_cs {
                void __iomem *virt;
                dma_addr_t dma;
        } io;
+
+       struct atmel_smc_cs_conf smcconf;
 };
 
 struct atmel_nand {
@@ -196,6 +198,8 @@ struct atmel_nand_controller_ops {
        void (*nand_init)(struct atmel_nand_controller *nc,
                          struct atmel_nand *nand);
        int (*ecc_init)(struct atmel_nand *nand);
+       int (*setup_data_interface)(struct atmel_nand *nand, int csline,
+                                   const struct nand_data_interface *conf);
 };
 
 struct atmel_nand_controller_caps {
@@ -912,7 +916,7 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_hsmc_nand_controller *nc;
-       int ret;
+       int ret, status;
 
        nc = to_hsmc_nand_controller(chip->controller);
 
@@ -954,6 +958,10 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
                dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
                        ret);
 
+       status = chip->waitfunc(mtd, chip);
+       if (status & NAND_STATUS_FAIL)
+               return -EIO;
+
        return ret;
 }
 
@@ -1175,6 +1183,295 @@ static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
        return 0;
 }
 
+static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
+                                       const struct nand_data_interface *conf,
+                                       struct atmel_smc_cs_conf *smcconf)
+{
+       u32 ncycles, totalcycles, timeps, mckperiodps;
+       struct atmel_nand_controller *nc;
+       int ret;
+
+       nc = to_nand_controller(nand->base.controller);
+
+       /* DDR interface not supported. */
+       if (conf->type != NAND_SDR_IFACE)
+               return -ENOTSUPP;
+
+       /*
+        * tRC < 30ns implies EDO mode. This controller does not support this
+        * mode.
+        */
+       if (conf->timings.sdr.tRC_min < 30)
+               return -ENOTSUPP;
+
+       atmel_smc_cs_conf_init(smcconf);
+
+       mckperiodps = NSEC_PER_SEC / clk_get_rate(nc->mck);
+       mckperiodps *= 1000;
+
+       /*
+        * Set write pulse timing. This one is easy to extract:
+        *
+        * NWE_PULSE = tWP
+        */
+       ncycles = DIV_ROUND_UP(conf->timings.sdr.tWP_min, mckperiodps);
+       totalcycles = ncycles;
+       ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NWE_SHIFT,
+                                         ncycles);
+       if (ret)
+               return ret;
+
+       /*
+        * The write setup timing depends on the operation done on the NAND.
+        * All operations goes through the same data bus, but the operation
+        * type depends on the address we are writing to (ALE/CLE address
+        * lines).
+        * Since we have no way to differentiate the different operations at
+        * the SMC level, we must consider the worst case (the biggest setup
+        * time among all operation types):
+        *
+        * NWE_SETUP = max(tCLS, tCS, tALS, tDS) - NWE_PULSE
+        */
+       timeps = max3(conf->timings.sdr.tCLS_min, conf->timings.sdr.tCS_min,
+                     conf->timings.sdr.tALS_min);
+       timeps = max(timeps, conf->timings.sdr.tDS_min);
+       ncycles = DIV_ROUND_UP(timeps, mckperiodps);
+       ncycles = ncycles > totalcycles ? ncycles - totalcycles : 0;
+       totalcycles += ncycles;
+       ret = atmel_smc_cs_conf_set_setup(smcconf, ATMEL_SMC_NWE_SHIFT,
+                                         ncycles);
+       if (ret)
+               return ret;
+
+       /*
+        * As for the write setup timing, the write hold timing depends on the
+        * operation done on the NAND:
+        *
+        * NWE_HOLD = max(tCLH, tCH, tALH, tDH, tWH)
+        */
+       timeps = max3(conf->timings.sdr.tCLH_min, conf->timings.sdr.tCH_min,
+                     conf->timings.sdr.tALH_min);
+       timeps = max3(timeps, conf->timings.sdr.tDH_min,
+                     conf->timings.sdr.tWH_min);
+       ncycles = DIV_ROUND_UP(timeps, mckperiodps);
+       totalcycles += ncycles;
+
+       /*
+        * The write cycle timing is directly matching tWC, but is also
+        * dependent on the other timings on the setup and hold timings we
+        * calculated earlier, which gives:
+        *
+        * NWE_CYCLE = max(tWC, NWE_SETUP + NWE_PULSE + NWE_HOLD)
+        */
+       ncycles = DIV_ROUND_UP(conf->timings.sdr.tWC_min, mckperiodps);
+       ncycles = max(totalcycles, ncycles);
+       ret = atmel_smc_cs_conf_set_cycle(smcconf, ATMEL_SMC_NWE_SHIFT,
+                                         ncycles);
+       if (ret)
+               return ret;
+
+       /*
+        * We don't want the CS line to be toggled between each byte/word
+        * transfer to the NAND. The only way to guarantee that is to have the
+        * NCS_{WR,RD}_{SETUP,HOLD} timings set to 0, which in turn means:
+        *
+        * NCS_WR_PULSE = NWE_CYCLE
+        */
+       ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NCS_WR_SHIFT,
+                                         ncycles);
+       if (ret)
+               return ret;
+
+       /*
+        * As for the write setup timing, the read hold timing depends on the
+        * operation done on the NAND:
+        *
+        * NRD_HOLD = max(tREH, tRHOH)
+        */
+       timeps = max(conf->timings.sdr.tREH_min, conf->timings.sdr.tRHOH_min);
+       ncycles = DIV_ROUND_UP(timeps, mckperiodps);
+       totalcycles = ncycles;
+
+       /*
+        * TDF = tRHZ - NRD_HOLD
+        */
+       ncycles = DIV_ROUND_UP(conf->timings.sdr.tRHZ_max, mckperiodps);
+       ncycles -= totalcycles;
+
+       /*
+        * In ONFI 4.0 specs, tRHZ has been increased to support EDO NANDs and
+        * we might end up with a config that does not fit in the TDF field.
+        * Just take the max value in this case and hope that the NAND is more
+        * tolerant than advertised.
+        */
+       if (ncycles > ATMEL_SMC_MODE_TDF_MAX)
+               ncycles = ATMEL_SMC_MODE_TDF_MAX;
+       else if (ncycles < ATMEL_SMC_MODE_TDF_MIN)
+               ncycles = ATMEL_SMC_MODE_TDF_MIN;
+
+       smcconf->mode |= ATMEL_SMC_MODE_TDF(ncycles) |
+                        ATMEL_SMC_MODE_TDFMODE_OPTIMIZED;
+
+       /*
+        * Read pulse timing directly matches tRP:
+        *
+        * NRD_PULSE = tRP
+        */
+       ncycles = DIV_ROUND_UP(conf->timings.sdr.tRP_min, mckperiodps);
+       totalcycles += ncycles;
+       ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NRD_SHIFT,
+                                         ncycles);
+       if (ret)
+               return ret;
+
+       /*
+        * The write cycle timing is directly matching tWC, but is also
+        * dependent on the setup and hold timings we calculated earlier,
+        * which gives:
+        *
+        * NRD_CYCLE = max(tRC, NRD_PULSE + NRD_HOLD)
+        *
+        * NRD_SETUP is always 0.
+        */
+       ncycles = DIV_ROUND_UP(conf->timings.sdr.tRC_min, mckperiodps);
+       ncycles = max(totalcycles, ncycles);
+       ret = atmel_smc_cs_conf_set_cycle(smcconf, ATMEL_SMC_NRD_SHIFT,
+                                         ncycles);
+       if (ret)
+               return ret;
+
+       /*
+        * We don't want the CS line to be toggled between each byte/word
+        * transfer from the NAND. The only way to guarantee that is to have
+        * the NCS_{WR,RD}_{SETUP,HOLD} timings set to 0, which in turn means:
+        *
+        * NCS_RD_PULSE = NRD_CYCLE
+        */
+       ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NCS_RD_SHIFT,
+                                         ncycles);
+       if (ret)
+               return ret;
+
+       /* Txxx timings are directly matching tXXX ones. */
+       ncycles = DIV_ROUND_UP(conf->timings.sdr.tCLR_min, mckperiodps);
+       ret = atmel_smc_cs_conf_set_timing(smcconf,
+                                          ATMEL_HSMC_TIMINGS_TCLR_SHIFT,
+                                          ncycles);
+       if (ret)
+               return ret;
+
+       ncycles = DIV_ROUND_UP(conf->timings.sdr.tADL_min, mckperiodps);
+       ret = atmel_smc_cs_conf_set_timing(smcconf,
+                                          ATMEL_HSMC_TIMINGS_TADL_SHIFT,
+                                          ncycles);
+       if (ret)
+               return ret;
+
+       ncycles = DIV_ROUND_UP(conf->timings.sdr.tAR_min, mckperiodps);
+       ret = atmel_smc_cs_conf_set_timing(smcconf,
+                                          ATMEL_HSMC_TIMINGS_TAR_SHIFT,
+                                          ncycles);
+       if (ret)
+               return ret;
+
+       ncycles = DIV_ROUND_UP(conf->timings.sdr.tRR_min, mckperiodps);
+       ret = atmel_smc_cs_conf_set_timing(smcconf,
+                                          ATMEL_HSMC_TIMINGS_TRR_SHIFT,
+                                          ncycles);
+       if (ret)
+               return ret;
+
+       ncycles = DIV_ROUND_UP(conf->timings.sdr.tWB_max, mckperiodps);
+       ret = atmel_smc_cs_conf_set_timing(smcconf,
+                                          ATMEL_HSMC_TIMINGS_TWB_SHIFT,
+                                          ncycles);
+       if (ret)
+               return ret;
+
+       /* Attach the CS line to the NFC logic. */
+       smcconf->timings |= ATMEL_HSMC_TIMINGS_NFSEL;
+
+       /* Set the appropriate data bus width. */
+       if (nand->base.options & NAND_BUSWIDTH_16)
+               smcconf->mode |= ATMEL_SMC_MODE_DBW_16;
+
+       /* Operate in NRD/NWE READ/WRITEMODE. */
+       smcconf->mode |= ATMEL_SMC_MODE_READMODE_NRD |
+                        ATMEL_SMC_MODE_WRITEMODE_NWE;
+
+       return 0;
+}
+
+static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand,
+                                       int csline,
+                                       const struct nand_data_interface *conf)
+{
+       struct atmel_nand_controller *nc;
+       struct atmel_smc_cs_conf smcconf;
+       struct atmel_nand_cs *cs;
+       int ret;
+
+       nc = to_nand_controller(nand->base.controller);
+
+       ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
+       if (ret)
+               return ret;
+
+       if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+               return 0;
+
+       cs = &nand->cs[csline];
+       cs->smcconf = smcconf;
+       atmel_smc_cs_conf_apply(nc->smc, cs->id, &cs->smcconf);
+
+       return 0;
+}
+
+static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
+                                       int csline,
+                                       const struct nand_data_interface *conf)
+{
+       struct atmel_nand_controller *nc;
+       struct atmel_smc_cs_conf smcconf;
+       struct atmel_nand_cs *cs;
+       int ret;
+
+       nc = to_nand_controller(nand->base.controller);
+
+       ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
+       if (ret)
+               return ret;
+
+       if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+               return 0;
+
+       cs = &nand->cs[csline];
+       cs->smcconf = smcconf;
+
+       if (cs->rb.type == ATMEL_NAND_NATIVE_RB)
+               cs->smcconf.timings |= ATMEL_HSMC_TIMINGS_RBNSEL(cs->rb.id);
+
+       atmel_hsmc_cs_conf_apply(nc->smc, cs->id, &cs->smcconf);
+
+       return 0;
+}
+
+static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+                                       const struct nand_data_interface *conf)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct atmel_nand *nand = to_atmel_nand(chip);
+       struct atmel_nand_controller *nc;
+
+       nc = to_nand_controller(nand->base.controller);
+
+       if (csline >= nand->numcs ||
+           (csline < 0 && csline != NAND_DATA_IFACE_CHECK_ONLY))
+               return -EINVAL;
+
+       return nc->caps->ops->setup_data_interface(nand, csline, conf);
+}
+
 static void atmel_nand_init(struct atmel_nand_controller *nc,
                            struct atmel_nand *nand)
 {
@@ -1192,6 +1489,9 @@ static void atmel_nand_init(struct atmel_nand_controller *nc,
        chip->write_buf = atmel_nand_write_buf;
        chip->select_chip = atmel_nand_select_chip;
 
+       if (nc->mck && nc->caps->ops->setup_data_interface)
+               chip->setup_data_interface = atmel_nand_setup_data_interface;
+
        /* Some NANDs require a longer delay than the default one (20us). */
        chip->chip_delay = 40;
 
@@ -1677,6 +1977,12 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
        if (nc->caps->legacy_of_bindings)
                return 0;
 
+       nc->mck = of_clk_get(dev->parent->of_node, 0);
+       if (IS_ERR(nc->mck)) {
+               dev_err(dev, "Failed to retrieve MCK clk\n");
+               return PTR_ERR(nc->mck);
+       }
+
        np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
        if (!np) {
                dev_err(dev, "Missing or invalid atmel,smc property\n");
@@ -1983,6 +2289,7 @@ static const struct atmel_nand_controller_ops atmel_hsmc_nc_ops = {
        .remove = atmel_hsmc_nand_controller_remove,
        .ecc_init = atmel_hsmc_nand_ecc_init,
        .nand_init = atmel_hsmc_nand_init,
+       .setup_data_interface = atmel_hsmc_nand_setup_data_interface,
 };
 
 static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = {
@@ -2037,7 +2344,14 @@ atmel_smc_nand_controller_remove(struct atmel_nand_controller *nc)
        return 0;
 }
 
-static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
+/*
+ * The SMC reg layout of at91rm9200 is completely different which prevents us
+ * from re-using atmel_smc_nand_setup_data_interface() for the
+ * ->setup_data_interface() hook.
+ * At this point, there's no support for the at91rm9200 SMC IP, so we leave
+ * ->setup_data_interface() unassigned.
+ */
+static const struct atmel_nand_controller_ops at91rm9200_nc_ops = {
        .probe = atmel_smc_nand_controller_probe,
        .remove = atmel_smc_nand_controller_remove,
        .ecc_init = atmel_nand_ecc_init,
@@ -2047,6 +2361,20 @@ static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
 static const struct atmel_nand_controller_caps atmel_rm9200_nc_caps = {
        .ale_offs = BIT(21),
        .cle_offs = BIT(22),
+       .ops = &at91rm9200_nc_ops,
+};
+
+static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
+       .probe = atmel_smc_nand_controller_probe,
+       .remove = atmel_smc_nand_controller_remove,
+       .ecc_init = atmel_nand_ecc_init,
+       .nand_init = atmel_smc_nand_init,
+       .setup_data_interface = atmel_smc_nand_setup_data_interface,
+};
+
+static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = {
+       .ale_offs = BIT(21),
+       .cle_offs = BIT(22),
        .ops = &atmel_smc_nc_ops,
 };
 
@@ -2093,7 +2421,7 @@ static const struct of_device_id atmel_nand_controller_of_ids[] = {
        },
        {
                .compatible = "atmel,at91sam9260-nand-controller",
-               .data = &atmel_rm9200_nc_caps,
+               .data = &atmel_sam9260_nc_caps,
        },
        {
                .compatible = "atmel,at91sam9261-nand-controller",
@@ -2181,6 +2509,24 @@ static int atmel_nand_controller_remove(struct platform_device *pdev)
        return nc->caps->ops->remove(nc);
 }
 
+static __maybe_unused int atmel_nand_controller_resume(struct device *dev)
+{
+       struct atmel_nand_controller *nc = dev_get_drvdata(dev);
+       struct atmel_nand *nand;
+
+       list_for_each_entry(nand, &nc->chips, node) {
+               int i;
+
+               for (i = 0; i < nand->numcs; i++)
+                       nand_reset(&nand->base, i);
+       }
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(atmel_nand_controller_pm_ops, NULL,
+                        atmel_nand_controller_resume);
+
 static struct platform_driver atmel_nand_controller_driver = {
        .driver = {
                .name = "atmel-nand-controller",
index f1da4ea..54bac5b 100644 (file)
@@ -392,6 +392,8 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
        b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
        b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
        b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
+       b47n->nand_chip.onfi_set_features = nand_onfi_get_set_features_notsupp;
+       b47n->nand_chip.onfi_get_features = nand_onfi_get_set_features_notsupp;
 
        nand_chip->chip_delay = 50;
        b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
index d40c32d..2fd733e 100644 (file)
@@ -654,6 +654,8 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        cafe->nand.read_buf = cafe_read_buf;
        cafe->nand.write_buf = cafe_write_buf;
        cafe->nand.select_chip = cafe_select_chip;
+       cafe->nand.onfi_set_features = nand_onfi_get_set_features_notsupp;
+       cafe->nand.onfi_get_features = nand_onfi_get_set_features_notsupp;
 
        cafe->nand.chip_delay = 0;
 
index 531c519..7b26e53 100644 (file)
@@ -771,11 +771,14 @@ static int nand_davinci_probe(struct platform_device *pdev)
                        info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
                        info->chip.ecc.bytes = 10;
                        info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
+                       info->chip.ecc.algo = NAND_ECC_BCH;
                } else {
+                       /* 1bit ecc hamming */
                        info->chip.ecc.calculate = nand_davinci_calculate_1bit;
                        info->chip.ecc.correct = nand_davinci_correct_1bit;
                        info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
                        info->chip.ecc.bytes = 3;
+                       info->chip.ecc.algo = NAND_ECC_HAMMING;
                }
                info->chip.ecc.size = 512;
                info->chip.ecc.strength = pdata->ecc_bits;
index 16634df..d723be3 100644 (file)
 #include <linux/mutex.h>
 #include <linux/mtd/mtd.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 
 #include "denali.h"
 
 MODULE_LICENSE("GPL");
 
-/*
- * We define a module parameter that allows the user to override
- * the hardware and decide what timing mode should be used.
- */
-#define NAND_DEFAULT_TIMINGS   -1
+#define DENALI_NAND_NAME    "denali-nand"
 
-static int onfi_timing_mode = NAND_DEFAULT_TIMINGS;
-module_param(onfi_timing_mode, int, S_IRUGO);
-MODULE_PARM_DESC(onfi_timing_mode,
-          "Overrides default ONFI setting. -1 indicates use default timings");
+/* Host Data/Command Interface */
+#define DENALI_HOST_ADDR       0x00
+#define DENALI_HOST_DATA       0x10
 
-#define DENALI_NAND_NAME    "denali-nand"
+#define DENALI_MAP00           (0 << 26)       /* direct access to buffer */
+#define DENALI_MAP01           (1 << 26)       /* read/write pages in PIO */
+#define DENALI_MAP10           (2 << 26)       /* high-level control plane */
+#define DENALI_MAP11           (3 << 26)       /* direct controller access */
 
-/*
- * We define a macro here that combines all interrupts this driver uses into
- * a single constant value, for convenience.
- */
-#define DENALI_IRQ_ALL (INTR__DMA_CMD_COMP | \
-                       INTR__ECC_TRANSACTION_DONE | \
-                       INTR__ECC_ERR | \
-                       INTR__PROGRAM_FAIL | \
-                       INTR__LOAD_COMP | \
-                       INTR__PROGRAM_COMP | \
-                       INTR__TIME_OUT | \
-                       INTR__ERASE_FAIL | \
-                       INTR__RST_COMP | \
-                       INTR__ERASE_COMP)
+/* MAP11 access cycle type */
+#define DENALI_MAP11_CMD       ((DENALI_MAP11) | 0)    /* command cycle */
+#define DENALI_MAP11_ADDR      ((DENALI_MAP11) | 1)    /* address cycle */
+#define DENALI_MAP11_DATA      ((DENALI_MAP11) | 2)    /* data cycle */
 
-/*
- * indicates whether or not the internal value for the flash bank is
- * valid or not
- */
-#define CHIP_SELECT_INVALID    -1
+/* MAP10 commands */
+#define DENALI_ERASE           0x01
+
+#define DENALI_BANK(denali)    ((denali)->active_bank << 24)
+
+#define DENALI_INVALID_BANK    -1
+#define DENALI_NR_BANKS                4
 
 /*
- * This macro divides two integers and rounds fractional values up
- * to the nearest integer value.
+ * The bus interface clock, clk_x, is phase aligned with the core clock.  The
+ * clk_x is an integral multiple N of the core clk.  The value N is configured
+ * at IP delivery time, and its available value is 4, 5, or 6.  We need to align
+ * to the largest value to make it work with any possible configuration.
  */
-#define CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y)))
+#define DENALI_CLK_X_MULT      6
 
 /*
  * this macro allows us to convert from an MTD structure to our own
@@ -77,339 +70,11 @@ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
        return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
 }
 
-/*
- * These constants are defined by the driver to enable common driver
- * configuration options.
- */
-#define SPARE_ACCESS           0x41
-#define MAIN_ACCESS            0x42
-#define MAIN_SPARE_ACCESS      0x43
-
-#define DENALI_READ    0
-#define DENALI_WRITE   0x100
-
-/*
- * this is a helper macro that allows us to
- * format the bank into the proper bits for the controller
- */
-#define BANK(x) ((x) << 24)
-
-/* forward declarations */
-static void clear_interrupts(struct denali_nand_info *denali);
-static uint32_t wait_for_irq(struct denali_nand_info *denali,
-                                                       uint32_t irq_mask);
-static void denali_irq_enable(struct denali_nand_info *denali,
-                                                       uint32_t int_mask);
-static uint32_t read_interrupt_status(struct denali_nand_info *denali);
-
-/*
- * Certain operations for the denali NAND controller use an indexed mode to
- * read/write data. The operation is performed by writing the address value
- * of the command to the device memory followed by the data. This function
- * abstracts this common operation.
- */
-static void index_addr(struct denali_nand_info *denali,
-                               uint32_t address, uint32_t data)
-{
-       iowrite32(address, denali->flash_mem);
-       iowrite32(data, denali->flash_mem + 0x10);
-}
-
-/* Perform an indexed read of the device */
-static void index_addr_read_data(struct denali_nand_info *denali,
-                                uint32_t address, uint32_t *pdata)
-{
-       iowrite32(address, denali->flash_mem);
-       *pdata = ioread32(denali->flash_mem + 0x10);
-}
-
-/*
- * We need to buffer some data for some of the NAND core routines.
- * The operations manage buffering that data.
- */
-static void reset_buf(struct denali_nand_info *denali)
-{
-       denali->buf.head = denali->buf.tail = 0;
-}
-
-static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte)
-{
-       denali->buf.buf[denali->buf.tail++] = byte;
-}
-
-/* reads the status of the device */
-static void read_status(struct denali_nand_info *denali)
-{
-       uint32_t cmd;
-
-       /* initialize the data buffer to store status */
-       reset_buf(denali);
-
-       cmd = ioread32(denali->flash_reg + WRITE_PROTECT);
-       if (cmd)
-               write_byte_to_buf(denali, NAND_STATUS_WP);
-       else
-               write_byte_to_buf(denali, 0);
-}
-
-/* resets a specific device connected to the core */
-static void reset_bank(struct denali_nand_info *denali)
-{
-       uint32_t irq_status;
-       uint32_t irq_mask = INTR__RST_COMP | INTR__TIME_OUT;
-
-       clear_interrupts(denali);
-
-       iowrite32(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET);
-
-       irq_status = wait_for_irq(denali, irq_mask);
-
-       if (irq_status & INTR__TIME_OUT)
-               dev_err(denali->dev, "reset bank failed.\n");
-}
-
-/* Reset the flash controller */
-static uint16_t denali_nand_reset(struct denali_nand_info *denali)
-{
-       int i;
-
-       for (i = 0; i < denali->max_banks; i++)
-               iowrite32(INTR__RST_COMP | INTR__TIME_OUT,
-               denali->flash_reg + INTR_STATUS(i));
-
-       for (i = 0; i < denali->max_banks; i++) {
-               iowrite32(1 << i, denali->flash_reg + DEVICE_RESET);
-               while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) &
-                       (INTR__RST_COMP | INTR__TIME_OUT)))
-                       cpu_relax();
-               if (ioread32(denali->flash_reg + INTR_STATUS(i)) &
-                       INTR__TIME_OUT)
-                       dev_dbg(denali->dev,
-                       "NAND Reset operation timed out on bank %d\n", i);
-       }
-
-       for (i = 0; i < denali->max_banks; i++)
-               iowrite32(INTR__RST_COMP | INTR__TIME_OUT,
-                         denali->flash_reg + INTR_STATUS(i));
-
-       return PASS;
-}
-
-/*
- * this routine calculates the ONFI timing values for a given mode and
- * programs the clocking register accordingly. The mode is determined by
- * the get_onfi_nand_para routine.
- */
-static void nand_onfi_timing_set(struct denali_nand_info *denali,
-                                                               uint16_t mode)
-{
-       uint16_t Trea[6] = {40, 30, 25, 20, 20, 16};
-       uint16_t Trp[6] = {50, 25, 17, 15, 12, 10};
-       uint16_t Treh[6] = {30, 15, 15, 10, 10, 7};
-       uint16_t Trc[6] = {100, 50, 35, 30, 25, 20};
-       uint16_t Trhoh[6] = {0, 15, 15, 15, 15, 15};
-       uint16_t Trloh[6] = {0, 0, 0, 0, 5, 5};
-       uint16_t Tcea[6] = {100, 45, 30, 25, 25, 25};
-       uint16_t Tadl[6] = {200, 100, 100, 100, 70, 70};
-       uint16_t Trhw[6] = {200, 100, 100, 100, 100, 100};
-       uint16_t Trhz[6] = {200, 100, 100, 100, 100, 100};
-       uint16_t Twhr[6] = {120, 80, 80, 60, 60, 60};
-       uint16_t Tcs[6] = {70, 35, 25, 25, 20, 15};
-
-       uint16_t data_invalid_rhoh, data_invalid_rloh, data_invalid;
-       uint16_t dv_window = 0;
-       uint16_t en_lo, en_hi;
-       uint16_t acc_clks;
-       uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt;
-
-       en_lo = CEIL_DIV(Trp[mode], CLK_X);
-       en_hi = CEIL_DIV(Treh[mode], CLK_X);
-#if ONFI_BLOOM_TIME
-       if ((en_hi * CLK_X) < (Treh[mode] + 2))
-               en_hi++;
-#endif
-
-       if ((en_lo + en_hi) * CLK_X < Trc[mode])
-               en_lo += CEIL_DIV((Trc[mode] - (en_lo + en_hi) * CLK_X), CLK_X);
-
-       if ((en_lo + en_hi) < CLK_MULTI)
-               en_lo += CLK_MULTI - en_lo - en_hi;
-
-       while (dv_window < 8) {
-               data_invalid_rhoh = en_lo * CLK_X + Trhoh[mode];
-
-               data_invalid_rloh = (en_lo + en_hi) * CLK_X + Trloh[mode];
-
-               data_invalid = data_invalid_rhoh < data_invalid_rloh ?
-                                       data_invalid_rhoh : data_invalid_rloh;
-
-               dv_window = data_invalid - Trea[mode];
-
-               if (dv_window < 8)
-                       en_lo++;
-       }
-
-       acc_clks = CEIL_DIV(Trea[mode], CLK_X);
-
-       while (acc_clks * CLK_X - Trea[mode] < 3)
-               acc_clks++;
-
-       if (data_invalid - acc_clks * CLK_X < 2)
-               dev_warn(denali->dev, "%s, Line %d: Warning!\n",
-                        __FILE__, __LINE__);
-
-       addr_2_data = CEIL_DIV(Tadl[mode], CLK_X);
-       re_2_we = CEIL_DIV(Trhw[mode], CLK_X);
-       re_2_re = CEIL_DIV(Trhz[mode], CLK_X);
-       we_2_re = CEIL_DIV(Twhr[mode], CLK_X);
-       cs_cnt = CEIL_DIV((Tcs[mode] - Trp[mode]), CLK_X);
-       if (cs_cnt == 0)
-               cs_cnt = 1;
-
-       if (Tcea[mode]) {
-               while (cs_cnt * CLK_X + Trea[mode] < Tcea[mode])
-                       cs_cnt++;
-       }
-
-#if MODE5_WORKAROUND
-       if (mode == 5)
-               acc_clks = 5;
-#endif
-
-       /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */
-       if (ioread32(denali->flash_reg + MANUFACTURER_ID) == 0 &&
-               ioread32(denali->flash_reg + DEVICE_ID) == 0x88)
-               acc_clks = 6;
-
-       iowrite32(acc_clks, denali->flash_reg + ACC_CLKS);
-       iowrite32(re_2_we, denali->flash_reg + RE_2_WE);
-       iowrite32(re_2_re, denali->flash_reg + RE_2_RE);
-       iowrite32(we_2_re, denali->flash_reg + WE_2_RE);
-       iowrite32(addr_2_data, denali->flash_reg + ADDR_2_DATA);
-       iowrite32(en_lo, denali->flash_reg + RDWR_EN_LO_CNT);
-       iowrite32(en_hi, denali->flash_reg + RDWR_EN_HI_CNT);
-       iowrite32(cs_cnt, denali->flash_reg + CS_SETUP_CNT);
-}
-
-/* queries the NAND device to see what ONFI modes it supports. */
-static uint16_t get_onfi_nand_para(struct denali_nand_info *denali)
+static void denali_host_write(struct denali_nand_info *denali,
+                             uint32_t addr, uint32_t data)
 {
-       int i;
-
-       /*
-        * we needn't to do a reset here because driver has already
-        * reset all the banks before
-        */
-       if (!(ioread32(denali->flash_reg + ONFI_TIMING_MODE) &
-               ONFI_TIMING_MODE__VALUE))
-               return FAIL;
-
-       for (i = 5; i > 0; i--) {
-               if (ioread32(denali->flash_reg + ONFI_TIMING_MODE) &
-                       (0x01 << i))
-                       break;
-       }
-
-       nand_onfi_timing_set(denali, i);
-
-       /*
-        * By now, all the ONFI devices we know support the page cache
-        * rw feature. So here we enable the pipeline_rw_ahead feature
-        */
-       /* iowrite32(1, denali->flash_reg + CACHE_WRITE_ENABLE); */
-       /* iowrite32(1, denali->flash_reg + CACHE_READ_ENABLE);  */
-
-       return PASS;
-}
-
-static void get_samsung_nand_para(struct denali_nand_info *denali,
-                                                       uint8_t device_id)
-{
-       if (device_id == 0xd3) { /* Samsung K9WAG08U1A */
-               /* Set timing register values according to datasheet */
-               iowrite32(5, denali->flash_reg + ACC_CLKS);
-               iowrite32(20, denali->flash_reg + RE_2_WE);
-               iowrite32(12, denali->flash_reg + WE_2_RE);
-               iowrite32(14, denali->flash_reg + ADDR_2_DATA);
-               iowrite32(3, denali->flash_reg + RDWR_EN_LO_CNT);
-               iowrite32(2, denali->flash_reg + RDWR_EN_HI_CNT);
-               iowrite32(2, denali->flash_reg + CS_SETUP_CNT);
-       }
-}
-
-static void get_toshiba_nand_para(struct denali_nand_info *denali)
-{
-       /*
-        * Workaround to fix a controller bug which reports a wrong
-        * spare area size for some kind of Toshiba NAND device
-        */
-       if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) &&
-               (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64))
-               iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
-}
-
-static void get_hynix_nand_para(struct denali_nand_info *denali,
-                                                       uint8_t device_id)
-{
-       switch (device_id) {
-       case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */
-       case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */
-               iowrite32(128, denali->flash_reg + PAGES_PER_BLOCK);
-               iowrite32(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
-               iowrite32(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
-               iowrite32(0, denali->flash_reg + DEVICE_WIDTH);
-               break;
-       default:
-               dev_warn(denali->dev,
-                        "Unknown Hynix NAND (Device ID: 0x%x).\n"
-                        "Will use default parameter values instead.\n",
-                        device_id);
-       }
-}
-
-/*
- * determines how many NAND chips are connected to the controller. Note for
- * Intel CE4100 devices we don't support more than one device.
- */
-static void find_valid_banks(struct denali_nand_info *denali)
-{
-       uint32_t id[denali->max_banks];
-       int i;
-
-       denali->total_used_banks = 1;
-       for (i = 0; i < denali->max_banks; i++) {
-               index_addr(denali, MODE_11 | (i << 24) | 0, 0x90);
-               index_addr(denali, MODE_11 | (i << 24) | 1, 0);
-               index_addr_read_data(denali, MODE_11 | (i << 24) | 2, &id[i]);
-
-               dev_dbg(denali->dev,
-                       "Return 1st ID for bank[%d]: %x\n", i, id[i]);
-
-               if (i == 0) {
-                       if (!(id[i] & 0x0ff))
-                               break; /* WTF? */
-               } else {
-                       if ((id[i] & 0x0ff) == (id[0] & 0x0ff))
-                               denali->total_used_banks++;
-                       else
-                               break;
-               }
-       }
-
-       if (denali->platform == INTEL_CE4100) {
-               /*
-                * Platform limitations of the CE4100 device limit
-                * users to a single chip solution for NAND.
-                * Multichip support is not enabled.
-                */
-               if (denali->total_used_banks != 1) {
-                       dev_err(denali->dev,
-                               "Sorry, Intel CE4100 only supports a single NAND device.\n");
-                       BUG();
-               }
-       }
-       dev_dbg(denali->dev,
-               "denali->total_used_banks: %d\n", denali->total_used_banks);
+       iowrite32(addr, denali->host + DENALI_HOST_ADDR);
+       iowrite32(data, denali->host + DENALI_HOST_DATA);
 }
 
 /*
@@ -418,7 +83,7 @@ static void find_valid_banks(struct denali_nand_info *denali)
  */
 static void detect_max_banks(struct denali_nand_info *denali)
 {
-       uint32_t features = ioread32(denali->flash_reg + FEATURES);
+       uint32_t features = ioread32(denali->reg + FEATURES);
 
        denali->max_banks = 1 << (features & FEATURES__N_BANKS);
 
@@ -427,227 +92,120 @@ static void detect_max_banks(struct denali_nand_info *denali)
                denali->max_banks <<= 1;
 }
 
-static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
+static void denali_enable_irq(struct denali_nand_info *denali)
 {
-       uint16_t status = PASS;
-       uint32_t id_bytes[8], addr;
-       uint8_t maf_id, device_id;
        int i;
 
-       /*
-        * Use read id method to get device ID and other params.
-        * For some NAND chips, controller can't report the correct
-        * device ID by reading from DEVICE_ID register
-        */
-       addr = MODE_11 | BANK(denali->flash_bank);
-       index_addr(denali, addr | 0, 0x90);
-       index_addr(denali, addr | 1, 0);
-       for (i = 0; i < 8; i++)
-               index_addr_read_data(denali, addr | 2, &id_bytes[i]);
-       maf_id = id_bytes[0];
-       device_id = id_bytes[1];
-
-       if (ioread32(denali->flash_reg + ONFI_DEVICE_NO_OF_LUNS) &
-               ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE) { /* ONFI 1.0 NAND */
-               if (FAIL == get_onfi_nand_para(denali))
-                       return FAIL;
-       } else if (maf_id == 0xEC) { /* Samsung NAND */
-               get_samsung_nand_para(denali, device_id);
-       } else if (maf_id == 0x98) { /* Toshiba NAND */
-               get_toshiba_nand_para(denali);
-       } else if (maf_id == 0xAD) { /* Hynix NAND */
-               get_hynix_nand_para(denali, device_id);
-       }
-
-       dev_info(denali->dev,
-                       "Dump timing register values:\n"
-                       "acc_clks: %d, re_2_we: %d, re_2_re: %d\n"
-                       "we_2_re: %d, addr_2_data: %d, rdwr_en_lo_cnt: %d\n"
-                       "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n",
-                       ioread32(denali->flash_reg + ACC_CLKS),
-                       ioread32(denali->flash_reg + RE_2_WE),
-                       ioread32(denali->flash_reg + RE_2_RE),
-                       ioread32(denali->flash_reg + WE_2_RE),
-                       ioread32(denali->flash_reg + ADDR_2_DATA),
-                       ioread32(denali->flash_reg + RDWR_EN_LO_CNT),
-                       ioread32(denali->flash_reg + RDWR_EN_HI_CNT),
-                       ioread32(denali->flash_reg + CS_SETUP_CNT));
-
-       find_valid_banks(denali);
-
-       /*
-        * If the user specified to override the default timings
-        * with a specific ONFI mode, we apply those changes here.
-        */
-       if (onfi_timing_mode != NAND_DEFAULT_TIMINGS)
-               nand_onfi_timing_set(denali, onfi_timing_mode);
-
-       return status;
+       for (i = 0; i < DENALI_NR_BANKS; i++)
+               iowrite32(U32_MAX, denali->reg + INTR_EN(i));
+       iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE);
 }
 
-static void denali_set_intr_modes(struct denali_nand_info *denali,
-                                       uint16_t INT_ENABLE)
+static void denali_disable_irq(struct denali_nand_info *denali)
 {
-       if (INT_ENABLE)
-               iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE);
-       else
-               iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE);
-}
-
-/*
- * validation function to verify that the controlling software is making
- * a valid request
- */
-static inline bool is_flash_bank_valid(int flash_bank)
-{
-       return flash_bank >= 0 && flash_bank < 4;
-}
-
-static void denali_irq_init(struct denali_nand_info *denali)
-{
-       uint32_t int_mask;
        int i;
 
-       /* Disable global interrupts */
-       denali_set_intr_modes(denali, false);
-
-       int_mask = DENALI_IRQ_ALL;
-
-       /* Clear all status bits */
-       for (i = 0; i < denali->max_banks; ++i)
-               iowrite32(0xFFFF, denali->flash_reg + INTR_STATUS(i));
-
-       denali_irq_enable(denali, int_mask);
+       for (i = 0; i < DENALI_NR_BANKS; i++)
+               iowrite32(0, denali->reg + INTR_EN(i));
+       iowrite32(0, denali->reg + GLOBAL_INT_ENABLE);
 }
 
-static void denali_irq_cleanup(int irqnum, struct denali_nand_info *denali)
+static void denali_clear_irq(struct denali_nand_info *denali,
+                            int bank, uint32_t irq_status)
 {
-       denali_set_intr_modes(denali, false);
+       /* write one to clear bits */
+       iowrite32(irq_status, denali->reg + INTR_STATUS(bank));
 }
 
-static void denali_irq_enable(struct denali_nand_info *denali,
-                                                       uint32_t int_mask)
+static void denali_clear_irq_all(struct denali_nand_info *denali)
 {
        int i;
 
-       for (i = 0; i < denali->max_banks; ++i)
-               iowrite32(int_mask, denali->flash_reg + INTR_EN(i));
+       for (i = 0; i < DENALI_NR_BANKS; i++)
+               denali_clear_irq(denali, i, U32_MAX);
 }
 
-/*
- * This function only returns when an interrupt that this driver cares about
- * occurs. This is to reduce the overhead of servicing interrupts
- */
-static inline uint32_t denali_irq_detected(struct denali_nand_info *denali)
+static irqreturn_t denali_isr(int irq, void *dev_id)
 {
-       return read_interrupt_status(denali) & DENALI_IRQ_ALL;
-}
+       struct denali_nand_info *denali = dev_id;
+       irqreturn_t ret = IRQ_NONE;
+       uint32_t irq_status;
+       int i;
 
-/* Interrupts are cleared by writing a 1 to the appropriate status bit */
-static inline void clear_interrupt(struct denali_nand_info *denali,
-                                                       uint32_t irq_mask)
-{
-       uint32_t intr_status_reg;
+       spin_lock(&denali->irq_lock);
 
-       intr_status_reg = INTR_STATUS(denali->flash_bank);
+       for (i = 0; i < DENALI_NR_BANKS; i++) {
+               irq_status = ioread32(denali->reg + INTR_STATUS(i));
+               if (irq_status)
+                       ret = IRQ_HANDLED;
 
-       iowrite32(irq_mask, denali->flash_reg + intr_status_reg);
-}
+               denali_clear_irq(denali, i, irq_status);
 
-static void clear_interrupts(struct denali_nand_info *denali)
-{
-       uint32_t status;
+               if (i != denali->active_bank)
+                       continue;
 
-       spin_lock_irq(&denali->irq_lock);
+               denali->irq_status |= irq_status;
 
-       status = read_interrupt_status(denali);
-       clear_interrupt(denali, status);
+               if (denali->irq_status & denali->irq_mask)
+                       complete(&denali->complete);
+       }
+
+       spin_unlock(&denali->irq_lock);
 
-       denali->irq_status = 0x0;
-       spin_unlock_irq(&denali->irq_lock);
+       return ret;
 }
 
-static uint32_t read_interrupt_status(struct denali_nand_info *denali)
+static void denali_reset_irq(struct denali_nand_info *denali)
 {
-       uint32_t intr_status_reg;
-
-       intr_status_reg = INTR_STATUS(denali->flash_bank);
+       unsigned long flags;
 
-       return ioread32(denali->flash_reg + intr_status_reg);
+       spin_lock_irqsave(&denali->irq_lock, flags);
+       denali->irq_status = 0;
+       denali->irq_mask = 0;
+       spin_unlock_irqrestore(&denali->irq_lock, flags);
 }
 
-/*
- * This is the interrupt service routine. It handles all interrupts
- * sent to this device. Note that on CE4100, this is a shared interrupt.
- */
-static irqreturn_t denali_isr(int irq, void *dev_id)
+static uint32_t denali_wait_for_irq(struct denali_nand_info *denali,
+                                   uint32_t irq_mask)
 {
-       struct denali_nand_info *denali = dev_id;
+       unsigned long time_left, flags;
        uint32_t irq_status;
-       irqreturn_t result = IRQ_NONE;
 
-       spin_lock(&denali->irq_lock);
+       spin_lock_irqsave(&denali->irq_lock, flags);
 
-       /* check to see if a valid NAND chip has been selected. */
-       if (is_flash_bank_valid(denali->flash_bank)) {
-               /*
-                * check to see if controller generated the interrupt,
-                * since this is a shared interrupt
-                */
-               irq_status = denali_irq_detected(denali);
-               if (irq_status != 0) {
-                       /* handle interrupt */
-                       /* first acknowledge it */
-                       clear_interrupt(denali, irq_status);
-                       /*
-                        * store the status in the device context for someone
-                        * to read
-                        */
-                       denali->irq_status |= irq_status;
-                       /* notify anyone who cares that it happened */
-                       complete(&denali->complete);
-                       /* tell the OS that we've handled this */
-                       result = IRQ_HANDLED;
-               }
+       irq_status = denali->irq_status;
+
+       if (irq_mask & irq_status) {
+               /* return immediately if the IRQ has already happened. */
+               spin_unlock_irqrestore(&denali->irq_lock, flags);
+               return irq_status;
        }
-       spin_unlock(&denali->irq_lock);
-       return result;
-}
 
-static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
-{
-       unsigned long comp_res;
-       uint32_t intr_status;
-       unsigned long timeout = msecs_to_jiffies(1000);
+       denali->irq_mask = irq_mask;
+       reinit_completion(&denali->complete);
+       spin_unlock_irqrestore(&denali->irq_lock, flags);
 
-       do {
-               comp_res =
-                       wait_for_completion_timeout(&denali->complete, timeout);
-               spin_lock_irq(&denali->irq_lock);
-               intr_status = denali->irq_status;
-
-               if (intr_status & irq_mask) {
-                       denali->irq_status &= ~irq_mask;
-                       spin_unlock_irq(&denali->irq_lock);
-                       /* our interrupt was detected */
-                       break;
-               }
+       time_left = wait_for_completion_timeout(&denali->complete,
+                                               msecs_to_jiffies(1000));
+       if (!time_left) {
+               dev_err(denali->dev, "timeout while waiting for irq 0x%x\n",
+                       denali->irq_mask);
+               return 0;
+       }
 
-               /*
-                * these are not the interrupts you are looking for -
-                * need to wait again
-                */
-               spin_unlock_irq(&denali->irq_lock);
-       } while (comp_res != 0);
+       return denali->irq_status;
+}
+
+static uint32_t denali_check_irq(struct denali_nand_info *denali)
+{
+       unsigned long flags;
+       uint32_t irq_status;
 
-       if (comp_res == 0) {
-               /* timeout */
-               pr_err("timeout occurred, status = 0x%x, mask = 0x%x\n",
-                               intr_status, irq_mask);
+       spin_lock_irqsave(&denali->irq_lock, flags);
+       irq_status = denali->irq_status;
+       spin_unlock_irqrestore(&denali->irq_lock, flags);
 
-               intr_status = 0;
-       }
-       return intr_status;
+       return irq_status;
 }
 
 /*
@@ -664,153 +222,111 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en,
        transfer_spare_flag = transfer_spare ? TRANSFER_SPARE_REG__FLAG : 0;
 
        /* Enable spare area/ECC per user's request. */
-       iowrite32(ecc_en_flag, denali->flash_reg + ECC_ENABLE);
-       iowrite32(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG);
+       iowrite32(ecc_en_flag, denali->reg + ECC_ENABLE);
+       iowrite32(transfer_spare_flag, denali->reg + TRANSFER_SPARE_REG);
 }
 
-/*
- * sends a pipeline command operation to the controller. See the Denali NAND
- * controller's user guide for more information (section 4.2.3.6).
- */
-static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
-                                   bool ecc_en, bool transfer_spare,
-                                   int access_type, int op)
+static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-       int status = PASS;
-       uint32_t addr, cmd;
-
-       setup_ecc_for_xfer(denali, ecc_en, transfer_spare);
+       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       int i;
 
-       clear_interrupts(denali);
+       iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali),
+                 denali->host + DENALI_HOST_ADDR);
 
-       addr = BANK(denali->flash_bank) | denali->page;
+       for (i = 0; i < len; i++)
+               buf[i] = ioread32(denali->host + DENALI_HOST_DATA);
+}
 
-       if (op == DENALI_WRITE && access_type != SPARE_ACCESS) {
-               cmd = MODE_01 | addr;
-               iowrite32(cmd, denali->flash_mem);
-       } else if (op == DENALI_WRITE && access_type == SPARE_ACCESS) {
-               /* read spare area */
-               cmd = MODE_10 | addr;
-               index_addr(denali, cmd, access_type);
+static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       int i;
 
-               cmd = MODE_01 | addr;
-               iowrite32(cmd, denali->flash_mem);
-       } else if (op == DENALI_READ) {
-               /* setup page read request for access type */
-               cmd = MODE_10 | addr;
-               index_addr(denali, cmd, access_type);
+       iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali),
+                 denali->host + DENALI_HOST_ADDR);
 
-               cmd = MODE_01 | addr;
-               iowrite32(cmd, denali->flash_mem);
-       }
-       return status;
+       for (i = 0; i < len; i++)
+               iowrite32(buf[i], denali->host + DENALI_HOST_DATA);
 }
 
-/* helper function that simply writes a buffer to the flash */
-static int write_data_to_flash_mem(struct denali_nand_info *denali,
-                                  const uint8_t *buf, int len)
+static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-       uint32_t *buf32;
+       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       uint16_t *buf16 = (uint16_t *)buf;
        int i;
 
-       /*
-        * verify that the len is a multiple of 4.
-        * see comment in read_data_from_flash_mem()
-        */
-       BUG_ON((len % 4) != 0);
+       iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali),
+                 denali->host + DENALI_HOST_ADDR);
 
-       /* write the data to the flash memory */
-       buf32 = (uint32_t *)buf;
-       for (i = 0; i < len / 4; i++)
-               iowrite32(*buf32++, denali->flash_mem + 0x10);
-       return i * 4; /* intent is to return the number of bytes read */
+       for (i = 0; i < len / 2; i++)
+               buf16[i] = ioread32(denali->host + DENALI_HOST_DATA);
 }
 
-/* helper function that simply reads a buffer from the flash */
-static int read_data_from_flash_mem(struct denali_nand_info *denali,
-                                   uint8_t *buf, int len)
+static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
+                              int len)
 {
-       uint32_t *buf32;
+       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       const uint16_t *buf16 = (const uint16_t *)buf;
        int i;
 
-       /*
-        * we assume that len will be a multiple of 4, if not it would be nice
-        * to know about it ASAP rather than have random failures...
-        * This assumption is based on the fact that this function is designed
-        * to be used to read flash pages, which are typically multiples of 4.
-        */
-       BUG_ON((len % 4) != 0);
+       iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali),
+                 denali->host + DENALI_HOST_ADDR);
 
-       /* transfer the data from the flash */
-       buf32 = (uint32_t *)buf;
-       for (i = 0; i < len / 4; i++)
-               *buf32++ = ioread32(denali->flash_mem + 0x10);
-       return i * 4; /* intent is to return the number of bytes read */
+       for (i = 0; i < len / 2; i++)
+               iowrite32(buf16[i], denali->host + DENALI_HOST_DATA);
 }
 
-/* writes OOB data to the device */
-static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
+static uint8_t denali_read_byte(struct mtd_info *mtd)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
-       uint32_t irq_status;
-       uint32_t irq_mask = INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL;
-       int status = 0;
+       uint8_t byte;
 
-       denali->page = page;
+       denali_read_buf(mtd, &byte, 1);
 
-       if (denali_send_pipeline_cmd(denali, false, false, SPARE_ACCESS,
-                                                       DENALI_WRITE) == PASS) {
-               write_data_to_flash_mem(denali, buf, mtd->oobsize);
+       return byte;
+}
 
-               /* wait for operation to complete */
-               irq_status = wait_for_irq(denali, irq_mask);
+static void denali_write_byte(struct mtd_info *mtd, uint8_t byte)
+{
+       denali_write_buf(mtd, &byte, 1);
+}
 
-               if (irq_status == 0) {
-                       dev_err(denali->dev, "OOB write failed\n");
-                       status = -EIO;
-               }
-       } else {
-               dev_err(denali->dev, "unable to send pipeline command\n");
-               status = -EIO;
-       }
-       return status;
+static uint16_t denali_read_word(struct mtd_info *mtd)
+{
+       uint16_t word;
+
+       denali_read_buf16(mtd, (uint8_t *)&word, 2);
+
+       return word;
 }
 
-/* reads OOB data from the device */
-static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
+static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       uint32_t irq_mask = INTR__LOAD_COMP;
-       uint32_t irq_status, addr, cmd;
+       uint32_t type;
 
-       denali->page = page;
+       if (ctrl & NAND_CLE)
+               type = DENALI_MAP11_CMD;
+       else if (ctrl & NAND_ALE)
+               type = DENALI_MAP11_ADDR;
+       else
+               return;
 
-       if (denali_send_pipeline_cmd(denali, false, true, SPARE_ACCESS,
-                                                       DENALI_READ) == PASS) {
-               read_data_from_flash_mem(denali, buf, mtd->oobsize);
+       /*
+        * Some commands are followed by chip->dev_ready or chip->waitfunc.
+        * irq_status must be cleared here to catch the R/B# interrupt later.
+        */
+       if (ctrl & NAND_CTRL_CHANGE)
+               denali_reset_irq(denali);
 
-               /*
-                * wait for command to be accepted
-                * can always use status0 bit as the
-                * mask is identical for each bank.
-                */
-               irq_status = wait_for_irq(denali, irq_mask);
+       denali_host_write(denali, DENALI_BANK(denali) | type, dat);
+}
 
-               if (irq_status == 0)
-                       dev_err(denali->dev, "page on OOB timeout %d\n",
-                                       denali->page);
+static int denali_dev_ready(struct mtd_info *mtd)
+{
+       struct denali_nand_info *denali = mtd_to_denali(mtd);
 
-               /*
-                * We set the device back to MAIN_ACCESS here as I observed
-                * instability with the controller if you do a block erase
-                * and the last transaction was a SPARE_ACCESS. Block erase
-                * is reliable (according to the MTD test infrastructure)
-                * if you are in MAIN_ACCESS.
-                */
-               addr = BANK(denali->flash_bank) | denali->page;
-               cmd = MODE_10 | addr;
-               index_addr(denali, cmd, MAIN_ACCESS);
-       }
+       return !!(denali_check_irq(denali) & INTR__INT_ACT);
 }
 
 static int denali_check_erased_page(struct mtd_info *mtd,
@@ -856,11 +372,11 @@ static int denali_hw_ecc_fixup(struct mtd_info *mtd,
                               unsigned long *uncor_ecc_flags)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
-       int bank = denali->flash_bank;
+       int bank = denali->active_bank;
        uint32_t ecc_cor;
        unsigned int max_bitflips;
 
-       ecc_cor = ioread32(denali->flash_reg + ECC_COR_INFO(bank));
+       ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank));
        ecc_cor >>= ECC_COR_INFO__SHIFT(bank);
 
        if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) {
@@ -886,8 +402,6 @@ static int denali_hw_ecc_fixup(struct mtd_info *mtd,
        return max_bitflips;
 }
 
-#define ECC_SECTOR_SIZE 512
-
 #define ECC_SECTOR(x)  (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)
 #define ECC_BYTE(x)    (((x) & ECC_ERROR_ADDRESS__OFFSET))
 #define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK)
@@ -899,22 +413,23 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd,
                               struct denali_nand_info *denali,
                               unsigned long *uncor_ecc_flags, uint8_t *buf)
 {
+       unsigned int ecc_size = denali->nand.ecc.size;
        unsigned int bitflips = 0;
        unsigned int max_bitflips = 0;
        uint32_t err_addr, err_cor_info;
        unsigned int err_byte, err_sector, err_device;
        uint8_t err_cor_value;
        unsigned int prev_sector = 0;
+       uint32_t irq_status;
 
-       /* read the ECC errors. we'll ignore them for now */
-       denali_set_intr_modes(denali, false);
+       denali_reset_irq(denali);
 
        do {
-               err_addr = ioread32(denali->flash_reg + ECC_ERROR_ADDRESS);
+               err_addr = ioread32(denali->reg + ECC_ERROR_ADDRESS);
                err_sector = ECC_SECTOR(err_addr);
                err_byte = ECC_BYTE(err_addr);
 
-               err_cor_info = ioread32(denali->flash_reg + ERR_CORRECTION_INFO);
+               err_cor_info = ioread32(denali->reg + ERR_CORRECTION_INFO);
                err_cor_value = ECC_CORRECTION_VALUE(err_cor_info);
                err_device = ECC_ERR_DEVICE(err_cor_info);
 
@@ -928,9 +443,9 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd,
                         * an erased sector.
                         */
                        *uncor_ecc_flags |= BIT(err_sector);
-               } else if (err_byte < ECC_SECTOR_SIZE) {
+               } else if (err_byte < ecc_size) {
                        /*
-                        * If err_byte is larger than ECC_SECTOR_SIZE, means error
+                        * If err_byte is larger than ecc_size, means error
                         * happened in OOB, so we ignore it. It's no need for
                         * us to correct it err_device is represented the NAND
                         * error bits are happened in if there are more than
@@ -939,8 +454,8 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd,
                        int offset;
                        unsigned int flips_in_byte;
 
-                       offset = (err_sector * ECC_SECTOR_SIZE + err_byte) *
-                                               denali->devnum + err_device;
+                       offset = (err_sector * ecc_size + err_byte) *
+                                       denali->devs_per_cs + err_device;
 
                        /* correct the ECC error */
                        flips_in_byte = hweight8(buf[offset] ^ err_cor_value);
@@ -959,10 +474,9 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd,
         * ECC_TRANSACTION_DONE interrupt, so here just wait for
         * a while for this interrupt
         */
-       while (!(read_interrupt_status(denali) & INTR__ECC_TRANSACTION_DONE))
-               cpu_relax();
-       clear_interrupts(denali);
-       denali_set_intr_modes(denali, true);
+       irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE);
+       if (!(irq_status & INTR__ECC_TRANSACTION_DONE))
+               return -EIO;
 
        return max_bitflips;
 }
@@ -970,17 +484,17 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd,
 /* programs the controller to either enable/disable DMA transfers */
 static void denali_enable_dma(struct denali_nand_info *denali, bool en)
 {
-       iowrite32(en ? DMA_ENABLE__FLAG : 0, denali->flash_reg + DMA_ENABLE);
-       ioread32(denali->flash_reg + DMA_ENABLE);
+       iowrite32(en ? DMA_ENABLE__FLAG : 0, denali->reg + DMA_ENABLE);
+       ioread32(denali->reg + DMA_ENABLE);
 }
 
-static void denali_setup_dma64(struct denali_nand_info *denali, int op)
+static void denali_setup_dma64(struct denali_nand_info *denali,
+                              dma_addr_t dma_addr, int page, int write)
 {
        uint32_t mode;
        const int page_count = 1;
-       uint64_t addr = denali->buf.dma_buf;
 
-       mode = MODE_10 | BANK(denali->flash_bank) | denali->page;
+       mode = DENALI_MAP10 | DENALI_BANK(denali) | page;
 
        /* DMA is a three step process */
 
@@ -988,191 +502,354 @@ static void denali_setup_dma64(struct denali_nand_info *denali, int op)
         * 1. setup transfer type, interrupt when complete,
         *    burst len = 64 bytes, the number of pages
         */
-       index_addr(denali, mode, 0x01002000 | (64 << 16) | op | page_count);
+       denali_host_write(denali, mode,
+                         0x01002000 | (64 << 16) | (write << 8) | page_count);
 
        /* 2. set memory low address */
-       index_addr(denali, mode, addr);
+       denali_host_write(denali, mode, dma_addr);
 
        /* 3. set memory high address */
-       index_addr(denali, mode, addr >> 32);
+       denali_host_write(denali, mode, (uint64_t)dma_addr >> 32);
 }
 
-static void denali_setup_dma32(struct denali_nand_info *denali, int op)
+static void denali_setup_dma32(struct denali_nand_info *denali,
+                              dma_addr_t dma_addr, int page, int write)
 {
        uint32_t mode;
        const int page_count = 1;
-       uint32_t addr = denali->buf.dma_buf;
 
-       mode = MODE_10 | BANK(denali->flash_bank);
+       mode = DENALI_MAP10 | DENALI_BANK(denali);
 
        /* DMA is a four step process */
 
        /* 1. setup transfer type and # of pages */
-       index_addr(denali, mode | denali->page, 0x2000 | op | page_count);
+       denali_host_write(denali, mode | page,
+                         0x2000 | (write << 8) | page_count);
 
        /* 2. set memory high address bits 23:8 */
-       index_addr(denali, mode | ((addr >> 16) << 8), 0x2200);
+       denali_host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200);
 
        /* 3. set memory low address bits 23:8 */
-       index_addr(denali, mode | ((addr & 0xffff) << 8), 0x2300);
+       denali_host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300);
 
        /* 4. interrupt when complete, burst len = 64 bytes */
-       index_addr(denali, mode | 0x14000, 0x2400);
+       denali_host_write(denali, mode | 0x14000, 0x2400);
 }
 
-static void denali_setup_dma(struct denali_nand_info *denali, int op)
+static void denali_setup_dma(struct denali_nand_info *denali,
+                            dma_addr_t dma_addr, int page, int write)
 {
        if (denali->caps & DENALI_CAP_DMA_64BIT)
-               denali_setup_dma64(denali, op);
+               denali_setup_dma64(denali, dma_addr, page, write);
        else
-               denali_setup_dma32(denali, op);
+               denali_setup_dma32(denali, dma_addr, page, write);
 }
 
-/*
- * writes a page. user specifies type, and this function handles the
- * configuration details.
- */
-static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                       const uint8_t *buf, bool raw_xfer)
+static int denali_pio_read(struct denali_nand_info *denali, void *buf,
+                          size_t size, int page, int raw)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
-       dma_addr_t addr = denali->buf.dma_buf;
-       size_t size = mtd->writesize + mtd->oobsize;
+       uint32_t addr = DENALI_BANK(denali) | page;
+       uint32_t *buf32 = (uint32_t *)buf;
+       uint32_t irq_status, ecc_err_mask;
+       int i;
+
+       if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
+               ecc_err_mask = INTR__ECC_UNCOR_ERR;
+       else
+               ecc_err_mask = INTR__ECC_ERR;
+
+       denali_reset_irq(denali);
+
+       iowrite32(DENALI_MAP01 | addr, denali->host + DENALI_HOST_ADDR);
+       for (i = 0; i < size / 4; i++)
+               *buf32++ = ioread32(denali->host + DENALI_HOST_DATA);
+
+       irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC);
+       if (!(irq_status & INTR__PAGE_XFER_INC))
+               return -EIO;
+
+       if (irq_status & INTR__ERASED_PAGE)
+               memset(buf, 0xff, size);
+
+       return irq_status & ecc_err_mask ? -EBADMSG : 0;
+}
+
+static int denali_pio_write(struct denali_nand_info *denali,
+                           const void *buf, size_t size, int page, int raw)
+{
+       uint32_t addr = DENALI_BANK(denali) | page;
+       const uint32_t *buf32 = (uint32_t *)buf;
        uint32_t irq_status;
-       uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL;
+       int i;
 
-       /*
-        * if it is a raw xfer, we want to disable ecc and send the spare area.
-        * !raw_xfer - enable ecc
-        * raw_xfer - transfer spare
-        */
-       setup_ecc_for_xfer(denali, !raw_xfer, raw_xfer);
+       denali_reset_irq(denali);
 
-       /* copy buffer into DMA buffer */
-       memcpy(denali->buf.buf, buf, mtd->writesize);
+       iowrite32(DENALI_MAP01 | addr, denali->host + DENALI_HOST_ADDR);
+       for (i = 0; i < size / 4; i++)
+               iowrite32(*buf32++, denali->host + DENALI_HOST_DATA);
 
-       if (raw_xfer) {
-               /* transfer the data to the spare area */
-               memcpy(denali->buf.buf + mtd->writesize,
-                       chip->oob_poi,
-                       mtd->oobsize);
+       irq_status = denali_wait_for_irq(denali,
+                               INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL);
+       if (!(irq_status & INTR__PROGRAM_COMP))
+               return -EIO;
+
+       return 0;
+}
+
+static int denali_pio_xfer(struct denali_nand_info *denali, void *buf,
+                          size_t size, int page, int raw, int write)
+{
+       if (write)
+               return denali_pio_write(denali, buf, size, page, raw);
+       else
+               return denali_pio_read(denali, buf, size, page, raw);
+}
+
+static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
+                          size_t size, int page, int raw, int write)
+{
+       dma_addr_t dma_addr;
+       uint32_t irq_mask, irq_status, ecc_err_mask;
+       enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+       int ret = 0;
+
+       dma_addr = dma_map_single(denali->dev, buf, size, dir);
+       if (dma_mapping_error(denali->dev, dma_addr)) {
+               dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n");
+               return denali_pio_xfer(denali, buf, size, page, raw, write);
        }
 
-       dma_sync_single_for_device(denali->dev, addr, size, DMA_TO_DEVICE);
+       if (write) {
+               /*
+                * INTR__PROGRAM_COMP is never asserted for the DMA transfer.
+                * We can use INTR__DMA_CMD_COMP instead.  This flag is asserted
+                * when the page program is completed.
+                */
+               irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL;
+               ecc_err_mask = 0;
+       } else if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) {
+               irq_mask = INTR__DMA_CMD_COMP;
+               ecc_err_mask = INTR__ECC_UNCOR_ERR;
+       } else {
+               irq_mask = INTR__DMA_CMD_COMP;
+               ecc_err_mask = INTR__ECC_ERR;
+       }
 
-       clear_interrupts(denali);
        denali_enable_dma(denali, true);
 
-       denali_setup_dma(denali, DENALI_WRITE);
+       denali_reset_irq(denali);
+       denali_setup_dma(denali, dma_addr, page, write);
 
        /* wait for operation to complete */
-       irq_status = wait_for_irq(denali, irq_mask);
-
-       if (irq_status == 0) {
-               dev_err(denali->dev, "timeout on write_page (type = %d)\n",
-                       raw_xfer);
-               denali->status = NAND_STATUS_FAIL;
-       }
+       irq_status = denali_wait_for_irq(denali, irq_mask);
+       if (!(irq_status & INTR__DMA_CMD_COMP))
+               ret = -EIO;
+       else if (irq_status & ecc_err_mask)
+               ret = -EBADMSG;
 
        denali_enable_dma(denali, false);
-       dma_sync_single_for_cpu(denali->dev, addr, size, DMA_TO_DEVICE);
+       dma_unmap_single(denali->dev, dma_addr, size, dir);
 
-       return 0;
-}
+       if (irq_status & INTR__ERASED_PAGE)
+               memset(buf, 0xff, size);
 
-/* NAND core entry points */
+       return ret;
+}
 
-/*
- * this is the callback that the NAND core calls to write a page. Since
- * writing a page with ECC or without is similar, all the work is done
- * by write_page above.
- */
-static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                               const uint8_t *buf, int oob_required, int page)
+static int denali_data_xfer(struct denali_nand_info *denali, void *buf,
+                           size_t size, int page, int raw, int write)
 {
-       /*
-        * for regular page writes, we let HW handle all the ECC
-        * data written to the device.
-        */
-       return write_page(mtd, chip, buf, false);
+       setup_ecc_for_xfer(denali, !raw, raw);
+
+       if (denali->dma_avail)
+               return denali_dma_xfer(denali, buf, size, page, raw, write);
+       else
+               return denali_pio_xfer(denali, buf, size, page, raw, write);
 }
 
-/*
- * This is the callback that the NAND core calls to write a page without ECC.
- * raw access is similar to ECC page writes, so all the work is done in the
- * write_page() function above.
- */
-static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                const uint8_t *buf, int oob_required,
-                                int page)
+static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
+                           int page, int write)
 {
-       /*
-        * for raw page writes, we want to disable ECC and simply write
-        * whatever data is in the buffer.
-        */
-       return write_page(mtd, chip, buf, true);
+       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       unsigned int start_cmd = write ? NAND_CMD_SEQIN : NAND_CMD_READ0;
+       unsigned int rnd_cmd = write ? NAND_CMD_RNDIN : NAND_CMD_RNDOUT;
+       int writesize = mtd->writesize;
+       int oobsize = mtd->oobsize;
+       uint8_t *bufpoi = chip->oob_poi;
+       int ecc_steps = chip->ecc.steps;
+       int ecc_size = chip->ecc.size;
+       int ecc_bytes = chip->ecc.bytes;
+       int oob_skip = denali->oob_skip_bytes;
+       size_t size = writesize + oobsize;
+       int i, pos, len;
+
+       /* BBM at the beginning of the OOB area */
+       chip->cmdfunc(mtd, start_cmd, writesize, page);
+       if (write)
+               chip->write_buf(mtd, bufpoi, oob_skip);
+       else
+               chip->read_buf(mtd, bufpoi, oob_skip);
+       bufpoi += oob_skip;
+
+       /* OOB ECC */
+       for (i = 0; i < ecc_steps; i++) {
+               pos = ecc_size + i * (ecc_size + ecc_bytes);
+               len = ecc_bytes;
+
+               if (pos >= writesize)
+                       pos += oob_skip;
+               else if (pos + len > writesize)
+                       len = writesize - pos;
+
+               chip->cmdfunc(mtd, rnd_cmd, pos, -1);
+               if (write)
+                       chip->write_buf(mtd, bufpoi, len);
+               else
+                       chip->read_buf(mtd, bufpoi, len);
+               bufpoi += len;
+               if (len < ecc_bytes) {
+                       len = ecc_bytes - len;
+                       chip->cmdfunc(mtd, rnd_cmd, writesize + oob_skip, -1);
+                       if (write)
+                               chip->write_buf(mtd, bufpoi, len);
+                       else
+                               chip->read_buf(mtd, bufpoi, len);
+                       bufpoi += len;
+               }
+       }
+
+       /* OOB free */
+       len = oobsize - (bufpoi - chip->oob_poi);
+       chip->cmdfunc(mtd, rnd_cmd, size - len, -1);
+       if (write)
+               chip->write_buf(mtd, bufpoi, len);
+       else
+               chip->read_buf(mtd, bufpoi, len);
 }
 
-static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                           int page)
+static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                               uint8_t *buf, int oob_required, int page)
 {
-       return write_oob_data(mtd, chip->oob_poi, page);
+       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       int writesize = mtd->writesize;
+       int oobsize = mtd->oobsize;
+       int ecc_steps = chip->ecc.steps;
+       int ecc_size = chip->ecc.size;
+       int ecc_bytes = chip->ecc.bytes;
+       void *dma_buf = denali->buf;
+       int oob_skip = denali->oob_skip_bytes;
+       size_t size = writesize + oobsize;
+       int ret, i, pos, len;
+
+       ret = denali_data_xfer(denali, dma_buf, size, page, 1, 0);
+       if (ret)
+               return ret;
+
+       /* Arrange the buffer for syndrome payload/ecc layout */
+       if (buf) {
+               for (i = 0; i < ecc_steps; i++) {
+                       pos = i * (ecc_size + ecc_bytes);
+                       len = ecc_size;
+
+                       if (pos >= writesize)
+                               pos += oob_skip;
+                       else if (pos + len > writesize)
+                               len = writesize - pos;
+
+                       memcpy(buf, dma_buf + pos, len);
+                       buf += len;
+                       if (len < ecc_size) {
+                               len = ecc_size - len;
+                               memcpy(buf, dma_buf + writesize + oob_skip,
+                                      len);
+                               buf += len;
+                       }
+               }
+       }
+
+       if (oob_required) {
+               uint8_t *oob = chip->oob_poi;
+
+               /* BBM at the beginning of the OOB area */
+               memcpy(oob, dma_buf + writesize, oob_skip);
+               oob += oob_skip;
+
+               /* OOB ECC */
+               for (i = 0; i < ecc_steps; i++) {
+                       pos = ecc_size + i * (ecc_size + ecc_bytes);
+                       len = ecc_bytes;
+
+                       if (pos >= writesize)
+                               pos += oob_skip;
+                       else if (pos + len > writesize)
+                               len = writesize - pos;
+
+                       memcpy(oob, dma_buf + pos, len);
+                       oob += len;
+                       if (len < ecc_bytes) {
+                               len = ecc_bytes - len;
+                               memcpy(oob, dma_buf + writesize + oob_skip,
+                                      len);
+                               oob += len;
+                       }
+               }
+
+               /* OOB free */
+               len = oobsize - (oob - chip->oob_poi);
+               memcpy(oob, dma_buf + size - len, len);
+       }
+
+       return 0;
 }
 
 static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
                           int page)
 {
-       read_oob_data(mtd, chip->oob_poi, page);
+       denali_oob_xfer(mtd, chip, page, 0);
 
        return 0;
 }
 
-static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                           uint8_t *buf, int oob_required, int page)
+static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+                           int page)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       dma_addr_t addr = denali->buf.dma_buf;
-       size_t size = mtd->writesize + mtd->oobsize;
-       uint32_t irq_status;
-       uint32_t irq_mask = denali->caps & DENALI_CAP_HW_ECC_FIXUP ?
-                               INTR__DMA_CMD_COMP | INTR__ECC_UNCOR_ERR :
-                               INTR__ECC_TRANSACTION_DONE | INTR__ECC_ERR;
-       unsigned long uncor_ecc_flags = 0;
-       int stat = 0;
+       int status;
 
-       if (page != denali->page) {
-               dev_err(denali->dev,
-                       "IN %s: page %d is not equal to denali->page %d",
-                       __func__, page, denali->page);
-               BUG();
-       }
+       denali_reset_irq(denali);
 
-       setup_ecc_for_xfer(denali, true, false);
+       denali_oob_xfer(mtd, chip, page, 1);
 
-       denali_enable_dma(denali, true);
-       dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE);
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+       status = chip->waitfunc(mtd, chip);
 
-       clear_interrupts(denali);
-       denali_setup_dma(denali, DENALI_READ);
-
-       /* wait for operation to complete */
-       irq_status = wait_for_irq(denali, irq_mask);
+       return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
 
-       dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE);
+static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+                           uint8_t *buf, int oob_required, int page)
+{
+       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       unsigned long uncor_ecc_flags = 0;
+       int stat = 0;
+       int ret;
 
-       memcpy(buf, denali->buf.buf, mtd->writesize);
+       ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0);
+       if (ret && ret != -EBADMSG)
+               return ret;
 
        if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
                stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags);
-       else if (irq_status & INTR__ECC_ERR)
+       else if (ret == -EBADMSG)
                stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf);
-       denali_enable_dma(denali, false);
 
        if (stat < 0)
                return stat;
 
        if (uncor_ecc_flags) {
-               read_oob_data(mtd, chip->oob_poi, denali->page);
+               ret = denali_read_oob(mtd, chip, page);
+               if (ret)
+                       return ret;
 
                stat = denali_check_erased_page(mtd, chip, buf,
                                                uncor_ecc_flags, stat);
@@ -1181,137 +858,266 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        return stat;
 }
 
-static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint8_t *buf, int oob_required, int page)
+static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                                const uint8_t *buf, int oob_required, int page)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       dma_addr_t addr = denali->buf.dma_buf;
-       size_t size = mtd->writesize + mtd->oobsize;
-       uint32_t irq_mask = INTR__DMA_CMD_COMP;
-
-       if (page != denali->page) {
-               dev_err(denali->dev,
-                       "IN %s: page %d is not equal to denali->page %d",
-                       __func__, page, denali->page);
-               BUG();
-       }
-
-       setup_ecc_for_xfer(denali, false, true);
-       denali_enable_dma(denali, true);
-
-       dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE);
-
-       clear_interrupts(denali);
-       denali_setup_dma(denali, DENALI_READ);
-
-       /* wait for operation to complete */
-       wait_for_irq(denali, irq_mask);
+       int writesize = mtd->writesize;
+       int oobsize = mtd->oobsize;
+       int ecc_steps = chip->ecc.steps;
+       int ecc_size = chip->ecc.size;
+       int ecc_bytes = chip->ecc.bytes;
+       void *dma_buf = denali->buf;
+       int oob_skip = denali->oob_skip_bytes;
+       size_t size = writesize + oobsize;
+       int i, pos, len;
 
-       dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE);
+       /*
+        * Fill the buffer with 0xff first except the full page transfer.
+        * This simplifies the logic.
+        */
+       if (!buf || !oob_required)
+               memset(dma_buf, 0xff, size);
+
+       /* Arrange the buffer for syndrome payload/ecc layout */
+       if (buf) {
+               for (i = 0; i < ecc_steps; i++) {
+                       pos = i * (ecc_size + ecc_bytes);
+                       len = ecc_size;
+
+                       if (pos >= writesize)
+                               pos += oob_skip;
+                       else if (pos + len > writesize)
+                               len = writesize - pos;
+
+                       memcpy(dma_buf + pos, buf, len);
+                       buf += len;
+                       if (len < ecc_size) {
+                               len = ecc_size - len;
+                               memcpy(dma_buf + writesize + oob_skip, buf,
+                                      len);
+                               buf += len;
+                       }
+               }
+       }
 
-       denali_enable_dma(denali, false);
+       if (oob_required) {
+               const uint8_t *oob = chip->oob_poi;
+
+               /* BBM at the beginning of the OOB area */
+               memcpy(dma_buf + writesize, oob, oob_skip);
+               oob += oob_skip;
+
+               /* OOB ECC */
+               for (i = 0; i < ecc_steps; i++) {
+                       pos = ecc_size + i * (ecc_size + ecc_bytes);
+                       len = ecc_bytes;
+
+                       if (pos >= writesize)
+                               pos += oob_skip;
+                       else if (pos + len > writesize)
+                               len = writesize - pos;
+
+                       memcpy(dma_buf + pos, oob, len);
+                       oob += len;
+                       if (len < ecc_bytes) {
+                               len = ecc_bytes - len;
+                               memcpy(dma_buf + writesize + oob_skip, oob,
+                                      len);
+                               oob += len;
+                       }
+               }
 
-       memcpy(buf, denali->buf.buf, mtd->writesize);
-       memcpy(chip->oob_poi, denali->buf.buf + mtd->writesize, mtd->oobsize);
+               /* OOB free */
+               len = oobsize - (oob - chip->oob_poi);
+               memcpy(dma_buf + size - len, oob, len);
+       }
 
-       return 0;
+       return denali_data_xfer(denali, dma_buf, size, page, 1, 1);
 }
 
-static uint8_t denali_read_byte(struct mtd_info *mtd)
+static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                            const uint8_t *buf, int oob_required, int page)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       uint8_t result = 0xff;
-
-       if (denali->buf.head < denali->buf.tail)
-               result = denali->buf.buf[denali->buf.head++];
 
-       return result;
+       return denali_data_xfer(denali, (void *)buf, mtd->writesize,
+                               page, 0, 1);
 }
 
 static void denali_select_chip(struct mtd_info *mtd, int chip)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
 
-       spin_lock_irq(&denali->irq_lock);
-       denali->flash_bank = chip;
-       spin_unlock_irq(&denali->irq_lock);
+       denali->active_bank = chip;
 }
 
 static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       int status = denali->status;
+       uint32_t irq_status;
 
-       denali->status = 0;
+       /* R/B# pin transitioned from low to high? */
+       irq_status = denali_wait_for_irq(denali, INTR__INT_ACT);
 
-       return status;
+       return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
 }
 
 static int denali_erase(struct mtd_info *mtd, int page)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
+       uint32_t irq_status;
 
-       uint32_t cmd, irq_status;
-
-       clear_interrupts(denali);
+       denali_reset_irq(denali);
 
-       /* setup page read request for access type */
-       cmd = MODE_10 | BANK(denali->flash_bank) | page;
-       index_addr(denali, cmd, 0x1);
+       denali_host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page,
+                         DENALI_ERASE);
 
        /* wait for erase to complete or failure to occur */
-       irq_status = wait_for_irq(denali, INTR__ERASE_COMP | INTR__ERASE_FAIL);
+       irq_status = denali_wait_for_irq(denali,
+                                        INTR__ERASE_COMP | INTR__ERASE_FAIL);
 
-       return irq_status & INTR__ERASE_FAIL ? NAND_STATUS_FAIL : PASS;
+       return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL;
 }
 
-static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
-                          int page)
+#define DIV_ROUND_DOWN_ULL(ll, d) \
+       ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
+
+static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
+                                      const struct nand_data_interface *conf)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       uint32_t addr, id;
+       const struct nand_sdr_timings *timings;
+       unsigned long t_clk;
+       int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
+       int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup;
+       int addr_2_data_mask;
+       uint32_t tmp;
+
+       timings = nand_get_sdr_timings(conf);
+       if (IS_ERR(timings))
+               return PTR_ERR(timings);
+
+       /* clk_x period in picoseconds */
+       t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
+       if (!t_clk)
+               return -EINVAL;
+
+       if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
+               return 0;
+
+       /* tREA -> ACC_CLKS */
+       acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk);
+       acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE);
+
+       tmp = ioread32(denali->reg + ACC_CLKS);
+       tmp &= ~ACC_CLKS__VALUE;
+       tmp |= acc_clks;
+       iowrite32(tmp, denali->reg + ACC_CLKS);
+
+       /* tRWH -> RE_2_WE */
+       re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk);
+       re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE);
+
+       tmp = ioread32(denali->reg + RE_2_WE);
+       tmp &= ~RE_2_WE__VALUE;
+       tmp |= re_2_we;
+       iowrite32(tmp, denali->reg + RE_2_WE);
+
+       /* tRHZ -> RE_2_RE */
+       re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk);
+       re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE);
+
+       tmp = ioread32(denali->reg + RE_2_RE);
+       tmp &= ~RE_2_RE__VALUE;
+       tmp |= re_2_re;
+       iowrite32(tmp, denali->reg + RE_2_RE);
+
+       /* tWHR -> WE_2_RE */
+       we_2_re = DIV_ROUND_UP(timings->tWHR_min, t_clk);
+       we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE);
+
+       tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE);
+       tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE;
+       tmp |= we_2_re;
+       iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE);
+
+       /* tADL -> ADDR_2_DATA */
+
+       /* for older versions, ADDR_2_DATA is only 6 bit wide */
+       addr_2_data_mask = TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA;
+       if (denali->revision < 0x0501)
+               addr_2_data_mask >>= 1;
+
+       addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk);
+       addr_2_data = min_t(int, addr_2_data, addr_2_data_mask);
+
+       tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA);
+       tmp &= ~addr_2_data_mask;
+       tmp |= addr_2_data;
+       iowrite32(tmp, denali->reg + TCWAW_AND_ADDR_2_DATA);
+
+       /* tREH, tWH -> RDWR_EN_HI_CNT */
+       rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min),
+                                 t_clk);
+       rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE);
+
+       tmp = ioread32(denali->reg + RDWR_EN_HI_CNT);
+       tmp &= ~RDWR_EN_HI_CNT__VALUE;
+       tmp |= rdwr_en_hi;
+       iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT);
+
+       /* tRP, tWP -> RDWR_EN_LO_CNT */
+       rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min),
+                                 t_clk);
+       rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min),
+                                    t_clk);
+       rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT);
+       rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi);
+       rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE);
+
+       tmp = ioread32(denali->reg + RDWR_EN_LO_CNT);
+       tmp &= ~RDWR_EN_LO_CNT__VALUE;
+       tmp |= rdwr_en_lo;
+       iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT);
+
+       /* tCS, tCEA -> CS_SETUP_CNT */
+       cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo,
+                       (int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks,
+                       0);
+       cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE);
+
+       tmp = ioread32(denali->reg + CS_SETUP_CNT);
+       tmp &= ~CS_SETUP_CNT__VALUE;
+       tmp |= cs_setup;
+       iowrite32(tmp, denali->reg + CS_SETUP_CNT);
+
+       return 0;
+}
+
+static void denali_reset_banks(struct denali_nand_info *denali)
+{
+       u32 irq_status;
        int i;
 
-       switch (cmd) {
-       case NAND_CMD_PAGEPROG:
-               break;
-       case NAND_CMD_STATUS:
-               read_status(denali);
-               break;
-       case NAND_CMD_READID:
-       case NAND_CMD_PARAM:
-               reset_buf(denali);
-               /*
-                * sometimes ManufactureId read from register is not right
-                * e.g. some of Micron MT29F32G08QAA MLC NAND chips
-                * So here we send READID cmd to NAND insteand
-                */
-               addr = MODE_11 | BANK(denali->flash_bank);
-               index_addr(denali, addr | 0, 0x90);
-               index_addr(denali, addr | 1, col);
-               for (i = 0; i < 8; i++) {
-                       index_addr_read_data(denali, addr | 2, &id);
-                       write_byte_to_buf(denali, id);
-               }
-               break;
-       case NAND_CMD_READ0:
-       case NAND_CMD_SEQIN:
-               denali->page = page;
-               break;
-       case NAND_CMD_RESET:
-               reset_bank(denali);
-               break;
-       case NAND_CMD_READOOB:
-               /* TODO: Read OOB data */
-               break;
-       default:
-               pr_err(": unsupported command received 0x%x\n", cmd);
-               break;
+       for (i = 0; i < denali->max_banks; i++) {
+               denali->active_bank = i;
+
+               denali_reset_irq(denali);
+
+               iowrite32(DEVICE_RESET__BANK(i),
+                         denali->reg + DEVICE_RESET);
+
+               irq_status = denali_wait_for_irq(denali,
+                       INTR__RST_COMP | INTR__INT_ACT | INTR__TIME_OUT);
+               if (!(irq_status & INTR__INT_ACT))
+                       break;
        }
+
+       dev_dbg(denali->dev, "%d chips connected\n", i);
+       denali->max_banks = i;
 }
-/* end NAND core entry points */
 
-/* Initialization code to bring the device up to a known good state */
 static void denali_hw_init(struct denali_nand_info *denali)
 {
        /*
@@ -1319,8 +1125,7 @@ static void denali_hw_init(struct denali_nand_info *denali)
         * override it.
         */
        if (!denali->revision)
-               denali->revision =
-                               swab16(ioread32(denali->flash_reg + REVISION));
+               denali->revision = swab16(ioread32(denali->reg + REVISION));
 
        /*
         * tell driver how many bit controller will skip before
@@ -1328,30 +1133,51 @@ static void denali_hw_init(struct denali_nand_info *denali)
         * set by firmware. So we read this value out.
         * if this value is 0, just let it be.
         */
-       denali->bbtskipbytes = ioread32(denali->flash_reg +
-                                               SPARE_AREA_SKIP_BYTES);
+       denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
        detect_max_banks(denali);
-       denali_nand_reset(denali);
-       iowrite32(0x0F, denali->flash_reg + RB_PIN_ENABLED);
-       iowrite32(CHIP_EN_DONT_CARE__FLAG,
-                       denali->flash_reg + CHIP_ENABLE_DONT_CARE);
+       iowrite32(0x0F, denali->reg + RB_PIN_ENABLED);
+       iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
 
-       iowrite32(0xffff, denali->flash_reg + SPARE_AREA_MARKER);
+       iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER);
 
        /* Should set value for these registers when init */
-       iowrite32(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES);
-       iowrite32(1, denali->flash_reg + ECC_ENABLE);
-       denali_nand_timing_set(denali);
-       denali_irq_init(denali);
+       iowrite32(0, denali->reg + TWO_ROW_ADDR_CYCLES);
+       iowrite32(1, denali->reg + ECC_ENABLE);
 }
 
-/*
- * Althogh controller spec said SLC ECC is forceb to be 4bit,
- * but denali controller in MRST only support 15bit and 8bit ECC
- * correction
- */
-#define ECC_8BITS      14
-#define ECC_15BITS     26
+int denali_calc_ecc_bytes(int step_size, int strength)
+{
+       /* BCH code.  Denali requires ecc.bytes to be multiple of 2 */
+       return DIV_ROUND_UP(strength * fls(step_size * 8), 16) * 2;
+}
+EXPORT_SYMBOL(denali_calc_ecc_bytes);
+
+static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip,
+                           struct denali_nand_info *denali)
+{
+       int oobavail = mtd->oobsize - denali->oob_skip_bytes;
+       int ret;
+
+       /*
+        * If .size and .strength are already set (usually by DT),
+        * check if they are supported by this controller.
+        */
+       if (chip->ecc.size && chip->ecc.strength)
+               return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail);
+
+       /*
+        * We want .size and .strength closest to the chip's requirement
+        * unless NAND_ECC_MAXIMIZE is requested.
+        */
+       if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
+               ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail);
+               if (!ret)
+                       return 0;
+       }
+
+       /* Max ECC strength is the last thing we can do */
+       return nand_maximize_ecc(chip, denali->ecc_caps, oobavail);
+}
 
 static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
                                struct mtd_oob_region *oobregion)
@@ -1362,7 +1188,7 @@ static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
        if (section)
                return -ERANGE;
 
-       oobregion->offset = denali->bbtskipbytes;
+       oobregion->offset = denali->oob_skip_bytes;
        oobregion->length = chip->ecc.total;
 
        return 0;
@@ -1377,7 +1203,7 @@ static int denali_ooblayout_free(struct mtd_info *mtd, int section,
        if (section)
                return -ERANGE;
 
-       oobregion->offset = chip->ecc.total + denali->bbtskipbytes;
+       oobregion->offset = chip->ecc.total + denali->oob_skip_bytes;
        oobregion->length = mtd->oobsize - oobregion->offset;
 
        return 0;
@@ -1388,29 +1214,6 @@ static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
        .free = denali_ooblayout_free,
 };
 
-static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
-static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
-
-static struct nand_bbt_descr bbt_main_descr = {
-       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-       .offs = 8,
-       .len = 4,
-       .veroffs = 12,
-       .maxblocks = 4,
-       .pattern = bbt_pattern,
-};
-
-static struct nand_bbt_descr bbt_mirror_descr = {
-       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-       .offs = 8,
-       .len = 4,
-       .veroffs = 12,
-       .maxblocks = 4,
-       .pattern = mirror_pattern,
-};
-
 /* initialize driver data structures */
 static void denali_drv_init(struct denali_nand_info *denali)
 {
@@ -1425,12 +1228,6 @@ static void denali_drv_init(struct denali_nand_info *denali)
         * element that might be access shared data (interrupt status)
         */
        spin_lock_init(&denali->irq_lock);
-
-       /* indicate that MTD has not selected a valid bank yet */
-       denali->flash_bank = CHIP_SELECT_INVALID;
-
-       /* initialize our irq_status variable to indicate no interrupts */
-       denali->irq_status = 0;
 }
 
 static int denali_multidev_fixup(struct denali_nand_info *denali)
@@ -1445,23 +1242,23 @@ static int denali_multidev_fixup(struct denali_nand_info *denali)
         * In this case, the core framework knows nothing about this fact,
         * so we should tell it the _logical_ pagesize and anything necessary.
         */
-       denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
+       denali->devs_per_cs = ioread32(denali->reg + DEVICES_CONNECTED);
 
        /*
         * On some SoCs, DEVICES_CONNECTED is not auto-detected.
         * For those, DEVICES_CONNECTED is left to 0.  Set 1 if it is the case.
         */
-       if (denali->devnum == 0) {
-               denali->devnum = 1;
-               iowrite32(1, denali->flash_reg + DEVICES_CONNECTED);
+       if (denali->devs_per_cs == 0) {
+               denali->devs_per_cs = 1;
+               iowrite32(1, denali->reg + DEVICES_CONNECTED);
        }
 
-       if (denali->devnum == 1)
+       if (denali->devs_per_cs == 1)
                return 0;
 
-       if (denali->devnum != 2) {
+       if (denali->devs_per_cs != 2) {
                dev_err(denali->dev, "unsupported number of devices %d\n",
-                       denali->devnum);
+                       denali->devs_per_cs);
                return -EINVAL;
        }
 
@@ -1479,7 +1276,7 @@ static int denali_multidev_fixup(struct denali_nand_info *denali)
        chip->ecc.size <<= 1;
        chip->ecc.bytes <<= 1;
        chip->ecc.strength <<= 1;
-       denali->bbtskipbytes <<= 1;
+       denali->oob_skip_bytes <<= 1;
 
        return 0;
 }
@@ -1490,27 +1287,12 @@ int denali_init(struct denali_nand_info *denali)
        struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
 
-       if (denali->platform == INTEL_CE4100) {
-               /*
-                * Due to a silicon limitation, we can only support
-                * ONFI timing mode 1 and below.
-                */
-               if (onfi_timing_mode < -1 || onfi_timing_mode > 1) {
-                       pr_err("Intel CE4100 only supports ONFI timing mode 1 or below\n");
-                       return -EINVAL;
-               }
-       }
-
-       /* allocate a temporary buffer for nand_scan_ident() */
-       denali->buf.buf = devm_kzalloc(denali->dev, PAGE_SIZE,
-                                       GFP_DMA | GFP_KERNEL);
-       if (!denali->buf.buf)
-               return -ENOMEM;
-
        mtd->dev.parent = denali->dev;
        denali_hw_init(denali);
        denali_drv_init(denali);
 
+       denali_clear_irq_all(denali);
+
        /* Request IRQ after all the hardware initialization is finished */
        ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
                               IRQF_SHARED, DENALI_NAND_NAME, denali);
@@ -1519,8 +1301,11 @@ int denali_init(struct denali_nand_info *denali)
                return ret;
        }
 
-       /* now that our ISR is registered, we can enable interrupts */
-       denali_set_intr_modes(denali, true);
+       denali_enable_irq(denali);
+       denali_reset_banks(denali);
+
+       denali->active_bank = DENALI_INVALID_BANK;
+
        nand_set_flash_node(chip, denali->dev->of_node);
        /* Fallback to the default name if DT did not give "label" property */
        if (!mtd->name)
@@ -1528,10 +1313,17 @@ int denali_init(struct denali_nand_info *denali)
 
        /* register the driver with the NAND core subsystem */
        chip->select_chip = denali_select_chip;
-       chip->cmdfunc = denali_cmdfunc;
        chip->read_byte = denali_read_byte;
+       chip->write_byte = denali_write_byte;
+       chip->read_word = denali_read_word;
+       chip->cmd_ctrl = denali_cmd_ctrl;
+       chip->dev_ready = denali_dev_ready;
        chip->waitfunc = denali_waitfunc;
 
+       /* clk rate info is needed for setup_data_interface */
+       if (denali->clk_x_rate)
+               chip->setup_data_interface = denali_setup_data_interface;
+
        /*
         * scan for NAND devices attached to the controller
         * this is the first stage in a two step process to register
@@ -1539,33 +1331,25 @@ int denali_init(struct denali_nand_info *denali)
         */
        ret = nand_scan_ident(mtd, denali->max_banks, NULL);
        if (ret)
-               goto failed_req_irq;
-
-       /* allocate the right size buffer now */
-       devm_kfree(denali->dev, denali->buf.buf);
-       denali->buf.buf = devm_kzalloc(denali->dev,
-                            mtd->writesize + mtd->oobsize,
-                            GFP_KERNEL);
-       if (!denali->buf.buf) {
-               ret = -ENOMEM;
-               goto failed_req_irq;
-       }
+               goto disable_irq;
 
-       ret = dma_set_mask(denali->dev,
-                          DMA_BIT_MASK(denali->caps & DENALI_CAP_DMA_64BIT ?
-                                       64 : 32));
-       if (ret) {
-               dev_err(denali->dev, "No usable DMA configuration\n");
-               goto failed_req_irq;
+       if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
+               denali->dma_avail = 1;
+
+       if (denali->dma_avail) {
+               int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32;
+
+               ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit));
+               if (ret) {
+                       dev_info(denali->dev,
+                                "Failed to set DMA mask. Disabling DMA.\n");
+                       denali->dma_avail = 0;
+               }
        }
 
-       denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf,
-                            mtd->writesize + mtd->oobsize,
-                            DMA_BIDIRECTIONAL);
-       if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
-               dev_err(denali->dev, "Failed to map DMA buffer\n");
-               ret = -EIO;
-               goto failed_req_irq;
+       if (denali->dma_avail) {
+               chip->options |= NAND_USE_BOUNCE_BUFFER;
+               chip->buf_align = 16;
        }
 
        /*
@@ -1574,46 +1358,49 @@ int denali_init(struct denali_nand_info *denali)
         * bad block management.
         */
 
-       /* Bad block management */
-       chip->bbt_td = &bbt_main_descr;
-       chip->bbt_md = &bbt_mirror_descr;
-
-       /* skip the scan for now until we have OOB read and write support */
        chip->bbt_options |= NAND_BBT_USE_FLASH;
-       chip->options |= NAND_SKIP_BBTSCAN;
+       chip->bbt_options |= NAND_BBT_NO_OOB;
+
        chip->ecc.mode = NAND_ECC_HW_SYNDROME;
 
        /* no subpage writes on denali */
        chip->options |= NAND_NO_SUBPAGE_WRITE;
 
-       /*
-        * Denali Controller only support 15bit and 8bit ECC in MRST,
-        * so just let controller do 15bit ECC for MLC and 8bit ECC for
-        * SLC if possible.
-        * */
-       if (!nand_is_slc(chip) &&
-                       (mtd->oobsize > (denali->bbtskipbytes +
-                       ECC_15BITS * (mtd->writesize /
-                       ECC_SECTOR_SIZE)))) {
-               /* if MLC OOB size is large enough, use 15bit ECC*/
-               chip->ecc.strength = 15;
-               chip->ecc.bytes = ECC_15BITS;
-               iowrite32(15, denali->flash_reg + ECC_CORRECTION);
-       } else if (mtd->oobsize < (denali->bbtskipbytes +
-                       ECC_8BITS * (mtd->writesize /
-                       ECC_SECTOR_SIZE))) {
-               pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes");
-               goto failed_req_irq;
-       } else {
-               chip->ecc.strength = 8;
-               chip->ecc.bytes = ECC_8BITS;
-               iowrite32(8, denali->flash_reg + ECC_CORRECTION);
+       ret = denali_ecc_setup(mtd, chip, denali);
+       if (ret) {
+               dev_err(denali->dev, "Failed to setup ECC settings.\n");
+               goto disable_irq;
        }
 
+       dev_dbg(denali->dev,
+               "chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
+               chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
+
+       iowrite32(MAKE_ECC_CORRECTION(chip->ecc.strength, 1),
+                 denali->reg + ECC_CORRECTION);
+       iowrite32(mtd->erasesize / mtd->writesize,
+                 denali->reg + PAGES_PER_BLOCK);
+       iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0,
+                 denali->reg + DEVICE_WIDTH);
+       iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE);
+       iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE);
+
+       iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE);
+       iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE);
+       /* chip->ecc.steps is set by nand_scan_tail(); not available here */
+       iowrite32(mtd->writesize / chip->ecc.size,
+                 denali->reg + CFG_NUM_DATA_BLOCKS);
+
        mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
 
-       /* override the default read operations */
-       chip->ecc.size = ECC_SECTOR_SIZE;
+       if (chip->options & NAND_BUSWIDTH_16) {
+               chip->read_buf = denali_read_buf16;
+               chip->write_buf = denali_write_buf16;
+       } else {
+               chip->read_buf = denali_read_buf;
+               chip->write_buf = denali_write_buf;
+       }
+       chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
        chip->ecc.read_page = denali_read_page;
        chip->ecc.read_page_raw = denali_read_page_raw;
        chip->ecc.write_page = denali_write_page;
@@ -1624,21 +1411,34 @@ int denali_init(struct denali_nand_info *denali)
 
        ret = denali_multidev_fixup(denali);
        if (ret)
-               goto failed_req_irq;
+               goto disable_irq;
+
+       /*
+        * This buffer is DMA-mapped by denali_{read,write}_page_raw.  Do not
+        * use devm_kmalloc() because the memory allocated by devm_ does not
+        * guarantee DMA-safe alignment.
+        */
+       denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
+       if (!denali->buf) {
+               ret = -ENOMEM;
+               goto disable_irq;
+       }
 
        ret = nand_scan_tail(mtd);
        if (ret)
-               goto failed_req_irq;
+               goto free_buf;
 
        ret = mtd_device_register(mtd, NULL, 0);
        if (ret) {
                dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
-               goto failed_req_irq;
+               goto free_buf;
        }
        return 0;
 
-failed_req_irq:
-       denali_irq_cleanup(denali->irq, denali);
+free_buf:
+       kfree(denali->buf);
+disable_irq:
+       denali_disable_irq(denali);
 
        return ret;
 }
@@ -1648,16 +1448,9 @@ EXPORT_SYMBOL(denali_init);
 void denali_remove(struct denali_nand_info *denali)
 {
        struct mtd_info *mtd = nand_to_mtd(&denali->nand);
-       /*
-        * Pre-compute DMA buffer size to avoid any problems in case
-        * nand_release() ever changes in a way that mtd->writesize and
-        * mtd->oobsize are not reliable after this call.
-        */
-       int bufsize = mtd->writesize + mtd->oobsize;
 
        nand_release(mtd);
-       denali_irq_cleanup(denali->irq, denali);
-       dma_unmap_single(denali->dev, denali->buf.dma_buf, bufsize,
-                        DMA_BIDIRECTIONAL);
+       kfree(denali->buf);
+       denali_disable_irq(denali);
 }
 EXPORT_SYMBOL(denali_remove);
index ec00485..237cc70 100644 (file)
 #include <linux/mtd/nand.h>
 
 #define DEVICE_RESET                           0x0
-#define     DEVICE_RESET__BANK0                                0x0001
-#define     DEVICE_RESET__BANK1                                0x0002
-#define     DEVICE_RESET__BANK2                                0x0004
-#define     DEVICE_RESET__BANK3                                0x0008
+#define     DEVICE_RESET__BANK(bank)                   BIT(bank)
 
 #define TRANSFER_SPARE_REG                     0x10
-#define     TRANSFER_SPARE_REG__FLAG                   0x0001
+#define     TRANSFER_SPARE_REG__FLAG                   BIT(0)
 
 #define LOAD_WAIT_CNT                          0x20
-#define     LOAD_WAIT_CNT__VALUE                       0xffff
+#define     LOAD_WAIT_CNT__VALUE                       GENMASK(15, 0)
 
 #define PROGRAM_WAIT_CNT                       0x30
-#define     PROGRAM_WAIT_CNT__VALUE                    0xffff
+#define     PROGRAM_WAIT_CNT__VALUE                    GENMASK(15, 0)
 
 #define ERASE_WAIT_CNT                         0x40
-#define     ERASE_WAIT_CNT__VALUE                      0xffff
+#define     ERASE_WAIT_CNT__VALUE                      GENMASK(15, 0)
 
 #define INT_MON_CYCCNT                         0x50
-#define     INT_MON_CYCCNT__VALUE                      0xffff
+#define     INT_MON_CYCCNT__VALUE                      GENMASK(15, 0)
 
 #define RB_PIN_ENABLED                         0x60
-#define     RB_PIN_ENABLED__BANK0                      0x0001
-#define     RB_PIN_ENABLED__BANK1                      0x0002
-#define     RB_PIN_ENABLED__BANK2                      0x0004
-#define     RB_PIN_ENABLED__BANK3                      0x0008
+#define     RB_PIN_ENABLED__BANK(bank)                 BIT(bank)
 
 #define MULTIPLANE_OPERATION                   0x70
-#define     MULTIPLANE_OPERATION__FLAG                 0x0001
+#define     MULTIPLANE_OPERATION__FLAG                 BIT(0)
 
 #define MULTIPLANE_READ_ENABLE                 0x80
-#define     MULTIPLANE_READ_ENABLE__FLAG               0x0001
+#define     MULTIPLANE_READ_ENABLE__FLAG               BIT(0)
 
 #define COPYBACK_DISABLE                       0x90
-#define     COPYBACK_DISABLE__FLAG                     0x0001
+#define     COPYBACK_DISABLE__FLAG                     BIT(0)
 
 #define CACHE_WRITE_ENABLE                     0xa0
-#define     CACHE_WRITE_ENABLE__FLAG                   0x0001
+#define     CACHE_WRITE_ENABLE__FLAG                   BIT(0)
 
 #define CACHE_READ_ENABLE                      0xb0
-#define     CACHE_READ_ENABLE__FLAG                    0x0001
+#define     CACHE_READ_ENABLE__FLAG                    BIT(0)
 
 #define PREFETCH_MODE                          0xc0
-#define     PREFETCH_MODE__PREFETCH_EN                 0x0001
-#define     PREFETCH_MODE__PREFETCH_BURST_LENGTH       0xfff0
+#define     PREFETCH_MODE__PREFETCH_EN                 BIT(0)
+#define     PREFETCH_MODE__PREFETCH_BURST_LENGTH       GENMASK(15, 4)
 
 #define CHIP_ENABLE_DONT_CARE                  0xd0
-#define     CHIP_EN_DONT_CARE__FLAG                    0x01
+#define     CHIP_EN_DONT_CARE__FLAG                    BIT(0)
 
 #define ECC_ENABLE                             0xe0
-#define     ECC_ENABLE__FLAG                           0x0001
+#define     ECC_ENABLE__FLAG                           BIT(0)
 
 #define GLOBAL_INT_ENABLE                      0xf0
-#define     GLOBAL_INT_EN_FLAG                         0x01
+#define     GLOBAL_INT_EN_FLAG                         BIT(0)
 
-#define WE_2_RE                                        0x100
-#define     WE_2_RE__VALUE                             0x003f
+#define TWHR2_AND_WE_2_RE                      0x100
+#define     TWHR2_AND_WE_2_RE__WE_2_RE                 GENMASK(5, 0)
+#define     TWHR2_AND_WE_2_RE__TWHR2                   GENMASK(13, 8)
 
-#define ADDR_2_DATA                            0x110
-#define     ADDR_2_DATA__VALUE                         0x003f
+#define TCWAW_AND_ADDR_2_DATA                  0x110
+/* The width of ADDR_2_DATA is 6 bit for old IP, 7 bit for new IP */
+#define     TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA         GENMASK(6, 0)
+#define     TCWAW_AND_ADDR_2_DATA__TCWAW               GENMASK(13, 8)
 
 #define RE_2_WE                                        0x120
-#define     RE_2_WE__VALUE                             0x003f
+#define     RE_2_WE__VALUE                             GENMASK(5, 0)
 
 #define ACC_CLKS                               0x130
-#define     ACC_CLKS__VALUE                            0x000f
+#define     ACC_CLKS__VALUE                            GENMASK(3, 0)
 
 #define NUMBER_OF_PLANES                       0x140
-#define     NUMBER_OF_PLANES__VALUE                    0x0007
+#define     NUMBER_OF_PLANES__VALUE                    GENMASK(2, 0)
 
 #define PAGES_PER_BLOCK                                0x150
-#define     PAGES_PER_BLOCK__VALUE                     0xffff
+#define     PAGES_PER_BLOCK__VALUE                     GENMASK(15, 0)
 
 #define DEVICE_WIDTH                           0x160
-#define     DEVICE_WIDTH__VALUE                                0x0003
+#define     DEVICE_WIDTH__VALUE                                GENMASK(1, 0)
 
 #define DEVICE_MAIN_AREA_SIZE                  0x170
-#define     DEVICE_MAIN_AREA_SIZE__VALUE               0xffff
+#define     DEVICE_MAIN_AREA_SIZE__VALUE               GENMASK(15, 0)
 
 #define DEVICE_SPARE_AREA_SIZE                 0x180
-#define     DEVICE_SPARE_AREA_SIZE__VALUE              0xffff
+#define     DEVICE_SPARE_AREA_SIZE__VALUE              GENMASK(15, 0)
 
 #define TWO_ROW_ADDR_CYCLES                    0x190
-#define     TWO_ROW_ADDR_CYCLES__FLAG                  0x0001
+#define     TWO_ROW_ADDR_CYCLES__FLAG                  BIT(0)
 
 #define MULTIPLANE_ADDR_RESTRICT               0x1a0
-#define     MULTIPLANE_ADDR_RESTRICT__FLAG             0x0001
+#define     MULTIPLANE_ADDR_RESTRICT__FLAG             BIT(0)
 
 #define ECC_CORRECTION                         0x1b0
-#define     ECC_CORRECTION__VALUE                      0x001f
+#define     ECC_CORRECTION__VALUE                      GENMASK(4, 0)
+#define     ECC_CORRECTION__ERASE_THRESHOLD            GENMASK(31, 16)
+#define     MAKE_ECC_CORRECTION(val, thresh)           \
+                       (((val) & (ECC_CORRECTION__VALUE)) | \
+                       (((thresh) << 16) & (ECC_CORRECTION__ERASE_THRESHOLD)))
 
 #define READ_MODE                              0x1c0
-#define     READ_MODE__VALUE                           0x000f
+#define     READ_MODE__VALUE                           GENMASK(3, 0)
 
 #define WRITE_MODE                             0x1d0
-#define     WRITE_MODE__VALUE                          0x000f
+#define     WRITE_MODE__VALUE                          GENMASK(3, 0)
 
 #define COPYBACK_MODE                          0x1e0
-#define     COPYBACK_MODE__VALUE                       0x000f
+#define     COPYBACK_MODE__VALUE                       GENMASK(3, 0)
 
 #define RDWR_EN_LO_CNT                         0x1f0
-#define     RDWR_EN_LO_CNT__VALUE                      0x001f
+#define     RDWR_EN_LO_CNT__VALUE                      GENMASK(4, 0)
 
 #define RDWR_EN_HI_CNT                         0x200
-#define     RDWR_EN_HI_CNT__VALUE                      0x001f
+#define     RDWR_EN_HI_CNT__VALUE                      GENMASK(4, 0)
 
 #define MAX_RD_DELAY                           0x210
-#define     MAX_RD_DELAY__VALUE                                0x000f
+#define     MAX_RD_DELAY__VALUE                                GENMASK(3, 0)
 
 #define CS_SETUP_CNT                           0x220
-#define     CS_SETUP_CNT__VALUE                                0x001f
+#define     CS_SETUP_CNT__VALUE                                GENMASK(4, 0)
+#define     CS_SETUP_CNT__TWB                          GENMASK(17, 12)
 
 #define SPARE_AREA_SKIP_BYTES                  0x230
-#define     SPARE_AREA_SKIP_BYTES__VALUE               0x003f
+#define     SPARE_AREA_SKIP_BYTES__VALUE               GENMASK(5, 0)
 
 #define SPARE_AREA_MARKER                      0x240
-#define     SPARE_AREA_MARKER__VALUE                   0xffff
+#define     SPARE_AREA_MARKER__VALUE                   GENMASK(15, 0)
 
 #define DEVICES_CONNECTED                      0x250
-#define     DEVICES_CONNECTED__VALUE                   0x0007
+#define     DEVICES_CONNECTED__VALUE                   GENMASK(2, 0)
 
 #define DIE_MASK                               0x260
-#define     DIE_MASK__VALUE                            0x00ff
+#define     DIE_MASK__VALUE                            GENMASK(7, 0)
 
 #define FIRST_BLOCK_OF_NEXT_PLANE              0x270
-#define     FIRST_BLOCK_OF_NEXT_PLANE__VALUE           0xffff
+#define     FIRST_BLOCK_OF_NEXT_PLANE__VALUE           GENMASK(15, 0)
 
 #define WRITE_PROTECT                          0x280
-#define     WRITE_PROTECT__FLAG                                0x0001
+#define     WRITE_PROTECT__FLAG                                BIT(0)
 
 #define RE_2_RE                                        0x290
-#define     RE_2_RE__VALUE                             0x003f
+#define     RE_2_RE__VALUE                             GENMASK(5, 0)
 
 #define MANUFACTURER_ID                                0x300
-#define     MANUFACTURER_ID__VALUE                     0x00ff
+#define     MANUFACTURER_ID__VALUE                     GENMASK(7, 0)
 
 #define DEVICE_ID                              0x310
-#define     DEVICE_ID__VALUE                           0x00ff
+#define     DEVICE_ID__VALUE                           GENMASK(7, 0)
 
 #define DEVICE_PARAM_0                         0x320
-#define     DEVICE_PARAM_0__VALUE                      0x00ff
+#define     DEVICE_PARAM_0__VALUE                      GENMASK(7, 0)
 
 #define DEVICE_PARAM_1                         0x330
-#define     DEVICE_PARAM_1__VALUE                      0x00ff
+#define     DEVICE_PARAM_1__VALUE                      GENMASK(7, 0)
 
 #define DEVICE_PARAM_2                         0x340
-#define     DEVICE_PARAM_2__VALUE                      0x00ff
+#define     DEVICE_PARAM_2__VALUE                      GENMASK(7, 0)
 
 #define LOGICAL_PAGE_DATA_SIZE                 0x350
-#define     LOGICAL_PAGE_DATA_SIZE__VALUE              0xffff
+#define     LOGICAL_PAGE_DATA_SIZE__VALUE              GENMASK(15, 0)
 
 #define LOGICAL_PAGE_SPARE_SIZE                        0x360
-#define     LOGICAL_PAGE_SPARE_SIZE__VALUE             0xffff
+#define     LOGICAL_PAGE_SPARE_SIZE__VALUE             GENMASK(15, 0)
 
 #define REVISION                               0x370
-#define     REVISION__VALUE                            0xffff
+#define     REVISION__VALUE                            GENMASK(15, 0)
 
 #define ONFI_DEVICE_FEATURES                   0x380
-#define     ONFI_DEVICE_FEATURES__VALUE                        0x003f
+#define     ONFI_DEVICE_FEATURES__VALUE                        GENMASK(5, 0)
 
 #define ONFI_OPTIONAL_COMMANDS                 0x390
-#define     ONFI_OPTIONAL_COMMANDS__VALUE              0x003f
+#define     ONFI_OPTIONAL_COMMANDS__VALUE              GENMASK(5, 0)
 
 #define ONFI_TIMING_MODE                       0x3a0
-#define     ONFI_TIMING_MODE__VALUE                    0x003f
+#define     ONFI_TIMING_MODE__VALUE                    GENMASK(5, 0)
 
 #define ONFI_PGM_CACHE_TIMING_MODE             0x3b0
-#define     ONFI_PGM_CACHE_TIMING_MODE__VALUE          0x003f
+#define     ONFI_PGM_CACHE_TIMING_MODE__VALUE          GENMASK(5, 0)
 
 #define ONFI_DEVICE_NO_OF_LUNS                 0x3c0
-#define     ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS         0x00ff
-#define     ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE                0x0100
+#define     ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS         GENMASK(7, 0)
+#define     ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE                BIT(8)
 
 #define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L     0x3d0
-#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE  0xffff
+#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE  GENMASK(15, 0)
 
 #define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U     0x3e0
-#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE  0xffff
-
-#define FEATURES                                       0x3f0
-#define     FEATURES__N_BANKS                          0x0003
-#define     FEATURES__ECC_MAX_ERR                      0x003c
-#define     FEATURES__DMA                              0x0040
-#define     FEATURES__CMD_DMA                          0x0080
-#define     FEATURES__PARTITION                                0x0100
-#define     FEATURES__XDMA_SIDEBAND                    0x0200
-#define     FEATURES__GPREG                            0x0400
-#define     FEATURES__INDEX_ADDR                       0x0800
+#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE  GENMASK(15, 0)
+
+#define FEATURES                               0x3f0
+#define     FEATURES__N_BANKS                          GENMASK(1, 0)
+#define     FEATURES__ECC_MAX_ERR                      GENMASK(5, 2)
+#define     FEATURES__DMA                              BIT(6)
+#define     FEATURES__CMD_DMA                          BIT(7)
+#define     FEATURES__PARTITION                                BIT(8)
+#define     FEATURES__XDMA_SIDEBAND                    BIT(9)
+#define     FEATURES__GPREG                            BIT(10)
+#define     FEATURES__INDEX_ADDR                       BIT(11)
 
 #define TRANSFER_MODE                          0x400
-#define     TRANSFER_MODE__VALUE                       0x0003
+#define     TRANSFER_MODE__VALUE                       GENMASK(1, 0)
 
-#define INTR_STATUS(__bank)    (0x410 + ((__bank) * 0x50))
-#define INTR_EN(__bank)                (0x420 + ((__bank) * 0x50))
+#define INTR_STATUS(bank)                      (0x410 + (bank) * 0x50)
+#define INTR_EN(bank)                          (0x420 + (bank) * 0x50)
 /* bit[1:0] is used differently depending on IP version */
-#define     INTR__ECC_UNCOR_ERR                                0x0001  /* new IP */
-#define     INTR__ECC_TRANSACTION_DONE                 0x0001  /* old IP */
-#define     INTR__ECC_ERR                              0x0002  /* old IP */
-#define     INTR__DMA_CMD_COMP                         0x0004
-#define     INTR__TIME_OUT                             0x0008
-#define     INTR__PROGRAM_FAIL                         0x0010
-#define     INTR__ERASE_FAIL                           0x0020
-#define     INTR__LOAD_COMP                            0x0040
-#define     INTR__PROGRAM_COMP                         0x0080
-#define     INTR__ERASE_COMP                           0x0100
-#define     INTR__PIPE_CPYBCK_CMD_COMP                 0x0200
-#define     INTR__LOCKED_BLK                           0x0400
-#define     INTR__UNSUP_CMD                            0x0800
-#define     INTR__INT_ACT                              0x1000
-#define     INTR__RST_COMP                             0x2000
-#define     INTR__PIPE_CMD_ERR                         0x4000
-#define     INTR__PAGE_XFER_INC                                0x8000
-
-#define PAGE_CNT(__bank)       (0x430 + ((__bank) * 0x50))
-#define ERR_PAGE_ADDR(__bank)  (0x440 + ((__bank) * 0x50))
-#define ERR_BLOCK_ADDR(__bank) (0x450 + ((__bank) * 0x50))
+#define     INTR__ECC_UNCOR_ERR                                BIT(0)  /* new IP */
+#define     INTR__ECC_TRANSACTION_DONE                 BIT(0)  /* old IP */
+#define     INTR__ECC_ERR                              BIT(1)  /* old IP */
+#define     INTR__DMA_CMD_COMP                         BIT(2)
+#define     INTR__TIME_OUT                             BIT(3)
+#define     INTR__PROGRAM_FAIL                         BIT(4)
+#define     INTR__ERASE_FAIL                           BIT(5)
+#define     INTR__LOAD_COMP                            BIT(6)
+#define     INTR__PROGRAM_COMP                         BIT(7)
+#define     INTR__ERASE_COMP                           BIT(8)
+#define     INTR__PIPE_CPYBCK_CMD_COMP                 BIT(9)
+#define     INTR__LOCKED_BLK                           BIT(10)
+#define     INTR__UNSUP_CMD                            BIT(11)
+#define     INTR__INT_ACT                              BIT(12)
+#define     INTR__RST_COMP                             BIT(13)
+#define     INTR__PIPE_CMD_ERR                         BIT(14)
+#define     INTR__PAGE_XFER_INC                                BIT(15)
+#define     INTR__ERASED_PAGE                          BIT(16)
+
+#define PAGE_CNT(bank)                         (0x430 + (bank) * 0x50)
+#define ERR_PAGE_ADDR(bank)                    (0x440 + (bank) * 0x50)
+#define ERR_BLOCK_ADDR(bank)                   (0x450 + (bank) * 0x50)
 
 #define ECC_THRESHOLD                          0x600
-#define     ECC_THRESHOLD__VALUE                       0x03ff
+#define     ECC_THRESHOLD__VALUE                       GENMASK(9, 0)
 
 #define ECC_ERROR_BLOCK_ADDRESS                        0x610
-#define     ECC_ERROR_BLOCK_ADDRESS__VALUE             0xffff
+#define     ECC_ERROR_BLOCK_ADDRESS__VALUE             GENMASK(15, 0)
 
 #define ECC_ERROR_PAGE_ADDRESS                 0x620
-#define     ECC_ERROR_PAGE_ADDRESS__VALUE              0x0fff
-#define     ECC_ERROR_PAGE_ADDRESS__BANK               0xf000
+#define     ECC_ERROR_PAGE_ADDRESS__VALUE              GENMASK(11, 0)
+#define     ECC_ERROR_PAGE_ADDRESS__BANK               GENMASK(15, 12)
 
 #define ECC_ERROR_ADDRESS                      0x630
-#define     ECC_ERROR_ADDRESS__OFFSET                  0x0fff
-#define     ECC_ERROR_ADDRESS__SECTOR_NR               0xf000
+#define     ECC_ERROR_ADDRESS__OFFSET                  GENMASK(11, 0)
+#define     ECC_ERROR_ADDRESS__SECTOR_NR               GENMASK(15, 12)
 
 #define ERR_CORRECTION_INFO                    0x640
-#define     ERR_CORRECTION_INFO__BYTEMASK              0x00ff
-#define     ERR_CORRECTION_INFO__DEVICE_NR             0x0f00
-#define     ERR_CORRECTION_INFO__ERROR_TYPE            0x4000
-#define     ERR_CORRECTION_INFO__LAST_ERR_INFO         0x8000
+#define     ERR_CORRECTION_INFO__BYTEMASK              GENMASK(7, 0)
+#define     ERR_CORRECTION_INFO__DEVICE_NR             GENMASK(11, 8)
+#define     ERR_CORRECTION_INFO__ERROR_TYPE            BIT(14)
+#define     ERR_CORRECTION_INFO__LAST_ERR_INFO         BIT(15)
 
 #define ECC_COR_INFO(bank)                     (0x650 + (bank) / 2 * 0x10)
 #define     ECC_COR_INFO__SHIFT(bank)                  ((bank) % 2 * 8)
-#define     ECC_COR_INFO__MAX_ERRORS                   0x007f
-#define     ECC_COR_INFO__UNCOR_ERR                    0x0080
+#define     ECC_COR_INFO__MAX_ERRORS                   GENMASK(6, 0)
+#define     ECC_COR_INFO__UNCOR_ERR                    BIT(7)
+
+#define CFG_DATA_BLOCK_SIZE                    0x6b0
+
+#define CFG_LAST_DATA_BLOCK_SIZE               0x6c0
+
+#define CFG_NUM_DATA_BLOCKS                    0x6d0
+
+#define CFG_META_DATA_SIZE                     0x6e0
 
 #define DMA_ENABLE                             0x700
-#define     DMA_ENABLE__FLAG                           0x0001
+#define     DMA_ENABLE__FLAG                           BIT(0)
 
 #define IGNORE_ECC_DONE                                0x710
-#define     IGNORE_ECC_DONE__FLAG                      0x0001
+#define     IGNORE_ECC_DONE__FLAG                      BIT(0)
 
 #define DMA_INTR                               0x720
 #define DMA_INTR_EN                            0x730
-#define     DMA_INTR__TARGET_ERROR                     0x0001
-#define     DMA_INTR__DESC_COMP_CHANNEL0               0x0002
-#define     DMA_INTR__DESC_COMP_CHANNEL1               0x0004
-#define     DMA_INTR__DESC_COMP_CHANNEL2               0x0008
-#define     DMA_INTR__DESC_COMP_CHANNEL3               0x0010
-#define     DMA_INTR__MEMCOPY_DESC_COMP                        0x0020
+#define     DMA_INTR__TARGET_ERROR                     BIT(0)
+#define     DMA_INTR__DESC_COMP_CHANNEL0               BIT(1)
+#define     DMA_INTR__DESC_COMP_CHANNEL1               BIT(2)
+#define     DMA_INTR__DESC_COMP_CHANNEL2               BIT(3)
+#define     DMA_INTR__DESC_COMP_CHANNEL3               BIT(4)
+#define     DMA_INTR__MEMCOPY_DESC_COMP                        BIT(5)
 
 #define TARGET_ERR_ADDR_LO                     0x740
-#define     TARGET_ERR_ADDR_LO__VALUE                  0xffff
+#define     TARGET_ERR_ADDR_LO__VALUE                  GENMASK(15, 0)
 
 #define TARGET_ERR_ADDR_HI                     0x750
-#define     TARGET_ERR_ADDR_HI__VALUE                  0xffff
+#define     TARGET_ERR_ADDR_HI__VALUE                  GENMASK(15, 0)
 
 #define CHNL_ACTIVE                            0x760
-#define     CHNL_ACTIVE__CHANNEL0                      0x0001
-#define     CHNL_ACTIVE__CHANNEL1                      0x0002
-#define     CHNL_ACTIVE__CHANNEL2                      0x0004
-#define     CHNL_ACTIVE__CHANNEL3                      0x0008
-
-#define FAIL 1                  /*failed flag*/
-#define PASS 0                  /*success flag*/
-
-#define CLK_X  5
-#define CLK_MULTI 4
-
-#define ONFI_BLOOM_TIME         1
-#define MODE5_WORKAROUND        0
-
-
-#define MODE_00    0x00000000
-#define MODE_01    0x04000000
-#define MODE_10    0x08000000
-#define MODE_11    0x0C000000
-
-#define ECC_SECTOR_SIZE     512
-
-struct nand_buf {
-       int head;
-       int tail;
-       uint8_t *buf;
-       dma_addr_t dma_buf;
-};
-
-#define INTEL_CE4100   1
-#define INTEL_MRST     2
-#define DT             3
+#define     CHNL_ACTIVE__CHANNEL0                      BIT(0)
+#define     CHNL_ACTIVE__CHANNEL1                      BIT(1)
+#define     CHNL_ACTIVE__CHANNEL2                      BIT(2)
+#define     CHNL_ACTIVE__CHANNEL3                      BIT(3)
 
 struct denali_nand_info {
        struct nand_chip nand;
-       int flash_bank; /* currently selected chip */
-       int status;
-       int platform;
-       struct nand_buf buf;
+       unsigned long clk_x_rate;       /* bus interface clock rate */
+       int active_bank;                /* currently selected bank */
        struct device *dev;
-       int total_used_banks;
-       int page;
-       void __iomem *flash_reg;        /* Register Interface */
-       void __iomem *flash_mem;        /* Host Data/Command Interface */
+       void __iomem *reg;              /* Register Interface */
+       void __iomem *host;             /* Host Data/Command Interface */
 
        /* elements used by ISR */
        struct completion complete;
        spinlock_t irq_lock;
+       uint32_t irq_mask;
        uint32_t irq_status;
        int irq;
 
-       int devnum;     /* represent how many nands connected */
-       int bbtskipbytes;
+       void *buf;
+       dma_addr_t dma_addr;
+       int dma_avail;
+       int devs_per_cs;                /* devices connected in parallel */
+       int oob_skip_bytes;
        int max_banks;
        unsigned int revision;
        unsigned int caps;
+       const struct nand_ecc_caps *ecc_caps;
 };
 
 #define DENALI_CAP_HW_ECC_FIXUP                        BIT(0)
 #define DENALI_CAP_DMA_64BIT                   BIT(1)
 
+int denali_calc_ecc_bytes(int step_size, int strength);
 extern int denali_init(struct denali_nand_info *denali);
 extern void denali_remove(struct denali_nand_info *denali);
 
index df9ef36..47f398e 100644 (file)
@@ -32,10 +32,31 @@ struct denali_dt {
 struct denali_dt_data {
        unsigned int revision;
        unsigned int caps;
+       const struct nand_ecc_caps *ecc_caps;
 };
 
+NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
+                    512, 8, 15);
 static const struct denali_dt_data denali_socfpga_data = {
        .caps = DENALI_CAP_HW_ECC_FIXUP,
+       .ecc_caps = &denali_socfpga_ecc_caps,
+};
+
+NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
+                    1024, 8, 16, 24);
+static const struct denali_dt_data denali_uniphier_v5a_data = {
+       .caps = DENALI_CAP_HW_ECC_FIXUP |
+               DENALI_CAP_DMA_64BIT,
+       .ecc_caps = &denali_uniphier_v5a_ecc_caps,
+};
+
+NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,
+                    1024, 8, 16);
+static const struct denali_dt_data denali_uniphier_v5b_data = {
+       .revision = 0x0501,
+       .caps = DENALI_CAP_HW_ECC_FIXUP |
+               DENALI_CAP_DMA_64BIT,
+       .ecc_caps = &denali_uniphier_v5b_ecc_caps,
 };
 
 static const struct of_device_id denali_nand_dt_ids[] = {
@@ -43,13 +64,21 @@ static const struct of_device_id denali_nand_dt_ids[] = {
                .compatible = "altr,socfpga-denali-nand",
                .data = &denali_socfpga_data,
        },
+       {
+               .compatible = "socionext,uniphier-denali-nand-v5a",
+               .data = &denali_uniphier_v5a_data,
+       },
+       {
+               .compatible = "socionext,uniphier-denali-nand-v5b",
+               .data = &denali_uniphier_v5b_data,
+       },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
 
 static int denali_dt_probe(struct platform_device *pdev)
 {
-       struct resource *denali_reg, *nand_data;
+       struct resource *res;
        struct denali_dt *dt;
        const struct denali_dt_data *data;
        struct denali_nand_info *denali;
@@ -64,9 +93,9 @@ static int denali_dt_probe(struct platform_device *pdev)
        if (data) {
                denali->revision = data->revision;
                denali->caps = data->caps;
+               denali->ecc_caps = data->ecc_caps;
        }
 
-       denali->platform = DT;
        denali->dev = &pdev->dev;
        denali->irq = platform_get_irq(pdev, 0);
        if (denali->irq < 0) {
@@ -74,17 +103,15 @@ static int denali_dt_probe(struct platform_device *pdev)
                return denali->irq;
        }
 
-       denali_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                                 "denali_reg");
-       denali->flash_reg = devm_ioremap_resource(&pdev->dev, denali_reg);
-       if (IS_ERR(denali->flash_reg))
-               return PTR_ERR(denali->flash_reg);
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
+       denali->reg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(denali->reg))
+               return PTR_ERR(denali->reg);
 
-       nand_data = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                                "nand_data");
-       denali->flash_mem = devm_ioremap_resource(&pdev->dev, nand_data);
-       if (IS_ERR(denali->flash_mem))
-               return PTR_ERR(denali->flash_mem);
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
+       denali->host = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(denali->host))
+               return PTR_ERR(denali->host);
 
        dt->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(dt->clk)) {
@@ -93,6 +120,8 @@ static int denali_dt_probe(struct platform_device *pdev)
        }
        clk_prepare_enable(dt->clk);
 
+       denali->clk_x_rate = clk_get_rate(dt->clk);
+
        ret = denali_init(denali);
        if (ret)
                goto out_disable_clk;
index ac84323..81370c7 100644 (file)
@@ -19,6 +19,9 @@
 
 #define DENALI_NAND_NAME    "denali-nand-pci"
 
+#define INTEL_CE4100   1
+#define INTEL_MRST     2
+
 /* List of platforms this NAND controller has be integrated into */
 static const struct pci_device_id denali_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
@@ -27,6 +30,8 @@ static const struct pci_device_id denali_pci_ids[] = {
 };
 MODULE_DEVICE_TABLE(pci, denali_pci_ids);
 
+NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15);
+
 static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        int ret;
@@ -45,13 +50,11 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        }
 
        if (id->driver_data == INTEL_CE4100) {
-               denali->platform = INTEL_CE4100;
                mem_base = pci_resource_start(dev, 0);
                mem_len = pci_resource_len(dev, 1);
                csr_base = pci_resource_start(dev, 1);
                csr_len = pci_resource_len(dev, 1);
        } else {
-               denali->platform = INTEL_MRST;
                csr_base = pci_resource_start(dev, 0);
                csr_len = pci_resource_len(dev, 0);
                mem_base = pci_resource_start(dev, 1);
@@ -65,6 +68,9 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        pci_set_master(dev);
        denali->dev = &dev->dev;
        denali->irq = dev->irq;
+       denali->ecc_caps = &denali_pci_ecc_caps;
+       denali->nand.ecc.options |= NAND_ECC_MAXIMIZE;
+       denali->clk_x_rate = 200000000;         /* 200 MHz */
 
        ret = pci_request_regions(dev, DENALI_NAND_NAME);
        if (ret) {
@@ -72,14 +78,14 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
                return ret;
        }
 
-       denali->flash_reg = ioremap_nocache(csr_base, csr_len);
-       if (!denali->flash_reg) {
+       denali->reg = ioremap_nocache(csr_base, csr_len);
+       if (!denali->reg) {
                dev_err(&dev->dev, "Spectra: Unable to remap memory region\n");
                return -ENOMEM;
        }
 
-       denali->flash_mem = ioremap_nocache(mem_base, mem_len);
-       if (!denali->flash_mem) {
+       denali->host = ioremap_nocache(mem_base, mem_len);
+       if (!denali->host) {
                dev_err(&dev->dev, "Spectra: ioremap_nocache failed!");
                ret = -ENOMEM;
                goto failed_remap_reg;
@@ -94,9 +100,9 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        return 0;
 
 failed_remap_mem:
-       iounmap(denali->flash_mem);
+       iounmap(denali->host);
 failed_remap_reg:
-       iounmap(denali->flash_reg);
+       iounmap(denali->reg);
        return ret;
 }
 
@@ -106,8 +112,8 @@ static void denali_pci_remove(struct pci_dev *dev)
        struct denali_nand_info *denali = pci_get_drvdata(dev);
 
        denali_remove(denali);
-       iounmap(denali->flash_reg);
-       iounmap(denali->flash_mem);
+       iounmap(denali->reg);
+       iounmap(denali->host);
 }
 
 static struct pci_driver denali_pci_driver = {
index 7af2a3c..a27a84f 100644 (file)
@@ -1260,6 +1260,8 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
        nand->read_buf = docg4_read_buf;
        nand->write_buf = docg4_write_buf16;
        nand->erase = docg4_erase_block;
+       nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
+       nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
        nand->ecc.read_page = docg4_read_page;
        nand->ecc.write_page = docg4_write_page;
        nand->ecc.read_page_raw = docg4_read_page_raw;
index 113f76e..b9ac16f 100644 (file)
@@ -775,6 +775,8 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
        chip->select_chip = fsl_elbc_select_chip;
        chip->cmdfunc = fsl_elbc_cmdfunc;
        chip->waitfunc = fsl_elbc_wait;
+       chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+       chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
 
        chip->bbt_td = &bbt_main_descr;
        chip->bbt_md = &bbt_mirror_descr;
index d1570f5..59408ec 100644 (file)
@@ -171,34 +171,6 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
                ifc_nand_ctrl->index += mtd->writesize;
 }
 
-static int is_blank(struct mtd_info *mtd, unsigned int bufnum)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
-       u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
-       u32 __iomem *mainarea = (u32 __iomem *)addr;
-       u8 __iomem *oob = addr + mtd->writesize;
-       struct mtd_oob_region oobregion = { };
-       int i, section = 0;
-
-       for (i = 0; i < mtd->writesize / 4; i++) {
-               if (__raw_readl(&mainarea[i]) != 0xffffffff)
-                       return 0;
-       }
-
-       mtd_ooblayout_ecc(mtd, section++, &oobregion);
-       while (oobregion.length) {
-               for (i = 0; i < oobregion.length; i++) {
-                       if (__raw_readb(&oob[oobregion.offset + i]) != 0xff)
-                               return 0;
-               }
-
-               mtd_ooblayout_ecc(mtd, section++, &oobregion);
-       }
-
-       return 1;
-}
-
 /* returns nonzero if entire page is blank */
 static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
                          u32 *eccstat, unsigned int bufnum)
@@ -274,16 +246,14 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
                        if (errors == 15) {
                                /*
                                 * Uncorrectable error.
-                                * OK only if the whole page is blank.
+                                * We'll check for blank pages later.
                                 *
                                 * We disable ECCER reporting due to...
                                 * erratum IFC-A002770 -- so report it now if we
                                 * see an uncorrectable error in ECCSTAT.
                                 */
-                               if (!is_blank(mtd, bufnum))
-                                       ctrl->nand_stat |=
-                                               IFC_NAND_EVTER_STAT_ECCER;
-                               break;
+                               ctrl->nand_stat |= IFC_NAND_EVTER_STAT_ECCER;
+                               continue;
                        }
 
                        mtd->ecc_stats.corrected += errors;
@@ -678,6 +648,39 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
        return nand_fsr | NAND_STATUS_WP;
 }
 
+/*
+ * The controller does not check for bitflips in erased pages,
+ * therefore software must check instead.
+ */
+static int check_erased_page(struct nand_chip *chip, u8 *buf)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       u8 *ecc = chip->oob_poi;
+       const int ecc_size = chip->ecc.bytes;
+       const int pkt_size = chip->ecc.size;
+       int i, res, bitflips = 0;
+       struct mtd_oob_region oobregion = { };
+
+       mtd_ooblayout_ecc(mtd, 0, &oobregion);
+       ecc += oobregion.offset;
+
+       for (i = 0; i < chip->ecc.steps; ++i) {
+               res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
+                                                 NULL, 0,
+                                                 chip->ecc.strength);
+               if (res < 0)
+                       mtd->ecc_stats.failed++;
+               else
+                       mtd->ecc_stats.corrected += res;
+
+               bitflips = max(res, bitflips);
+               buf += pkt_size;
+               ecc += ecc_size;
+       }
+
+       return bitflips;
+}
+
 static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                             uint8_t *buf, int oob_required, int page)
 {
@@ -689,8 +692,12 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        if (oob_required)
                fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
 
-       if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER)
-               dev_err(priv->dev, "NAND Flash ECC Uncorrectable Error\n");
+       if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) {
+               if (!oob_required)
+                       fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+               return check_erased_page(chip, buf);
+       }
 
        if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
                mtd->ecc_stats.failed++;
@@ -831,6 +838,8 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
        chip->select_chip = fsl_ifc_select_chip;
        chip->cmdfunc = fsl_ifc_cmdfunc;
        chip->waitfunc = fsl_ifc_wait;
+       chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+       chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
 
        chip->bbt_td = &bbt_main_descr;
        chip->bbt_md = &bbt_mirror_descr;
@@ -904,7 +913,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
                chip->ecc.algo = NAND_ECC_HAMMING;
        }
 
-       if (ctrl->version == FSL_IFC_VERSION_1_1_0)
+       if (ctrl->version >= FSL_IFC_VERSION_1_1_0)
                fsl_ifc_sram_init(priv);
 
        return 0;
index cea50d2..9d8b051 100644 (file)
@@ -302,25 +302,13 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
  * This routine initializes timing parameters related to NAND memory access in
  * FSMC registers
  */
-static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
-                          uint32_t busw, struct fsmc_nand_timings *timings)
+static void fsmc_nand_setup(struct fsmc_nand_data *host,
+                           struct fsmc_nand_timings *tims)
 {
        uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
        uint32_t tclr, tar, thiz, thold, twait, tset;
-       struct fsmc_nand_timings *tims;
-       struct fsmc_nand_timings default_timings = {
-               .tclr   = FSMC_TCLR_1,
-               .tar    = FSMC_TAR_1,
-               .thiz   = FSMC_THIZ_1,
-               .thold  = FSMC_THOLD_4,
-               .twait  = FSMC_TWAIT_6,
-               .tset   = FSMC_TSET_0,
-       };
-
-       if (timings)
-               tims = timings;
-       else
-               tims = &default_timings;
+       unsigned int bank = host->bank;
+       void __iomem *regs = host->regs_va;
 
        tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
        tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
@@ -329,7 +317,7 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
        twait = (tims->twait & FSMC_TWAIT_MASK) << FSMC_TWAIT_SHIFT;
        tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
 
-       if (busw)
+       if (host->nand.options & NAND_BUSWIDTH_16)
                writel_relaxed(value | FSMC_DEVWID_16,
                                FSMC_NAND_REG(regs, bank, PC));
        else
@@ -344,6 +332,87 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
                        FSMC_NAND_REG(regs, bank, ATTRIB));
 }
 
+static int fsmc_calc_timings(struct fsmc_nand_data *host,
+                            const struct nand_sdr_timings *sdrt,
+                            struct fsmc_nand_timings *tims)
+{
+       unsigned long hclk = clk_get_rate(host->clk);
+       unsigned long hclkn = NSEC_PER_SEC / hclk;
+       uint32_t thiz, thold, twait, tset;
+
+       if (sdrt->tRC_min < 30000)
+               return -EOPNOTSUPP;
+
+       tims->tar = DIV_ROUND_UP(sdrt->tAR_min / 1000, hclkn) - 1;
+       if (tims->tar > FSMC_TAR_MASK)
+               tims->tar = FSMC_TAR_MASK;
+       tims->tclr = DIV_ROUND_UP(sdrt->tCLR_min / 1000, hclkn) - 1;
+       if (tims->tclr > FSMC_TCLR_MASK)
+               tims->tclr = FSMC_TCLR_MASK;
+
+       thiz = sdrt->tCS_min - sdrt->tWP_min;
+       tims->thiz = DIV_ROUND_UP(thiz / 1000, hclkn);
+
+       thold = sdrt->tDH_min;
+       if (thold < sdrt->tCH_min)
+               thold = sdrt->tCH_min;
+       if (thold < sdrt->tCLH_min)
+               thold = sdrt->tCLH_min;
+       if (thold < sdrt->tWH_min)
+               thold = sdrt->tWH_min;
+       if (thold < sdrt->tALH_min)
+               thold = sdrt->tALH_min;
+       if (thold < sdrt->tREH_min)
+               thold = sdrt->tREH_min;
+       tims->thold = DIV_ROUND_UP(thold / 1000, hclkn);
+       if (tims->thold == 0)
+               tims->thold = 1;
+       else if (tims->thold > FSMC_THOLD_MASK)
+               tims->thold = FSMC_THOLD_MASK;
+
+       twait = max(sdrt->tRP_min, sdrt->tWP_min);
+       tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
+       if (tims->twait == 0)
+               tims->twait = 1;
+       else if (tims->twait > FSMC_TWAIT_MASK)
+               tims->twait = FSMC_TWAIT_MASK;
+
+       tset = max(sdrt->tCS_min - sdrt->tWP_min,
+                  sdrt->tCEA_max - sdrt->tREA_max);
+       tims->tset = DIV_ROUND_UP(tset / 1000, hclkn) - 1;
+       if (tims->tset == 0)
+               tims->tset = 1;
+       else if (tims->tset > FSMC_TSET_MASK)
+               tims->tset = FSMC_TSET_MASK;
+
+       return 0;
+}
+
+static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
+                                    const struct nand_data_interface *conf)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct fsmc_nand_data *host = nand_get_controller_data(nand);
+       struct fsmc_nand_timings tims;
+       const struct nand_sdr_timings *sdrt;
+       int ret;
+
+       sdrt = nand_get_sdr_timings(conf);
+       if (IS_ERR(sdrt))
+               return PTR_ERR(sdrt);
+
+       ret = fsmc_calc_timings(host, sdrt, &tims);
+       if (ret)
+               return ret;
+
+       if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+               return 0;
+
+       fsmc_nand_setup(host, &tims);
+
+       return 0;
+}
+
 /*
  * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
  */
@@ -796,10 +865,8 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
                return -ENOMEM;
        ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings,
                                                sizeof(*host->dev_timings));
-       if (ret) {
-               dev_info(&pdev->dev, "No timings in dts specified, using default timings!\n");
+       if (ret)
                host->dev_timings = NULL;
-       }
 
        /* Set default NAND bank to 0 */
        host->bank = 0;
@@ -933,9 +1000,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
                break;
        }
 
-       fsmc_nand_setup(host->regs_va, host->bank,
-                       nand->options & NAND_BUSWIDTH_16,
-                       host->dev_timings);
+       if (host->dev_timings)
+               fsmc_nand_setup(host, host->dev_timings);
+       else
+               nand->setup_data_interface = fsmc_setup_data_interface;
 
        if (AMBA_REV_BITS(host->pid) >= 8) {
                nand->ecc.read_page = fsmc_read_page_hwecc;
@@ -986,6 +1054,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
                                break;
                        }
 
+               case NAND_ECC_ON_DIE:
+                       break;
+
                default:
                        dev_err(&pdev->dev, "Unsupported ECC mode!\n");
                        goto err_probe;
@@ -1073,9 +1144,8 @@ static int fsmc_nand_resume(struct device *dev)
        struct fsmc_nand_data *host = dev_get_drvdata(dev);
        if (host) {
                clk_prepare_enable(host->clk);
-               fsmc_nand_setup(host->regs_va, host->bank,
-                               host->nand.options & NAND_BUSWIDTH_16,
-                               host->dev_timings);
+               if (host->dev_timings)
+                       fsmc_nand_setup(host, host->dev_timings);
        }
        return 0;
 }
index 141bd70..9778724 100644 (file)
@@ -26,7 +26,7 @@
 #include "gpmi-regs.h"
 #include "bch-regs.h"
 
-static struct timing_threshod timing_default_threshold = {
+static struct timing_threshold timing_default_threshold = {
        .max_data_setup_cycles       = (BM_GPMI_TIMING0_DATA_SETUP >>
                                                BP_GPMI_TIMING0_DATA_SETUP),
        .internal_data_setup_in_ns   = 0,
@@ -329,7 +329,7 @@ static unsigned int ns_to_cycles(unsigned int time,
 static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
                                        struct gpmi_nfc_hardware_timing *hw)
 {
-       struct timing_threshod *nfc = &timing_default_threshold;
+       struct timing_threshold *nfc = &timing_default_threshold;
        struct resources *r = &this->resources;
        struct nand_chip *nand = &this->nand;
        struct nand_timing target = this->timing;
@@ -932,7 +932,7 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
 
        nand->select_chip(mtd, 0);
 
-       /* [1] send SET FEATURE commond to NAND */
+       /* [1] send SET FEATURE command to NAND */
        feature[0] = mode;
        ret = nand->onfi_set_features(mtd, nand,
                                ONFI_FEATURE_ADDR_TIMING_MODE, feature);
index d521396..50f8d4a 100644 (file)
@@ -82,6 +82,10 @@ static int gpmi_ooblayout_free(struct mtd_info *mtd, int section,
        return 0;
 }
 
+static const char * const gpmi_clks_for_mx2x[] = {
+       "gpmi_io",
+};
+
 static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
        .ecc = gpmi_ooblayout_ecc,
        .free = gpmi_ooblayout_free,
@@ -91,24 +95,48 @@ static const struct gpmi_devdata gpmi_devdata_imx23 = {
        .type = IS_MX23,
        .bch_max_ecc_strength = 20,
        .max_chain_delay = 16,
+       .clks = gpmi_clks_for_mx2x,
+       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
 };
 
 static const struct gpmi_devdata gpmi_devdata_imx28 = {
        .type = IS_MX28,
        .bch_max_ecc_strength = 20,
        .max_chain_delay = 16,
+       .clks = gpmi_clks_for_mx2x,
+       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
+};
+
+static const char * const gpmi_clks_for_mx6[] = {
+       "gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
 };
 
 static const struct gpmi_devdata gpmi_devdata_imx6q = {
        .type = IS_MX6Q,
        .bch_max_ecc_strength = 40,
        .max_chain_delay = 12,
+       .clks = gpmi_clks_for_mx6,
+       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
 };
 
 static const struct gpmi_devdata gpmi_devdata_imx6sx = {
        .type = IS_MX6SX,
        .bch_max_ecc_strength = 62,
        .max_chain_delay = 12,
+       .clks = gpmi_clks_for_mx6,
+       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
+};
+
+static const char * const gpmi_clks_for_mx7d[] = {
+       "gpmi_io", "gpmi_bch_apb",
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx7d = {
+       .type = IS_MX7D,
+       .bch_max_ecc_strength = 62,
+       .max_chain_delay = 12,
+       .clks = gpmi_clks_for_mx7d,
+       .clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d),
 };
 
 static irqreturn_t bch_irq(int irq, void *cookie)
@@ -599,35 +627,14 @@ acquire_err:
        return -EINVAL;
 }
 
-static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = {
-       "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
-};
-
 static int gpmi_get_clks(struct gpmi_nand_data *this)
 {
        struct resources *r = &this->resources;
-       char **extra_clks = NULL;
        struct clk *clk;
        int err, i;
 
-       /* The main clock is stored in the first. */
-       r->clock[0] = devm_clk_get(this->dev, "gpmi_io");
-       if (IS_ERR(r->clock[0])) {
-               err = PTR_ERR(r->clock[0]);
-               goto err_clock;
-       }
-
-       /* Get extra clocks */
-       if (GPMI_IS_MX6(this))
-               extra_clks = extra_clks_for_mx6q;
-       if (!extra_clks)
-               return 0;
-
-       for (i = 1; i < GPMI_CLK_MAX; i++) {
-               if (extra_clks[i - 1] == NULL)
-                       break;
-
-               clk = devm_clk_get(this->dev, extra_clks[i - 1]);
+       for (i = 0; i < this->devdata->clks_count; i++) {
+               clk = devm_clk_get(this->dev, this->devdata->clks[i]);
                if (IS_ERR(clk)) {
                        err = PTR_ERR(clk);
                        goto err_clock;
@@ -1929,12 +1936,6 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
        return gpmi_alloc_dma_buffer(this);
 }
 
-static void gpmi_nand_exit(struct gpmi_nand_data *this)
-{
-       nand_release(nand_to_mtd(&this->nand));
-       gpmi_free_dma_buffer(this);
-}
-
 static int gpmi_init_last(struct gpmi_nand_data *this)
 {
        struct nand_chip *chip = &this->nand;
@@ -2048,18 +2049,20 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
 
        ret = nand_boot_init(this);
        if (ret)
-               goto err_out;
+               goto err_nand_cleanup;
        ret = chip->scan_bbt(mtd);
        if (ret)
-               goto err_out;
+               goto err_nand_cleanup;
 
        ret = mtd_device_register(mtd, NULL, 0);
        if (ret)
-               goto err_out;
+               goto err_nand_cleanup;
        return 0;
 
+err_nand_cleanup:
+       nand_cleanup(chip);
 err_out:
-       gpmi_nand_exit(this);
+       gpmi_free_dma_buffer(this);
        return ret;
 }
 
@@ -2076,6 +2079,9 @@ static const struct of_device_id gpmi_nand_id_table[] = {
        }, {
                .compatible = "fsl,imx6sx-gpmi-nand",
                .data = &gpmi_devdata_imx6sx,
+       }, {
+               .compatible = "fsl,imx7d-gpmi-nand",
+               .data = &gpmi_devdata_imx7d,
        }, {}
 };
 MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
@@ -2129,7 +2135,8 @@ static int gpmi_nand_remove(struct platform_device *pdev)
 {
        struct gpmi_nand_data *this = platform_get_drvdata(pdev);
 
-       gpmi_nand_exit(this);
+       nand_release(nand_to_mtd(&this->nand));
+       gpmi_free_dma_buffer(this);
        release_resources(this);
        return 0;
 }
index 4e49a1f..9df0ad6 100644 (file)
@@ -123,13 +123,16 @@ enum gpmi_type {
        IS_MX23,
        IS_MX28,
        IS_MX6Q,
-       IS_MX6SX
+       IS_MX6SX,
+       IS_MX7D,
 };
 
 struct gpmi_devdata {
        enum gpmi_type type;
        int bch_max_ecc_strength;
        int max_chain_delay; /* See the async EDO mode */
+       const char * const *clks;
+       const int clks_count;
 };
 
 struct gpmi_nand_data {
@@ -231,7 +234,7 @@ struct gpmi_nfc_hardware_timing {
 };
 
 /**
- * struct timing_threshod - Timing threshold
+ * struct timing_threshold - Timing threshold
  * @max_data_setup_cycles:       The maximum number of data setup cycles that
  *                               can be expressed in the hardware.
  * @internal_data_setup_in_ns:   The time, in ns, that the NFC hardware requires
@@ -253,7 +256,7 @@ struct gpmi_nfc_hardware_timing {
  *                               progress, this is the clock frequency during
  *                               the most recent I/O transaction.
  */
-struct timing_threshod {
+struct timing_threshold {
        const unsigned int      max_chip_count;
        const unsigned int      max_data_setup_cycles;
        const unsigned int      internal_data_setup_in_ns;
@@ -305,6 +308,8 @@ void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
 #define GPMI_IS_MX28(x)                ((x)->devdata->type == IS_MX28)
 #define GPMI_IS_MX6Q(x)                ((x)->devdata->type == IS_MX6Q)
 #define GPMI_IS_MX6SX(x)       ((x)->devdata->type == IS_MX6SX)
+#define GPMI_IS_MX7D(x)                ((x)->devdata->type == IS_MX7D)
 
-#define GPMI_IS_MX6(x)         (GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x))
+#define GPMI_IS_MX6(x)         (GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x) || \
+                                GPMI_IS_MX7D(x))
 #endif
index e40364e..530caa8 100644 (file)
@@ -764,6 +764,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
        chip->write_buf         = hisi_nfc_write_buf;
        chip->read_buf          = hisi_nfc_read_buf;
        chip->chip_delay        = HINFC504_CHIP_DELAY;
+       chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+       chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
 
        hisi_nfc_host_init(host);
 
index a39bb70..8bc835f 100644 (file)
@@ -205,7 +205,7 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
                return -EINVAL;
        }
 
-       mtd->ooblayout = &nand_ooblayout_lp_ops;
+       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
 
        return 0;
 }
index 6d6eaed..0e86fb6 100644 (file)
@@ -708,6 +708,8 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        chip->read_buf = mpc5121_nfc_read_buf;
        chip->write_buf = mpc5121_nfc_write_buf;
        chip->select_chip = mpc5121_nfc_select_chip;
+       chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+       chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
        chip->bbt_options = NAND_BBT_USE_FLASH;
        chip->ecc.mode = NAND_ECC_SOFT;
        chip->ecc.algo = NAND_ECC_HAMMING;
index dbf2562..6c3a4aa 100644 (file)
 
 #define ECC_IDLE_MASK          BIT(0)
 #define ECC_IRQ_EN             BIT(0)
+#define ECC_PG_IRQ_SEL         BIT(1)
 #define ECC_OP_ENABLE          (1)
 #define ECC_OP_DISABLE         (0)
 
 #define ECC_ENCCON             (0x00)
 #define ECC_ENCCNFG            (0x04)
-#define                ECC_CNFG_4BIT           (0)
-#define                ECC_CNFG_6BIT           (1)
-#define                ECC_CNFG_8BIT           (2)
-#define                ECC_CNFG_10BIT          (3)
-#define                ECC_CNFG_12BIT          (4)
-#define                ECC_CNFG_14BIT          (5)
-#define                ECC_CNFG_16BIT          (6)
-#define                ECC_CNFG_18BIT          (7)
-#define                ECC_CNFG_20BIT          (8)
-#define                ECC_CNFG_22BIT          (9)
-#define                ECC_CNFG_24BIT          (0xa)
-#define                ECC_CNFG_28BIT          (0xb)
-#define                ECC_CNFG_32BIT          (0xc)
-#define                ECC_CNFG_36BIT          (0xd)
-#define                ECC_CNFG_40BIT          (0xe)
-#define                ECC_CNFG_44BIT          (0xf)
-#define                ECC_CNFG_48BIT          (0x10)
-#define                ECC_CNFG_52BIT          (0x11)
-#define                ECC_CNFG_56BIT          (0x12)
-#define                ECC_CNFG_60BIT          (0x13)
 #define                ECC_MODE_SHIFT          (5)
 #define                ECC_MS_SHIFT            (16)
 #define ECC_ENCDIADDR          (0x08)
 #define ECC_ENCIDLE            (0x0C)
-#define ECC_ENCPAR(x)          (0x10 + (x) * sizeof(u32))
 #define ECC_ENCIRQ_EN          (0x80)
 #define ECC_ENCIRQ_STA         (0x84)
 #define ECC_DECCON             (0x100)
@@ -66,7 +46,6 @@
 #define                DEC_CNFG_CORRECT        (0x3 << 12)
 #define ECC_DECIDLE            (0x10C)
 #define ECC_DECENUM0           (0x114)
-#define                ERR_MASK                (0x3f)
 #define ECC_DECDONE            (0x124)
 #define ECC_DECIRQ_EN          (0x200)
 #define ECC_DECIRQ_STA         (0x204)
 #define ECC_IRQ_REG(op)                ((op) == ECC_ENCODE ? \
                                        ECC_ENCIRQ_EN : ECC_DECIRQ_EN)
 
+struct mtk_ecc_caps {
+       u32 err_mask;
+       const u8 *ecc_strength;
+       u8 num_ecc_strength;
+       u32 encode_parity_reg0;
+       int pg_irq_sel;
+};
+
 struct mtk_ecc {
        struct device *dev;
+       const struct mtk_ecc_caps *caps;
        void __iomem *regs;
        struct clk *clk;
 
@@ -87,7 +75,18 @@ struct mtk_ecc {
        struct mutex lock;
        u32 sectors;
 
-       u8 eccdata[112];
+       u8 *eccdata;
+};
+
+/* ecc strength that each IP supports */
+static const u8 ecc_strength_mt2701[] = {
+       4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
+       40, 44, 48, 52, 56, 60
+};
+
+static const u8 ecc_strength_mt2712[] = {
+       4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
+       40, 44, 48, 52, 56, 60, 68, 72, 80
 };
 
 static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
@@ -136,77 +135,24 @@ static irqreturn_t mtk_ecc_irq(int irq, void *id)
        return IRQ_HANDLED;
 }
 
-static void mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+static int mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
 {
-       u32 ecc_bit = ECC_CNFG_4BIT, dec_sz, enc_sz;
-       u32 reg;
-
-       switch (config->strength) {
-       case 4:
-               ecc_bit = ECC_CNFG_4BIT;
-               break;
-       case 6:
-               ecc_bit = ECC_CNFG_6BIT;
-               break;
-       case 8:
-               ecc_bit = ECC_CNFG_8BIT;
-               break;
-       case 10:
-               ecc_bit = ECC_CNFG_10BIT;
-               break;
-       case 12:
-               ecc_bit = ECC_CNFG_12BIT;
-               break;
-       case 14:
-               ecc_bit = ECC_CNFG_14BIT;
-               break;
-       case 16:
-               ecc_bit = ECC_CNFG_16BIT;
-               break;
-       case 18:
-               ecc_bit = ECC_CNFG_18BIT;
-               break;
-       case 20:
-               ecc_bit = ECC_CNFG_20BIT;
-               break;
-       case 22:
-               ecc_bit = ECC_CNFG_22BIT;
-               break;
-       case 24:
-               ecc_bit = ECC_CNFG_24BIT;
-               break;
-       case 28:
-               ecc_bit = ECC_CNFG_28BIT;
-               break;
-       case 32:
-               ecc_bit = ECC_CNFG_32BIT;
-               break;
-       case 36:
-               ecc_bit = ECC_CNFG_36BIT;
-               break;
-       case 40:
-               ecc_bit = ECC_CNFG_40BIT;
-               break;
-       case 44:
-               ecc_bit = ECC_CNFG_44BIT;
-               break;
-       case 48:
-               ecc_bit = ECC_CNFG_48BIT;
-               break;
-       case 52:
-               ecc_bit = ECC_CNFG_52BIT;
-               break;
-       case 56:
-               ecc_bit = ECC_CNFG_56BIT;
-               break;
-       case 60:
-               ecc_bit = ECC_CNFG_60BIT;
-               break;
-       default:
-               dev_err(ecc->dev, "invalid strength %d, default to 4 bits\n",
+       u32 ecc_bit, dec_sz, enc_sz;
+       u32 reg, i;
+
+       for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
+               if (ecc->caps->ecc_strength[i] == config->strength)
+                       break;
+       }
+
+       if (i == ecc->caps->num_ecc_strength) {
+               dev_err(ecc->dev, "invalid ecc strength %d\n",
                        config->strength);
+               return -EINVAL;
        }
 
+       ecc_bit = i;
+
        if (config->op == ECC_ENCODE) {
                /* configure ECC encoder (in bits) */
                enc_sz = config->len << 3;
@@ -232,6 +178,8 @@ static void mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
                if (config->sectors)
                        ecc->sectors = 1 << (config->sectors - 1);
        }
+
+       return 0;
 }
 
 void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
@@ -247,8 +195,8 @@ void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
                offset = (i >> 2) << 2;
                err = readl(ecc->regs + ECC_DECENUM0 + offset);
                err = err >> ((i % 4) * 8);
-               err &= ERR_MASK;
-               if (err == ERR_MASK) {
+               err &= ecc->caps->err_mask;
+               if (err == ecc->caps->err_mask) {
                        /* uncorrectable errors */
                        stats->failed++;
                        continue;
@@ -313,6 +261,7 @@ EXPORT_SYMBOL(of_mtk_ecc_get);
 int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
 {
        enum mtk_ecc_operation op = config->op;
+       u16 reg_val;
        int ret;
 
        ret = mutex_lock_interruptible(&ecc->lock);
@@ -322,11 +271,27 @@ int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
        }
 
        mtk_ecc_wait_idle(ecc, op);
-       mtk_ecc_config(ecc, config);
-       writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
 
-       init_completion(&ecc->done);
-       writew(ECC_IRQ_EN, ecc->regs + ECC_IRQ_REG(op));
+       ret = mtk_ecc_config(ecc, config);
+       if (ret) {
+               mutex_unlock(&ecc->lock);
+               return ret;
+       }
+
+       if (config->mode != ECC_NFI_MODE || op != ECC_ENCODE) {
+               init_completion(&ecc->done);
+               reg_val = ECC_IRQ_EN;
+               /*
+                * For ECC_NFI_MODE, if ecc->caps->pg_irq_sel is 1, then it
+                * means this chip can only generate one ecc irq during page
+                * read / write. If is 0, generate one ecc irq each ecc step.
+                */
+               if (ecc->caps->pg_irq_sel && config->mode == ECC_NFI_MODE)
+                       reg_val |= ECC_PG_IRQ_SEL;
+               writew(reg_val, ecc->regs + ECC_IRQ_REG(op));
+       }
+
+       writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
 
        return 0;
 }
@@ -396,7 +361,9 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
        len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
 
        /* write the parity bytes generated by the ECC back to temp buffer */
-       __ioread32_copy(ecc->eccdata, ecc->regs + ECC_ENCPAR(0), round_up(len, 4));
+       __ioread32_copy(ecc->eccdata,
+                       ecc->regs + ecc->caps->encode_parity_reg0,
+                       round_up(len, 4));
 
        /* copy into possibly unaligned OOB region with actual length */
        memcpy(data + bytes, ecc->eccdata, len);
@@ -409,37 +376,79 @@ timeout:
 }
 EXPORT_SYMBOL(mtk_ecc_encode);
 
-void mtk_ecc_adjust_strength(u32 *p)
+void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p)
 {
-       u32 ecc[] = {4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
-                       40, 44, 48, 52, 56, 60};
+       const u8 *ecc_strength = ecc->caps->ecc_strength;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(ecc); i++) {
-               if (*p <= ecc[i]) {
+       for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
+               if (*p <= ecc_strength[i]) {
                        if (!i)
-                               *p = ecc[i];
-                       else if (*p != ecc[i])
-                               *p = ecc[i - 1];
+                               *p = ecc_strength[i];
+                       else if (*p != ecc_strength[i])
+                               *p = ecc_strength[i - 1];
                        return;
                }
        }
 
-       *p = ecc[ARRAY_SIZE(ecc) - 1];
+       *p = ecc_strength[ecc->caps->num_ecc_strength - 1];
 }
 EXPORT_SYMBOL(mtk_ecc_adjust_strength);
 
+static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
+       .err_mask = 0x3f,
+       .ecc_strength = ecc_strength_mt2701,
+       .num_ecc_strength = 20,
+       .encode_parity_reg0 = 0x10,
+       .pg_irq_sel = 0,
+};
+
+static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
+       .err_mask = 0x7f,
+       .ecc_strength = ecc_strength_mt2712,
+       .num_ecc_strength = 23,
+       .encode_parity_reg0 = 0x300,
+       .pg_irq_sel = 1,
+};
+
+static const struct of_device_id mtk_ecc_dt_match[] = {
+       {
+               .compatible = "mediatek,mt2701-ecc",
+               .data = &mtk_ecc_caps_mt2701,
+       }, {
+               .compatible = "mediatek,mt2712-ecc",
+               .data = &mtk_ecc_caps_mt2712,
+       },
+       {},
+};
+
 static int mtk_ecc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct mtk_ecc *ecc;
        struct resource *res;
+       const struct of_device_id *of_ecc_id = NULL;
+       u32 max_eccdata_size;
        int irq, ret;
 
        ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
        if (!ecc)
                return -ENOMEM;
 
+       of_ecc_id = of_match_device(mtk_ecc_dt_match, &pdev->dev);
+       if (!of_ecc_id)
+               return -ENODEV;
+
+       ecc->caps = of_ecc_id->data;
+
+       max_eccdata_size = ecc->caps->num_ecc_strength - 1;
+       max_eccdata_size = ecc->caps->ecc_strength[max_eccdata_size];
+       max_eccdata_size = (max_eccdata_size * ECC_PARITY_BITS + 7) >> 3;
+       max_eccdata_size = round_up(max_eccdata_size, 4);
+       ecc->eccdata = devm_kzalloc(dev, max_eccdata_size, GFP_KERNEL);
+       if (!ecc->eccdata)
+               return -ENOMEM;
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        ecc->regs = devm_ioremap_resource(dev, res);
        if (IS_ERR(ecc->regs)) {
@@ -500,19 +509,12 @@ static int mtk_ecc_resume(struct device *dev)
                return ret;
        }
 
-       mtk_ecc_hw_init(ecc);
-
        return 0;
 }
 
 static SIMPLE_DEV_PM_OPS(mtk_ecc_pm_ops, mtk_ecc_suspend, mtk_ecc_resume);
 #endif
 
-static const struct of_device_id mtk_ecc_dt_match[] = {
-       { .compatible = "mediatek,mt2701-ecc" },
-       {},
-};
-
 MODULE_DEVICE_TABLE(of, mtk_ecc_dt_match);
 
 static struct platform_driver mtk_ecc_driver = {
index cbeba5c..d245c14 100644 (file)
@@ -42,7 +42,7 @@ void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
 int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
 int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
 void mtk_ecc_disable(struct mtk_ecc *);
-void mtk_ecc_adjust_strength(u32 *);
+void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
 
 struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
 void mtk_ecc_release(struct mtk_ecc *);
index 6c517c6..f7ae994 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/iopoll.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include "mtk_ecc.h"
 
 /* NAND controller register definition */
 #define NFI_PAGEFMT            (0x04)
 #define                PAGEFMT_FDM_ECC_SHIFT   (12)
 #define                PAGEFMT_FDM_SHIFT       (8)
-#define                PAGEFMT_SPARE_16        (0)
-#define                PAGEFMT_SPARE_26        (1)
-#define                PAGEFMT_SPARE_27        (2)
-#define                PAGEFMT_SPARE_28        (3)
-#define                PAGEFMT_SPARE_32        (4)
-#define                PAGEFMT_SPARE_36        (5)
-#define                PAGEFMT_SPARE_40        (6)
-#define                PAGEFMT_SPARE_44        (7)
-#define                PAGEFMT_SPARE_48        (8)
-#define                PAGEFMT_SPARE_49        (9)
-#define                PAGEFMT_SPARE_50        (0xa)
-#define                PAGEFMT_SPARE_51        (0xb)
-#define                PAGEFMT_SPARE_52        (0xc)
-#define                PAGEFMT_SPARE_62        (0xd)
-#define                PAGEFMT_SPARE_63        (0xe)
-#define                PAGEFMT_SPARE_64        (0xf)
-#define                PAGEFMT_SPARE_SHIFT     (4)
 #define                PAGEFMT_SEC_SEL_512     BIT(2)
 #define                PAGEFMT_512_2K          (0)
 #define                PAGEFMT_2K_4K           (1)
 #define MTK_RESET_TIMEOUT      (1000000)
 #define MTK_MAX_SECTOR         (16)
 #define MTK_NAND_MAX_NSELS     (2)
+#define MTK_NFC_MIN_SPARE      (16)
+#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
+       ((tpoecs) << 28 | (tprecs) << 22 | (tc2r) << 16 | \
+       (tw2r) << 12 | (twh) << 8 | (twst) << 4 | (trlt))
+
+struct mtk_nfc_caps {
+       const u8 *spare_size;
+       u8 num_spare_size;
+       u8 pageformat_spare_shift;
+       u8 nfi_clk_div;
+};
 
 struct mtk_nfc_bad_mark_ctl {
        void (*bm_swap)(struct mtd_info *, u8 *buf, int raw);
@@ -155,6 +150,7 @@ struct mtk_nfc {
        struct mtk_ecc *ecc;
 
        struct device *dev;
+       const struct mtk_nfc_caps *caps;
        void __iomem *regs;
 
        struct completion done;
@@ -163,6 +159,20 @@ struct mtk_nfc {
        u8 *buffer;
 };
 
+/*
+ * supported spare size of each IP.
+ * order should be the same with the spare size bitfiled defination of
+ * register NFI_PAGEFMT.
+ */
+static const u8 spare_size_mt2701[] = {
+       16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 63, 64
+};
+
+static const u8 spare_size_mt2712[] = {
+       16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 61, 63, 64, 67,
+       74
+};
+
 static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand)
 {
        return container_of(nand, struct mtk_nfc_nand_chip, nand);
@@ -308,7 +318,7 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
        struct nand_chip *chip = mtd_to_nand(mtd);
        struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
        struct mtk_nfc *nfc = nand_get_controller_data(chip);
-       u32 fmt, spare;
+       u32 fmt, spare, i;
 
        if (!mtd->writesize)
                return 0;
@@ -352,63 +362,21 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
        if (chip->ecc.size == 1024)
                spare >>= 1;
 
-       switch (spare) {
-       case 16:
-               fmt |= (PAGEFMT_SPARE_16 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 26:
-               fmt |= (PAGEFMT_SPARE_26 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 27:
-               fmt |= (PAGEFMT_SPARE_27 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 28:
-               fmt |= (PAGEFMT_SPARE_28 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 32:
-               fmt |= (PAGEFMT_SPARE_32 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 36:
-               fmt |= (PAGEFMT_SPARE_36 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 40:
-               fmt |= (PAGEFMT_SPARE_40 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 44:
-               fmt |= (PAGEFMT_SPARE_44 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 48:
-               fmt |= (PAGEFMT_SPARE_48 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 49:
-               fmt |= (PAGEFMT_SPARE_49 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 50:
-               fmt |= (PAGEFMT_SPARE_50 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 51:
-               fmt |= (PAGEFMT_SPARE_51 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 52:
-               fmt |= (PAGEFMT_SPARE_52 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 62:
-               fmt |= (PAGEFMT_SPARE_62 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 63:
-               fmt |= (PAGEFMT_SPARE_63 << PAGEFMT_SPARE_SHIFT);
-               break;
-       case 64:
-               fmt |= (PAGEFMT_SPARE_64 << PAGEFMT_SPARE_SHIFT);
-               break;
-       default:
-               dev_err(nfc->dev, "invalid spare per sector %d\n", spare);
+       for (i = 0; i < nfc->caps->num_spare_size; i++) {
+               if (nfc->caps->spare_size[i] == spare)
+                       break;
+       }
+
+       if (i == nfc->caps->num_spare_size) {
+               dev_err(nfc->dev, "invalid spare size %d\n", spare);
                return -EINVAL;
        }
 
+       fmt |= i << nfc->caps->pageformat_spare_shift;
+
        fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT;
        fmt |= mtk_nand->fdm.ecc_size << PAGEFMT_FDM_ECC_SHIFT;
-       nfi_writew(nfc, fmt, NFI_PAGEFMT);
+       nfi_writel(nfc, fmt, NFI_PAGEFMT);
 
        nfc->ecc_cfg.strength = chip->ecc.strength;
        nfc->ecc_cfg.len = chip->ecc.size + mtk_nand->fdm.ecc_size;
@@ -531,6 +499,74 @@ static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
                mtk_nfc_write_byte(mtd, buf[i]);
 }
 
+static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
+                                       const struct nand_data_interface *conf)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+       const struct nand_sdr_timings *timings;
+       u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
+
+       timings = nand_get_sdr_timings(conf);
+       if (IS_ERR(timings))
+               return -ENOTSUPP;
+
+       if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+               return 0;
+
+       rate = clk_get_rate(nfc->clk.nfi_clk);
+       /* There is a frequency divider in some IPs */
+       rate /= nfc->caps->nfi_clk_div;
+
+       /* turn clock rate into KHZ */
+       rate /= 1000;
+
+       tpoecs = max(timings->tALH_min, timings->tCLH_min) / 1000;
+       tpoecs = DIV_ROUND_UP(tpoecs * rate, 1000000);
+       tpoecs &= 0xf;
+
+       tprecs = max(timings->tCLS_min, timings->tALS_min) / 1000;
+       tprecs = DIV_ROUND_UP(tprecs * rate, 1000000);
+       tprecs &= 0x3f;
+
+       /* sdr interface has no tCR which means CE# low to RE# low */
+       tc2r = 0;
+
+       tw2r = timings->tWHR_min / 1000;
+       tw2r = DIV_ROUND_UP(tw2r * rate, 1000000);
+       tw2r = DIV_ROUND_UP(tw2r - 1, 2);
+       tw2r &= 0xf;
+
+       twh = max(timings->tREH_min, timings->tWH_min) / 1000;
+       twh = DIV_ROUND_UP(twh * rate, 1000000) - 1;
+       twh &= 0xf;
+
+       twst = timings->tWP_min / 1000;
+       twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
+       twst &= 0xf;
+
+       trlt = max(timings->tREA_max, timings->tRP_min) / 1000;
+       trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
+       trlt &= 0xf;
+
+       /*
+        * ACCON: access timing control register
+        * -------------------------------------
+        * 31:28: tpoecs, minimum required time for CS post pulling down after
+        *        accessing the device
+        * 27:22: tprecs, minimum required time for CS pre pulling down before
+        *        accessing the device
+        * 21:16: tc2r, minimum required time from NCEB low to NREB low
+        * 15:12: tw2r, minimum required time from NWEB high to NREB low.
+        * 11:08: twh, write enable hold time
+        * 07:04: twst, write wait states
+        * 03:00: trlt, read wait states
+        */
+       trlt = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt);
+       nfi_writel(nfc, trlt, NFI_ACCCON);
+
+       return 0;
+}
+
 static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data)
 {
        struct mtk_nfc *nfc = nand_get_controller_data(chip);
@@ -988,28 +1024,13 @@ static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
 static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
 {
        /*
-        * ACCON: access timing control register
-        * -------------------------------------
-        * 31:28: minimum required time for CS post pulling down after accessing
-        *      the device
-        * 27:22: minimum required time for CS pre pulling down before accessing
-        *      the device
-        * 21:16: minimum required time from NCEB low to NREB low
-        * 15:12: minimum required time from NWEB high to NREB low.
-        * 11:08: write enable hold time
-        * 07:04: write wait states
-        * 03:00: read wait states
-        */
-       nfi_writel(nfc, 0x10804211, NFI_ACCCON);
-
-       /*
         * CNRNB: nand ready/busy register
         * -------------------------------
         * 7:4: timeout register for polling the NAND busy/ready signal
         * 0  : poll the status of the busy/ready signal after [7:4]*16 cycles.
         */
        nfi_writew(nfc, 0xf1, NFI_CNRNB);
-       nfi_writew(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
+       nfi_writel(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
 
        mtk_nfc_hw_reset(nfc);
 
@@ -1131,12 +1152,12 @@ static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
        }
 }
 
-static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
+static int mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
-       u32 spare[] = {16, 26, 27, 28, 32, 36, 40, 44,
-                       48, 49, 50, 51, 52, 62, 63, 64};
-       u32 eccsteps, i;
+       struct mtk_nfc *nfc = nand_get_controller_data(nand);
+       const u8 *spare = nfc->caps->spare_size;
+       u32 eccsteps, i, closest_spare = 0;
 
        eccsteps = mtd->writesize / nand->ecc.size;
        *sps = mtd->oobsize / eccsteps;
@@ -1144,28 +1165,31 @@ static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
        if (nand->ecc.size == 1024)
                *sps >>= 1;
 
-       for (i = 0; i < ARRAY_SIZE(spare); i++) {
-               if (*sps <= spare[i]) {
-                       if (!i)
-                               *sps = spare[i];
-                       else if (*sps != spare[i])
-                               *sps = spare[i - 1];
-                       break;
+       if (*sps < MTK_NFC_MIN_SPARE)
+               return -EINVAL;
+
+       for (i = 0; i < nfc->caps->num_spare_size; i++) {
+               if (*sps >= spare[i] && spare[i] >= spare[closest_spare]) {
+                       closest_spare = i;
+                       if (*sps == spare[i])
+                               break;
                }
        }
 
-       if (i >= ARRAY_SIZE(spare))
-               *sps = spare[ARRAY_SIZE(spare) - 1];
+       *sps = spare[closest_spare];
 
        if (nand->ecc.size == 1024)
                *sps <<= 1;
+
+       return 0;
 }
 
 static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
+       struct mtk_nfc *nfc = nand_get_controller_data(nand);
        u32 spare;
-       int free;
+       int free, ret;
 
        /* support only ecc hw mode */
        if (nand->ecc.mode != NAND_ECC_HW) {
@@ -1194,7 +1218,9 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
                        nand->ecc.size = 1024;
                }
 
-               mtk_nfc_set_spare_per_sector(&spare, mtd);
+               ret = mtk_nfc_set_spare_per_sector(&spare, mtd);
+               if (ret)
+                       return ret;
 
                /* calculate oob bytes except ecc parity data */
                free = ((nand->ecc.strength * ECC_PARITY_BITS) + 7) >> 3;
@@ -1214,7 +1240,7 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
                }
        }
 
-       mtk_ecc_adjust_strength(&nand->ecc.strength);
+       mtk_ecc_adjust_strength(nfc->ecc, &nand->ecc.strength);
 
        dev_info(dev, "eccsize %d eccstrength %d\n",
                 nand->ecc.size, nand->ecc.strength);
@@ -1271,6 +1297,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
        nand->read_byte = mtk_nfc_read_byte;
        nand->read_buf = mtk_nfc_read_buf;
        nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
+       nand->setup_data_interface = mtk_nfc_setup_data_interface;
 
        /* set default mode in case dt entry is missing */
        nand->ecc.mode = NAND_ECC_HW;
@@ -1312,7 +1339,10 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
                return -EINVAL;
        }
 
-       mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
+       ret = mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
+       if (ret)
+               return ret;
+
        mtk_nfc_set_fdm(&chip->fdm, mtd);
        mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
 
@@ -1354,12 +1384,39 @@ static int mtk_nfc_nand_chips_init(struct device *dev, struct mtk_nfc *nfc)
        return 0;
 }
 
+static const struct mtk_nfc_caps mtk_nfc_caps_mt2701 = {
+       .spare_size = spare_size_mt2701,
+       .num_spare_size = 16,
+       .pageformat_spare_shift = 4,
+       .nfi_clk_div = 1,
+};
+
+static const struct mtk_nfc_caps mtk_nfc_caps_mt2712 = {
+       .spare_size = spare_size_mt2712,
+       .num_spare_size = 19,
+       .pageformat_spare_shift = 16,
+       .nfi_clk_div = 2,
+};
+
+static const struct of_device_id mtk_nfc_id_table[] = {
+       {
+               .compatible = "mediatek,mt2701-nfc",
+               .data = &mtk_nfc_caps_mt2701,
+       }, {
+               .compatible = "mediatek,mt2712-nfc",
+               .data = &mtk_nfc_caps_mt2712,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mtk_nfc_id_table);
+
 static int mtk_nfc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        struct mtk_nfc *nfc;
        struct resource *res;
+       const struct of_device_id *of_nfc_id = NULL;
        int ret, irq;
 
        nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
@@ -1423,6 +1480,14 @@ static int mtk_nfc_probe(struct platform_device *pdev)
                goto clk_disable;
        }
 
+       of_nfc_id = of_match_device(mtk_nfc_id_table, &pdev->dev);
+       if (!of_nfc_id) {
+               ret = -ENODEV;
+               goto clk_disable;
+       }
+
+       nfc->caps = of_nfc_id->data;
+
        platform_set_drvdata(pdev, nfc);
 
        ret = mtk_nfc_nand_chips_init(dev, nfc);
@@ -1485,8 +1550,6 @@ static int mtk_nfc_resume(struct device *dev)
        if (ret)
                return ret;
 
-       mtk_nfc_hw_init(nfc);
-
        /* reset NAND chip if VCC was powered off */
        list_for_each_entry(chip, &nfc->chips, node) {
                nand = &chip->nand;
@@ -1503,12 +1566,6 @@ static int mtk_nfc_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume);
 #endif
 
-static const struct of_device_id mtk_nfc_id_table[] = {
-       { .compatible = "mediatek,mt2701-nfc" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, mtk_nfc_id_table);
-
 static struct platform_driver mtk_nfc_driver = {
        .probe  = mtk_nfc_probe,
        .remove = mtk_nfc_remove,
index 61ca020..a764d5c 100644 (file)
@@ -152,9 +152,8 @@ struct mxc_nand_devtype_data {
        void (*select_chip)(struct mtd_info *mtd, int chip);
        int (*correct_data)(struct mtd_info *mtd, u_char *dat,
                        u_char *read_ecc, u_char *calc_ecc);
-       int (*setup_data_interface)(struct mtd_info *mtd,
-                                   const struct nand_data_interface *conf,
-                                   bool check_only);
+       int (*setup_data_interface)(struct mtd_info *mtd, int csline,
+                                   const struct nand_data_interface *conf);
 
        /*
         * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
@@ -1015,9 +1014,8 @@ static void preset_v1(struct mtd_info *mtd)
        writew(0x4, NFC_V1_V2_WRPROT);
 }
 
-static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
-                                       const struct nand_data_interface *conf,
-                                       bool check_only)
+static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, int csline,
+                                       const struct nand_data_interface *conf)
 {
        struct nand_chip *nand_chip = mtd_to_nand(mtd);
        struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
@@ -1075,7 +1073,7 @@ static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
                return -EINVAL;
        }
 
-       if (check_only)
+       if (csline == NAND_DATA_IFACE_CHECK_ONLY)
                return 0;
 
        ret = clk_set_rate(host->clk, rate);
index bf8486c..5fa5ddc 100644 (file)
@@ -755,6 +755,16 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
                return;
 
                /* This applies to read commands */
+       case NAND_CMD_READ0:
+               /*
+                * READ0 is sometimes used to exit GET STATUS mode. When this
+                * is the case no address cycles are requested, and we can use
+                * this information to detect that we should not wait for the
+                * device to be ready.
+                */
+               if (column == -1 && page_addr == -1)
+                       return;
+
        default:
                /*
                 * If we don't have access to the busy pin, we apply the given
@@ -889,6 +899,15 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
                return;
 
        case NAND_CMD_READ0:
+               /*
+                * READ0 is sometimes used to exit GET STATUS mode. When this
+                * is the case no address cycles are requested, and we can use
+                * this information to detect that READSTART should not be
+                * issued.
+                */
+               if (column == -1 && page_addr == -1)
+                       return;
+
                chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
                               NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
                chip->cmd_ctrl(mtd, NAND_CMD_NONE,
@@ -1044,12 +1063,13 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 /**
  * nand_reset_data_interface - Reset data interface and timings
  * @chip: The NAND chip
+ * @chipnr: Internal die id
  *
  * Reset the Data interface and timings to ONFI mode 0.
  *
  * Returns 0 for success or negative error code otherwise.
  */
-static int nand_reset_data_interface(struct nand_chip *chip)
+static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        const struct nand_data_interface *conf;
@@ -1073,7 +1093,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
         */
 
        conf = nand_get_default_data_interface();
-       ret = chip->setup_data_interface(mtd, conf, false);
+       ret = chip->setup_data_interface(mtd, chipnr, conf);
        if (ret)
                pr_err("Failed to configure data interface to SDR timing mode 0\n");
 
@@ -1083,6 +1103,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
 /**
  * nand_setup_data_interface - Setup the best data interface and timings
  * @chip: The NAND chip
+ * @chipnr: Internal die id
  *
  * Find and configure the best data interface and NAND timings supported by
  * the chip and the driver.
@@ -1092,7 +1113,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
  *
  * Returns 0 for success or negative error code otherwise.
  */
-static int nand_setup_data_interface(struct nand_chip *chip)
+static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
@@ -1116,7 +1137,7 @@ static int nand_setup_data_interface(struct nand_chip *chip)
                        goto err;
        }
 
-       ret = chip->setup_data_interface(mtd, chip->data_interface, false);
+       ret = chip->setup_data_interface(mtd, chipnr, chip->data_interface);
 err:
        return ret;
 }
@@ -1167,8 +1188,10 @@ static int nand_init_data_interface(struct nand_chip *chip)
                if (ret)
                        continue;
 
-               ret = chip->setup_data_interface(mtd, chip->data_interface,
-                                                true);
+               /* Pass -1 to only */
+               ret = chip->setup_data_interface(mtd,
+                                                NAND_DATA_IFACE_CHECK_ONLY,
+                                                chip->data_interface);
                if (!ret) {
                        chip->onfi_timing_mode_default = mode;
                        break;
@@ -1195,7 +1218,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
        struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
 
-       ret = nand_reset_data_interface(chip);
+       ret = nand_reset_data_interface(chip, chipnr);
        if (ret)
                return ret;
 
@@ -1208,7 +1231,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
        chip->select_chip(mtd, -1);
 
        chip->select_chip(mtd, chipnr);
-       ret = nand_setup_data_interface(chip);
+       ret = nand_setup_data_interface(chip, chipnr);
        chip->select_chip(mtd, -1);
        if (ret)
                return ret;
@@ -1424,7 +1447,10 @@ static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
 
        for (; len >= sizeof(long);
             len -= sizeof(long), bitmap += sizeof(long)) {
-               weight = hweight_long(*((unsigned long *)bitmap));
+               unsigned long d = *((unsigned long *)bitmap);
+               if (d == ~0UL)
+                       continue;
+               weight = hweight_long(d);
                bitflips += BITS_PER_LONG - weight;
                if (unlikely(bitflips > bitflips_threshold))
                        return -EBADMSG;
@@ -1527,14 +1553,15 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
  *
  * Not for syndrome calculating ECC controllers, which use a special oob layout.
  */
-static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                             uint8_t *buf, int oob_required, int page)
+int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                      uint8_t *buf, int oob_required, int page)
 {
        chip->read_buf(mtd, buf, mtd->writesize);
        if (oob_required)
                chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
        return 0;
 }
+EXPORT_SYMBOL(nand_read_page_raw);
 
 /**
  * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
@@ -2472,8 +2499,8 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
  *
  * Not for syndrome calculating ECC controllers, which use a special oob layout.
  */
-static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                              const uint8_t *buf, int oob_required, int page)
+int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                       const uint8_t *buf, int oob_required, int page)
 {
        chip->write_buf(mtd, buf, mtd->writesize);
        if (oob_required)
@@ -2481,6 +2508,7 @@ static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
 
        return 0;
 }
+EXPORT_SYMBOL(nand_write_page_raw);
 
 /**
  * nand_write_page_raw_syndrome - [INTERN] raw page write function
@@ -2718,7 +2746,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
  */
 static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                uint32_t offset, int data_len, const uint8_t *buf,
-               int oob_required, int page, int cached, int raw)
+               int oob_required, int page, int raw)
 {
        int status, subpage;
 
@@ -2744,30 +2772,12 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        if (status < 0)
                return status;
 
-       /*
-        * Cached progamming disabled for now. Not sure if it's worth the
-        * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s).
-        */
-       cached = 0;
+       if (nand_standard_page_accessors(&chip->ecc)) {
+               chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 
-       if (!cached || !NAND_HAS_CACHEPROG(chip)) {
-
-               if (nand_standard_page_accessors(&chip->ecc))
-                       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
                status = chip->waitfunc(mtd, chip);
-               /*
-                * See if operation failed and additional status checks are
-                * available.
-                */
-               if ((status & NAND_STATUS_FAIL) && (chip->errstat))
-                       status = chip->errstat(mtd, chip, FL_WRITING, status,
-                                              page);
-
                if (status & NAND_STATUS_FAIL)
                        return -EIO;
-       } else {
-               chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
-               status = chip->waitfunc(mtd, chip);
        }
 
        return 0;
@@ -2875,7 +2885,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 
        while (1) {
                int bytes = mtd->writesize;
-               int cached = writelen > bytes && page != blockmask;
                uint8_t *wbuf = buf;
                int use_bufpoi;
                int part_pagewr = (column || writelen < mtd->writesize);
@@ -2893,7 +2902,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                if (use_bufpoi) {
                        pr_debug("%s: using write bounce buffer for buf@%p\n",
                                         __func__, buf);
-                       cached = 0;
                        if (part_pagewr)
                                bytes = min_t(int, bytes - column, writelen);
                        chip->pagebuf = -1;
@@ -2912,7 +2920,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                }
 
                ret = nand_write_page(mtd, chip, column, bytes, wbuf,
-                                     oob_required, page, cached,
+                                     oob_required, page,
                                      (ops->mode == MTD_OPS_RAW));
                if (ret)
                        break;
@@ -3228,14 +3236,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 
                status = chip->erase(mtd, page & chip->pagemask);
 
-               /*
-                * See if operation failed and additional status checks are
-                * available
-                */
-               if ((status & NAND_STATUS_FAIL) && (chip->errstat))
-                       status = chip->errstat(mtd, chip, FL_ERASING,
-                                              status, page);
-
                /* See if block erase succeeded */
                if (status & NAND_STATUS_FAIL) {
                        pr_debug("%s: failed erase, page 0x%08x\n",
@@ -3422,6 +3422,25 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
+ * nand_onfi_get_set_features_notsupp - set/get features stub returning
+ *                                     -ENOTSUPP
+ * @mtd: MTD device structure
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ *
+ * Should be used by NAND controller drivers that do not support the SET/GET
+ * FEATURES operations.
+ */
+int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd,
+                                      struct nand_chip *chip, int addr,
+                                      u8 *subfeature_param)
+{
+       return -ENOTSUPP;
+}
+EXPORT_SYMBOL(nand_onfi_get_set_features_notsupp);
+
+/**
  * nand_suspend - [MTD Interface] Suspend the NAND flash
  * @mtd: MTD device structure
  */
@@ -4180,6 +4199,7 @@ static const char * const nand_ecc_modes[] = {
        [NAND_ECC_HW]           = "hw",
        [NAND_ECC_HW_SYNDROME]  = "hw_syndrome",
        [NAND_ECC_HW_OOB_FIRST] = "hw_oob_first",
+       [NAND_ECC_ON_DIE]       = "on-die",
 };
 
 static int of_get_nand_ecc_mode(struct device_node *np)
@@ -4374,7 +4394,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
         * For the other dies, nand_reset() will automatically switch to the
         * best mode for us.
         */
-       ret = nand_setup_data_interface(chip);
+       ret = nand_setup_data_interface(chip, 0);
        if (ret)
                goto err_nand_init;
 
@@ -4512,6 +4532,226 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
        }
 }
 
+/**
+ * nand_check_ecc_caps - check the sanity of preset ECC settings
+ * @chip: nand chip info structure
+ * @caps: ECC caps info structure
+ * @oobavail: OOB size that the ECC engine can use
+ *
+ * When ECC step size and strength are already set, check if they are supported
+ * by the controller and the calculated ECC bytes fit within the chip's OOB.
+ * On success, the calculated ECC bytes is set.
+ */
+int nand_check_ecc_caps(struct nand_chip *chip,
+                       const struct nand_ecc_caps *caps, int oobavail)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       const struct nand_ecc_step_info *stepinfo;
+       int preset_step = chip->ecc.size;
+       int preset_strength = chip->ecc.strength;
+       int nsteps, ecc_bytes;
+       int i, j;
+
+       if (WARN_ON(oobavail < 0))
+               return -EINVAL;
+
+       if (!preset_step || !preset_strength)
+               return -ENODATA;
+
+       nsteps = mtd->writesize / preset_step;
+
+       for (i = 0; i < caps->nstepinfos; i++) {
+               stepinfo = &caps->stepinfos[i];
+
+               if (stepinfo->stepsize != preset_step)
+                       continue;
+
+               for (j = 0; j < stepinfo->nstrengths; j++) {
+                       if (stepinfo->strengths[j] != preset_strength)
+                               continue;
+
+                       ecc_bytes = caps->calc_ecc_bytes(preset_step,
+                                                        preset_strength);
+                       if (WARN_ON_ONCE(ecc_bytes < 0))
+                               return ecc_bytes;
+
+                       if (ecc_bytes * nsteps > oobavail) {
+                               pr_err("ECC (step, strength) = (%d, %d) does not fit in OOB",
+                                      preset_step, preset_strength);
+                               return -ENOSPC;
+                       }
+
+                       chip->ecc.bytes = ecc_bytes;
+
+                       return 0;
+               }
+       }
+
+       pr_err("ECC (step, strength) = (%d, %d) not supported on this controller",
+              preset_step, preset_strength);
+
+       return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
+
+/**
+ * nand_match_ecc_req - meet the chip's requirement with least ECC bytes
+ * @chip: nand chip info structure
+ * @caps: ECC engine caps info structure
+ * @oobavail: OOB size that the ECC engine can use
+ *
+ * If a chip's ECC requirement is provided, try to meet it with the least
+ * number of ECC bytes (i.e. with the largest number of OOB-free bytes).
+ * On success, the chosen ECC settings are set.
+ */
+int nand_match_ecc_req(struct nand_chip *chip,
+                      const struct nand_ecc_caps *caps, int oobavail)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       const struct nand_ecc_step_info *stepinfo;
+       int req_step = chip->ecc_step_ds;
+       int req_strength = chip->ecc_strength_ds;
+       int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
+       int best_step, best_strength, best_ecc_bytes;
+       int best_ecc_bytes_total = INT_MAX;
+       int i, j;
+
+       if (WARN_ON(oobavail < 0))
+               return -EINVAL;
+
+       /* No information provided by the NAND chip */
+       if (!req_step || !req_strength)
+               return -ENOTSUPP;
+
+       /* number of correctable bits the chip requires in a page */
+       req_corr = mtd->writesize / req_step * req_strength;
+
+       for (i = 0; i < caps->nstepinfos; i++) {
+               stepinfo = &caps->stepinfos[i];
+               step_size = stepinfo->stepsize;
+
+               for (j = 0; j < stepinfo->nstrengths; j++) {
+                       strength = stepinfo->strengths[j];
+
+                       /*
+                        * If both step size and strength are smaller than the
+                        * chip's requirement, it is not easy to compare the
+                        * resulted reliability.
+                        */
+                       if (step_size < req_step && strength < req_strength)
+                               continue;
+
+                       if (mtd->writesize % step_size)
+                               continue;
+
+                       nsteps = mtd->writesize / step_size;
+
+                       ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
+                       if (WARN_ON_ONCE(ecc_bytes < 0))
+                               continue;
+                       ecc_bytes_total = ecc_bytes * nsteps;
+
+                       if (ecc_bytes_total > oobavail ||
+                           strength * nsteps < req_corr)
+                               continue;
+
+                       /*
+                        * We assume the best is to meet the chip's requrement
+                        * with the least number of ECC bytes.
+                        */
+                       if (ecc_bytes_total < best_ecc_bytes_total) {
+                               best_ecc_bytes_total = ecc_bytes_total;
+                               best_step = step_size;
+                               best_strength = strength;
+                               best_ecc_bytes = ecc_bytes;
+                       }
+               }
+       }
+
+       if (best_ecc_bytes_total == INT_MAX)
+               return -ENOTSUPP;
+
+       chip->ecc.size = best_step;
+       chip->ecc.strength = best_strength;
+       chip->ecc.bytes = best_ecc_bytes;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nand_match_ecc_req);
+
+/**
+ * nand_maximize_ecc - choose the max ECC strength available
+ * @chip: nand chip info structure
+ * @caps: ECC engine caps info structure
+ * @oobavail: OOB size that the ECC engine can use
+ *
+ * Choose the max ECC strength that is supported on the controller, and can fit
+ * within the chip's OOB.  On success, the chosen ECC settings are set.
+ */
+int nand_maximize_ecc(struct nand_chip *chip,
+                     const struct nand_ecc_caps *caps, int oobavail)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       const struct nand_ecc_step_info *stepinfo;
+       int step_size, strength, nsteps, ecc_bytes, corr;
+       int best_corr = 0;
+       int best_step = 0;
+       int best_strength, best_ecc_bytes;
+       int i, j;
+
+       if (WARN_ON(oobavail < 0))
+               return -EINVAL;
+
+       for (i = 0; i < caps->nstepinfos; i++) {
+               stepinfo = &caps->stepinfos[i];
+               step_size = stepinfo->stepsize;
+
+               /* If chip->ecc.size is already set, respect it */
+               if (chip->ecc.size && step_size != chip->ecc.size)
+                       continue;
+
+               for (j = 0; j < stepinfo->nstrengths; j++) {
+                       strength = stepinfo->strengths[j];
+
+                       if (mtd->writesize % step_size)
+                               continue;
+
+                       nsteps = mtd->writesize / step_size;
+
+                       ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
+                       if (WARN_ON_ONCE(ecc_bytes < 0))
+                               continue;
+
+                       if (ecc_bytes * nsteps > oobavail)
+                               continue;
+
+                       corr = strength * nsteps;
+
+                       /*
+                        * If the number of correctable bits is the same,
+                        * bigger step_size has more reliability.
+                        */
+                       if (corr > best_corr ||
+                           (corr == best_corr && step_size > best_step)) {
+                               best_corr = corr;
+                               best_step = step_size;
+                               best_strength = strength;
+                               best_ecc_bytes = ecc_bytes;
+                       }
+               }
+       }
+
+       if (!best_corr)
+               return -ENOTSUPP;
+
+       chip->ecc.size = best_step;
+       chip->ecc.strength = best_strength;
+       chip->ecc.bytes = best_ecc_bytes;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nand_maximize_ecc);
+
 /*
  * Check if the chip configuration meet the datasheet requirements.
 
@@ -4733,6 +4973,18 @@ int nand_scan_tail(struct mtd_info *mtd)
                }
                break;
 
+       case NAND_ECC_ON_DIE:
+               if (!ecc->read_page || !ecc->write_page) {
+                       WARN(1, "No ECC functions supplied; on-die ECC not possible\n");
+                       ret = -EINVAL;
+                       goto err_free;
+               }
+               if (!ecc->read_oob)
+                       ecc->read_oob = nand_read_oob_std;
+               if (!ecc->write_oob)
+                       ecc->write_oob = nand_write_oob_std;
+               break;
+
        case NAND_ECC_NONE:
                pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");
                ecc->read_page = nand_read_page_raw;
@@ -4773,6 +5025,11 @@ int nand_scan_tail(struct mtd_info *mtd)
                goto err_free;
        }
        ecc->total = ecc->steps * ecc->bytes;
+       if (ecc->total > mtd->oobsize) {
+               WARN(1, "Total number of ECC bytes exceeded oobsize\n");
+               ret = -EINVAL;
+               goto err_free;
+       }
 
        /*
         * The number of bytes available for a client to place data into
index 8770110..c30ab60 100644 (file)
 
 #include <linux/mtd/nand.h>
 
+/*
+ * Special Micron status bit that indicates when the block has been
+ * corrected by on-die ECC and should be rewritten
+ */
+#define NAND_STATUS_WRITE_RECOMMENDED  BIT(3)
+
 struct nand_onfi_vendor_micron {
        u8 two_plane_read;
        u8 read_cache;
@@ -66,9 +72,197 @@ static int micron_nand_onfi_init(struct nand_chip *chip)
        return 0;
 }
 
+static int micron_nand_on_die_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                           struct mtd_oob_region *oobregion)
+{
+       if (section >= 4)
+               return -ERANGE;
+
+       oobregion->offset = (section * 16) + 8;
+       oobregion->length = 8;
+
+       return 0;
+}
+
+static int micron_nand_on_die_ooblayout_free(struct mtd_info *mtd, int section,
+                                            struct mtd_oob_region *oobregion)
+{
+       if (section >= 4)
+               return -ERANGE;
+
+       oobregion->offset = (section * 16) + 2;
+       oobregion->length = 6;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops micron_nand_on_die_ooblayout_ops = {
+       .ecc = micron_nand_on_die_ooblayout_ecc,
+       .free = micron_nand_on_die_ooblayout_free,
+};
+
+static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable)
+{
+       u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
+
+       if (enable)
+               feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN;
+
+       return chip->onfi_set_features(nand_to_mtd(chip), chip,
+                                      ONFI_FEATURE_ON_DIE_ECC, feature);
+}
+
+static int
+micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
+                                uint8_t *buf, int oob_required,
+                                int page)
+{
+       int status;
+       int max_bitflips = 0;
+
+       micron_nand_on_die_ecc_setup(chip, true);
+
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+       chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+       status = chip->read_byte(mtd);
+       if (status & NAND_STATUS_FAIL)
+               mtd->ecc_stats.failed++;
+       /*
+        * The internal ECC doesn't tell us the number of bitflips
+        * that have been corrected, but tells us if it recommends to
+        * rewrite the block. If it's the case, then we pretend we had
+        * a number of bitflips equal to the ECC strength, which will
+        * hint the NAND core to rewrite the block.
+        */
+       else if (status & NAND_STATUS_WRITE_RECOMMENDED)
+               max_bitflips = chip->ecc.strength;
+
+       chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1);
+
+       nand_read_page_raw(mtd, chip, buf, oob_required, page);
+
+       micron_nand_on_die_ecc_setup(chip, false);
+
+       return max_bitflips;
+}
+
+static int
+micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
+                                 const uint8_t *buf, int oob_required,
+                                 int page)
+{
+       int status;
+
+       micron_nand_on_die_ecc_setup(chip, true);
+
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+       nand_write_page_raw(mtd, chip, buf, oob_required, page);
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+       status = chip->waitfunc(mtd, chip);
+
+       micron_nand_on_die_ecc_setup(chip, false);
+
+       return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+static int
+micron_nand_read_page_raw_on_die_ecc(struct mtd_info *mtd,
+                                    struct nand_chip *chip,
+                                    uint8_t *buf, int oob_required,
+                                    int page)
+{
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+       nand_read_page_raw(mtd, chip, buf, oob_required, page);
+
+       return 0;
+}
+
+static int
+micron_nand_write_page_raw_on_die_ecc(struct mtd_info *mtd,
+                                     struct nand_chip *chip,
+                                     const uint8_t *buf, int oob_required,
+                                     int page)
+{
+       int status;
+
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+       nand_write_page_raw(mtd, chip, buf, oob_required, page);
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+       status = chip->waitfunc(mtd, chip);
+
+       return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+enum {
+       /* The NAND flash doesn't support on-die ECC */
+       MICRON_ON_DIE_UNSUPPORTED,
+
+       /*
+        * The NAND flash supports on-die ECC and it can be
+        * enabled/disabled by a set features command.
+        */
+       MICRON_ON_DIE_SUPPORTED,
+
+       /*
+        * The NAND flash supports on-die ECC, and it cannot be
+        * disabled.
+        */
+       MICRON_ON_DIE_MANDATORY,
+};
+
+/*
+ * Try to detect if the NAND support on-die ECC. To do this, we enable
+ * the feature, and read back if it has been enabled as expected. We
+ * also check if it can be disabled, because some Micron NANDs do not
+ * allow disabling the on-die ECC and we don't support such NANDs for
+ * now.
+ *
+ * This function also has the side effect of disabling on-die ECC if
+ * it had been left enabled by the firmware/bootloader.
+ */
+static int micron_supports_on_die_ecc(struct nand_chip *chip)
+{
+       u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
+       int ret;
+
+       if (chip->onfi_version == 0)
+               return MICRON_ON_DIE_UNSUPPORTED;
+
+       if (chip->bits_per_cell != 1)
+               return MICRON_ON_DIE_UNSUPPORTED;
+
+       ret = micron_nand_on_die_ecc_setup(chip, true);
+       if (ret)
+               return MICRON_ON_DIE_UNSUPPORTED;
+
+       chip->onfi_get_features(nand_to_mtd(chip), chip,
+                               ONFI_FEATURE_ON_DIE_ECC, feature);
+       if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0)
+               return MICRON_ON_DIE_UNSUPPORTED;
+
+       ret = micron_nand_on_die_ecc_setup(chip, false);
+       if (ret)
+               return MICRON_ON_DIE_UNSUPPORTED;
+
+       chip->onfi_get_features(nand_to_mtd(chip), chip,
+                               ONFI_FEATURE_ON_DIE_ECC, feature);
+       if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN)
+               return MICRON_ON_DIE_MANDATORY;
+
+       /*
+        * Some Micron NANDs have an on-die ECC of 4/512, some other
+        * 8/512. We only support the former.
+        */
+       if (chip->onfi_params.ecc_bits != 4)
+               return MICRON_ON_DIE_UNSUPPORTED;
+
+       return MICRON_ON_DIE_SUPPORTED;
+}
+
 static int micron_nand_init(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       int ondie;
        int ret;
 
        ret = micron_nand_onfi_init(chip);
@@ -78,6 +272,34 @@ static int micron_nand_init(struct nand_chip *chip)
        if (mtd->writesize == 2048)
                chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
 
+       ondie = micron_supports_on_die_ecc(chip);
+
+       if (ondie == MICRON_ON_DIE_MANDATORY) {
+               pr_err("On-die ECC forcefully enabled, not supported\n");
+               return -EINVAL;
+       }
+
+       if (chip->ecc.mode == NAND_ECC_ON_DIE) {
+               if (ondie == MICRON_ON_DIE_UNSUPPORTED) {
+                       pr_err("On-die ECC selected but not supported\n");
+                       return -EINVAL;
+               }
+
+               chip->ecc.options = NAND_ECC_CUSTOM_PAGE_ACCESS;
+               chip->ecc.bytes = 8;
+               chip->ecc.size = 512;
+               chip->ecc.strength = 4;
+               chip->ecc.algo = NAND_ECC_BCH;
+               chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
+               chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
+               chip->ecc.read_page_raw =
+                       micron_nand_read_page_raw_on_die_ecc;
+               chip->ecc.write_page_raw =
+                       micron_nand_write_page_raw_on_die_ecc;
+
+               mtd_set_ooblayout(mtd, &micron_nand_on_die_ooblayout_ops);
+       }
+
        return 0;
 }
 
index f8e463a..209170e 100644 (file)
@@ -166,7 +166,11 @@ static int __init orion_nand_probe(struct platform_device *pdev)
                }
        }
 
-       clk_prepare_enable(info->clk);
+       ret = clk_prepare_enable(info->clk);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to prepare clock!\n");
+               return ret;
+       }
 
        ret = nand_scan(mtd, 1);
        if (ret)
index 649ba82..74dae4b 100644 (file)
@@ -1812,6 +1812,8 @@ static int alloc_nand_resource(struct platform_device *pdev)
                chip->write_buf         = pxa3xx_nand_write_buf;
                chip->options           |= NAND_NO_SUBPAGE_WRITE;
                chip->cmdfunc           = nand_cmdfunc;
+               chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+               chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
        }
 
        nand_hw_control_init(chip->controller);
index 57d483a..88af714 100644 (file)
@@ -2008,6 +2008,8 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
        chip->read_byte         = qcom_nandc_read_byte;
        chip->read_buf          = qcom_nandc_read_buf;
        chip->write_buf         = qcom_nandc_write_buf;
+       chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+       chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
 
        /*
         * the bad block marker is readable only when we read the last codeword
index f0b030d..9e0c849 100644 (file)
@@ -812,9 +812,8 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
        return -ENODEV;
 }
 
-static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
-                                       const struct nand_data_interface *conf,
-                                       bool check_only)
+static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+                                       const struct nand_data_interface *conf)
 {
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
        struct s3c2410_platform_nand *pdata = info->platform;
index 442ce61..891ac7b 100644 (file)
@@ -1183,6 +1183,8 @@ static int flctl_probe(struct platform_device *pdev)
        nand->read_buf = flctl_read_buf;
        nand->select_chip = flctl_select_chip;
        nand->cmdfunc = flctl_cmdfunc;
+       nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
+       nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
 
        if (pdata->flcmncr_val & SEL_16BIT)
                nand->options |= NAND_BUSWIDTH_16;
index 118a26f..d0b6f8f 100644 (file)
@@ -1301,7 +1301,6 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
 
        sunxi_nfc_hw_ecc_enable(mtd);
 
-       chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
        for (i = data_offs / ecc->size;
             i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) {
                int data_off = i * ecc->size;
@@ -1592,9 +1591,8 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
 #define sunxi_nand_lookup_timing(l, p, c) \
                        _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
 
-static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd,
-                                       const struct nand_data_interface *conf,
-                                       bool check_only)
+static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
+                                       const struct nand_data_interface *conf)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
        struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
@@ -1707,7 +1705,7 @@ static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd,
                return tRHW;
        }
 
-       if (check_only)
+       if (csline == NAND_DATA_IFACE_CHECK_ONLY)
                return 0;
 
        /*
@@ -1922,7 +1920,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
        ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage;
        ecc->read_oob_raw = nand_read_oob_std;
        ecc->write_oob_raw = nand_write_oob_std;
-       ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
 
        return 0;
 }
index 49b286c..9d40b79 100644 (file)
@@ -303,7 +303,7 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                            const u8 *buf, int oob_required, int page)
 {
        struct tango_nfc *nfc = to_tango_nfc(chip->controller);
-       int err, len = mtd->writesize;
+       int err, status, len = mtd->writesize;
 
        /* Calling tango_write_oob() would send PAGEPROG twice */
        if (oob_required)
@@ -314,6 +314,10 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        if (err)
                return err;
 
+       status = chip->waitfunc(mtd, chip);
+       if (status & NAND_STATUS_FAIL)
+               return -EIO;
+
        return 0;
 }
 
@@ -340,7 +344,7 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
 
        if (!*buf) {
                /* skip over "len" bytes */
-               chip->cmdfunc(mtd, NAND_CMD_SEQIN, *pos, -1);
+               chip->cmdfunc(mtd, NAND_CMD_RNDIN, *pos, -1);
        } else {
                tango_write_buf(mtd, *buf, len);
                *buf += len;
@@ -431,9 +435,16 @@ static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
 static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
                                const u8 *buf, int oob_required, int page)
 {
+       int status;
+
        chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
        raw_write(chip, buf, chip->oob_poi);
        chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+       status = chip->waitfunc(mtd, chip);
+       if (status & NAND_STATUS_FAIL)
+               return -EIO;
+
        return 0;
 }
 
@@ -484,9 +495,8 @@ static u32 to_ticks(int kHz, int ps)
        return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
 }
 
-static int tango_set_timings(struct mtd_info *mtd,
-                            const struct nand_data_interface *conf,
-                            bool check_only)
+static int tango_set_timings(struct mtd_info *mtd, int csline,
+                            const struct nand_data_interface *conf)
 {
        const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
        struct nand_chip *chip = mtd_to_nand(mtd);
@@ -498,7 +508,7 @@ static int tango_set_timings(struct mtd_info *mtd,
        if (IS_ERR(sdr))
                return PTR_ERR(sdr);
 
-       if (check_only)
+       if (csline == NAND_DATA_IFACE_CHECK_ONLY)
                return 0;
 
        Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max);
index 3ea4bb1..744ab10 100644 (file)
@@ -703,6 +703,8 @@ static int vf610_nfc_probe(struct platform_device *pdev)
        chip->read_buf = vf610_nfc_read_buf;
        chip->write_buf = vf610_nfc_write_buf;
        chip->select_chip = vf610_nfc_select_chip;
+       chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+       chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
 
        chip->options |= NAND_NO_SUBPAGE_WRITE;
 
diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig
new file mode 100644 (file)
index 0000000..d206b3c
--- /dev/null
@@ -0,0 +1,8 @@
+config MTD_PARSER_TRX
+       tristate "Parser for TRX format partitions"
+       depends on MTD && (BCM47XX || ARCH_BCM_5301X || COMPILE_TEST)
+       help
+         TRX is a firmware format used by Broadcom on their devices. It
+         may contain up to 3/4 partitions (depending on the version).
+         This driver will parse TRX header and report at least two partitions:
+         kernel and rootfs.
diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile
new file mode 100644 (file)
index 0000000..4d9024e
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_MTD_PARSER_TRX)           += parser_trx.o
diff --git a/drivers/mtd/parsers/parser_trx.c b/drivers/mtd/parsers/parser_trx.c
new file mode 100644 (file)
index 0000000..df360a7
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Parser for TRX format partitions
+ *
+ * Copyright (C) 2012 - 2017 Rafał Miłecki <rafal@milecki.pl>
+ *
+ * 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/module.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#define TRX_PARSER_MAX_PARTS           4
+
+/* Magics */
+#define TRX_MAGIC                      0x30524448
+#define UBI_EC_MAGIC                   0x23494255      /* UBI# */
+
+struct trx_header {
+       uint32_t magic;
+       uint32_t length;
+       uint32_t crc32;
+       uint16_t flags;
+       uint16_t version;
+       uint32_t offset[3];
+} __packed;
+
+static const char *parser_trx_data_part_name(struct mtd_info *master,
+                                            size_t offset)
+{
+       uint32_t buf;
+       size_t bytes_read;
+       int err;
+
+       err  = mtd_read(master, offset, sizeof(buf), &bytes_read,
+                       (uint8_t *)&buf);
+       if (err && !mtd_is_bitflip(err)) {
+               pr_err("mtd_read error while parsing (offset: 0x%zX): %d\n",
+                       offset, err);
+               goto out_default;
+       }
+
+       if (buf == UBI_EC_MAGIC)
+               return "ubi";
+
+out_default:
+       return "rootfs";
+}
+
+static int parser_trx_parse(struct mtd_info *mtd,
+                           const struct mtd_partition **pparts,
+                           struct mtd_part_parser_data *data)
+{
+       struct mtd_partition *parts;
+       struct mtd_partition *part;
+       struct trx_header trx;
+       size_t bytes_read;
+       uint8_t curr_part = 0, i = 0;
+       int err;
+
+       parts = kzalloc(sizeof(struct mtd_partition) * TRX_PARSER_MAX_PARTS,
+                       GFP_KERNEL);
+       if (!parts)
+               return -ENOMEM;
+
+       err = mtd_read(mtd, 0, sizeof(trx), &bytes_read, (uint8_t *)&trx);
+       if (err) {
+               pr_err("MTD reading error: %d\n", err);
+               kfree(parts);
+               return err;
+       }
+
+       if (trx.magic != TRX_MAGIC) {
+               kfree(parts);
+               return -ENOENT;
+       }
+
+       /* We have LZMA loader if there is address in offset[2] */
+       if (trx.offset[2]) {
+               part = &parts[curr_part++];
+               part->name = "loader";
+               part->offset = trx.offset[i];
+               i++;
+       }
+
+       if (trx.offset[i]) {
+               part = &parts[curr_part++];
+               part->name = "linux";
+               part->offset = trx.offset[i];
+               i++;
+       }
+
+       if (trx.offset[i]) {
+               part = &parts[curr_part++];
+               part->name = parser_trx_data_part_name(mtd, trx.offset[i]);
+               part->offset = trx.offset[i];
+               i++;
+       }
+
+       /*
+        * Assume that every partition ends at the beginning of the one it is
+        * followed by.
+        */
+       for (i = 0; i < curr_part; i++) {
+               u64 next_part_offset = (i < curr_part - 1) ?
+                                      parts[i + 1].offset : mtd->size;
+
+               parts[i].size = next_part_offset - parts[i].offset;
+       }
+
+       *pparts = parts;
+       return i;
+};
+
+static struct mtd_part_parser mtd_parser_trx = {
+       .parse_fn = parser_trx_parse,
+       .name = "trx",
+};
+module_mtd_part_parser(mtd_parser_trx);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Parser for TRX format partitions");
index bfdfb1e..293c8a4 100644 (file)
@@ -108,7 +108,7 @@ config SPI_INTEL_SPI_PLATFORM
 
 config SPI_STM32_QUADSPI
        tristate "STM32 Quad SPI controller"
-       depends on ARCH_STM32
+       depends on ARCH_STM32 || COMPILE_TEST
        help
          This enables support for the STM32 Quad SPI controller.
          We only connect the NOR to this controller.
index 56051d3..0106357 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/spi-nor.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/sizes.h>
 #include <linux/sysfs.h>
 
 #define DEVICE_NAME    "aspeed-smc"
@@ -97,6 +98,7 @@ struct aspeed_smc_chip {
        struct aspeed_smc_controller *controller;
        void __iomem *ctl;                      /* control register */
        void __iomem *ahb_base;                 /* base of chip window */
+       u32 ahb_window_size;                    /* chip mapping window size */
        u32 ctl_val[smc_max];                   /* control settings */
        enum aspeed_smc_flash_type type;        /* what type of flash */
        struct spi_nor nor;
@@ -109,6 +111,7 @@ struct aspeed_smc_controller {
        const struct aspeed_smc_info *info;     /* type info of controller */
        void __iomem *regs;                     /* controller registers */
        void __iomem *ahb_base;                 /* per-chip windows resource */
+       u32 ahb_window_size;                    /* full mapping window size */
 
        struct aspeed_smc_chip *chips[0];       /* pointers to attached chips */
 };
@@ -180,8 +183,7 @@ struct aspeed_smc_controller {
 
 #define CONTROL_KEEP_MASK                                              \
        (CONTROL_AAF_MODE | CONTROL_CE_INACTIVE_MASK | CONTROL_CLK_DIV4 | \
-        CONTROL_IO_DUMMY_MASK | CONTROL_CLOCK_FREQ_SEL_MASK |          \
-        CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
+        CONTROL_CLOCK_FREQ_SEL_MASK | CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
 
 /*
  * The Segment Register uses a 8MB unit to encode the start address
@@ -194,6 +196,10 @@ struct aspeed_smc_controller {
 #define SEGMENT_ADDR_REG0              0x30
 #define SEGMENT_ADDR_START(_r)         ((((_r) >> 16) & 0xFF) << 23)
 #define SEGMENT_ADDR_END(_r)           ((((_r) >> 24) & 0xFF) << 23)
+#define SEGMENT_ADDR_VALUE(start, end)                                 \
+       (((((start) >> 23) & 0xFF) << 16) | ((((end) >> 23) & 0xFF) << 24))
+#define SEGMENT_ADDR_REG(controller, cs)       \
+       ((controller)->regs + SEGMENT_ADDR_REG0 + (cs) * 4)
 
 /*
  * In user mode all data bytes read or written to the chip decode address
@@ -439,8 +445,7 @@ static void __iomem *aspeed_smc_chip_base(struct aspeed_smc_chip *chip,
        u32 reg;
 
        if (controller->info->nce > 1) {
-               reg = readl(controller->regs + SEGMENT_ADDR_REG0 +
-                           chip->cs * 4);
+               reg = readl(SEGMENT_ADDR_REG(controller, chip->cs));
 
                if (SEGMENT_ADDR_START(reg) >= SEGMENT_ADDR_END(reg))
                        return NULL;
@@ -451,6 +456,146 @@ static void __iomem *aspeed_smc_chip_base(struct aspeed_smc_chip *chip,
        return controller->ahb_base + offset;
 }
 
+static u32 aspeed_smc_ahb_base_phy(struct aspeed_smc_controller *controller)
+{
+       u32 seg0_val = readl(SEGMENT_ADDR_REG(controller, 0));
+
+       return SEGMENT_ADDR_START(seg0_val);
+}
+
+static u32 chip_set_segment(struct aspeed_smc_chip *chip, u32 cs, u32 start,
+                           u32 size)
+{
+       struct aspeed_smc_controller *controller = chip->controller;
+       void __iomem *seg_reg;
+       u32 seg_oldval, seg_newval, ahb_base_phy, end;
+
+       ahb_base_phy = aspeed_smc_ahb_base_phy(controller);
+
+       seg_reg = SEGMENT_ADDR_REG(controller, cs);
+       seg_oldval = readl(seg_reg);
+
+       /*
+        * If the chip size is not specified, use the default segment
+        * size, but take into account the possible overlap with the
+        * previous segment
+        */
+       if (!size)
+               size = SEGMENT_ADDR_END(seg_oldval) - start;
+
+       /*
+        * The segment cannot exceed the maximum window size of the
+        * controller.
+        */
+       if (start + size > ahb_base_phy + controller->ahb_window_size) {
+               size = ahb_base_phy + controller->ahb_window_size - start;
+               dev_warn(chip->nor.dev, "CE%d window resized to %dMB",
+                        cs, size >> 20);
+       }
+
+       end = start + size;
+       seg_newval = SEGMENT_ADDR_VALUE(start, end);
+       writel(seg_newval, seg_reg);
+
+       /*
+        * Restore default value if something goes wrong. The chip
+        * might have set some bogus value and we would loose access
+        * to the chip.
+        */
+       if (seg_newval != readl(seg_reg)) {
+               dev_err(chip->nor.dev, "CE%d window invalid", cs);
+               writel(seg_oldval, seg_reg);
+               start = SEGMENT_ADDR_START(seg_oldval);
+               end = SEGMENT_ADDR_END(seg_oldval);
+               size = end - start;
+       }
+
+       dev_info(chip->nor.dev, "CE%d window [ 0x%.8x - 0x%.8x ] %dMB",
+                cs, start, end, size >> 20);
+
+       return size;
+}
+
+/*
+ * The segment register defines the mapping window on the AHB bus and
+ * it needs to be configured depending on the chip size. The segment
+ * register of the following CE also needs to be tuned in order to
+ * provide a contiguous window across multiple chips.
+ *
+ * This is expected to be called in increasing CE order
+ */
+static u32 aspeed_smc_chip_set_segment(struct aspeed_smc_chip *chip)
+{
+       struct aspeed_smc_controller *controller = chip->controller;
+       u32 ahb_base_phy, start;
+       u32 size = chip->nor.mtd.size;
+
+       /*
+        * Each controller has a chip size limit for direct memory
+        * access
+        */
+       if (size > controller->info->maxsize)
+               size = controller->info->maxsize;
+
+       /*
+        * The AST2400 SPI controller only handles one chip and does
+        * not have segment registers. Let's use the chip size for the
+        * AHB window.
+        */
+       if (controller->info == &spi_2400_info)
+               goto out;
+
+       /*
+        * The AST2500 SPI controller has a HW bug when the CE0 chip
+        * size reaches 128MB. Enforce a size limit of 120MB to
+        * prevent the controller from using bogus settings in the
+        * segment register.
+        */
+       if (chip->cs == 0 && controller->info == &spi_2500_info &&
+           size == SZ_128M) {
+               size = 120 << 20;
+               dev_info(chip->nor.dev,
+                        "CE%d window resized to %dMB (AST2500 HW quirk)",
+                        chip->cs, size >> 20);
+       }
+
+       ahb_base_phy = aspeed_smc_ahb_base_phy(controller);
+
+       /*
+        * As a start address for the current segment, use the default
+        * start address if we are handling CE0 or use the previous
+        * segment ending address
+        */
+       if (chip->cs) {
+               u32 prev = readl(SEGMENT_ADDR_REG(controller, chip->cs - 1));
+
+               start = SEGMENT_ADDR_END(prev);
+       } else {
+               start = ahb_base_phy;
+       }
+
+       size = chip_set_segment(chip, chip->cs, start, size);
+
+       /* Update chip base address on the AHB bus */
+       chip->ahb_base = controller->ahb_base + (start - ahb_base_phy);
+
+       /*
+        * Now, make sure the next segment does not overlap with the
+        * current one we just configured, even if there is no
+        * available chip. That could break access in Command Mode.
+        */
+       if (chip->cs < controller->info->nce - 1)
+               chip_set_segment(chip, chip->cs + 1, start + size, 0);
+
+out:
+       if (size < chip->nor.mtd.size)
+               dev_warn(chip->nor.dev,
+                        "CE%d window too small for chip %dMB",
+                        chip->cs, (u32)chip->nor.mtd.size >> 20);
+
+       return size;
+}
+
 static void aspeed_smc_chip_enable_write(struct aspeed_smc_chip *chip)
 {
        struct aspeed_smc_controller *controller = chip->controller;
@@ -524,7 +669,7 @@ static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
         */
        chip->ahb_base = aspeed_smc_chip_base(chip, res);
        if (!chip->ahb_base) {
-               dev_warn(chip->nor.dev, "CE segment window closed.\n");
+               dev_warn(chip->nor.dev, "CE%d window closed", chip->cs);
                return -EINVAL;
        }
 
@@ -571,6 +716,9 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
        if (chip->nor.addr_width == 4 && info->set_4b)
                info->set_4b(chip);
 
+       /* This is for direct AHB access when using Command Mode. */
+       chip->ahb_window_size = aspeed_smc_chip_set_segment(chip);
+
        /*
         * base mode has not been optimized yet. use it for writes.
         */
@@ -585,14 +733,12 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
         * TODO: Adjust clocks if fast read is supported and interpret
         * SPI-NOR flags to adjust controller settings.
         */
-       switch (chip->nor.flash_read) {
-       case SPI_NOR_NORMAL:
-               cmd = CONTROL_COMMAND_MODE_NORMAL;
-               break;
-       case SPI_NOR_FAST:
-               cmd = CONTROL_COMMAND_MODE_FREAD;
-               break;
-       default:
+       if (chip->nor.read_proto == SNOR_PROTO_1_1_1) {
+               if (chip->nor.read_dummy == 0)
+                       cmd = CONTROL_COMMAND_MODE_NORMAL;
+               else
+                       cmd = CONTROL_COMMAND_MODE_FREAD;
+       } else {
                dev_err(chip->nor.dev, "unsupported SPI read mode\n");
                return -EINVAL;
        }
@@ -608,6 +754,11 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
 static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
                                  struct device_node *np, struct resource *r)
 {
+       const struct spi_nor_hwcaps hwcaps = {
+               .mask = SNOR_HWCAPS_READ |
+                       SNOR_HWCAPS_READ_FAST |
+                       SNOR_HWCAPS_PP,
+       };
        const struct aspeed_smc_info *info = controller->info;
        struct device *dev = controller->dev;
        struct device_node *child;
@@ -671,11 +822,11 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
                        break;
 
                /*
-                * TODO: Add support for SPI_NOR_QUAD and SPI_NOR_DUAL
+                * TODO: Add support for Dual and Quad SPI protocols
                 * attach when board support is present as determined
                 * by of property.
                 */
-               ret = spi_nor_scan(nor, NULL, SPI_NOR_NORMAL);
+               ret = spi_nor_scan(nor, NULL, &hwcaps);
                if (ret)
                        break;
 
@@ -731,6 +882,8 @@ static int aspeed_smc_probe(struct platform_device *pdev)
        if (IS_ERR(controller->ahb_base))
                return PTR_ERR(controller->ahb_base);
 
+       controller->ahb_window_size = resource_size(res);
+
        ret = aspeed_smc_setup_flash(controller, np, res);
        if (ret)
                dev_err(dev, "Aspeed SMC probe failed %d\n", ret);
index 47937d9..ba76fa8 100644 (file)
@@ -275,14 +275,48 @@ static void atmel_qspi_debug_command(struct atmel_qspi *aq,
 
 static int atmel_qspi_run_command(struct atmel_qspi *aq,
                                  const struct atmel_qspi_command *cmd,
-                                 u32 ifr_tfrtyp, u32 ifr_width)
+                                 u32 ifr_tfrtyp, enum spi_nor_protocol proto)
 {
        u32 iar, icr, ifr, sr;
        int err = 0;
 
        iar = 0;
        icr = 0;
-       ifr = ifr_tfrtyp | ifr_width;
+       ifr = ifr_tfrtyp;
+
+       /* Set the SPI protocol */
+       switch (proto) {
+       case SNOR_PROTO_1_1_1:
+               ifr |= QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
+               break;
+
+       case SNOR_PROTO_1_1_2:
+               ifr |= QSPI_IFR_WIDTH_DUAL_OUTPUT;
+               break;
+
+       case SNOR_PROTO_1_1_4:
+               ifr |= QSPI_IFR_WIDTH_QUAD_OUTPUT;
+               break;
+
+       case SNOR_PROTO_1_2_2:
+               ifr |= QSPI_IFR_WIDTH_DUAL_IO;
+               break;
+
+       case SNOR_PROTO_1_4_4:
+               ifr |= QSPI_IFR_WIDTH_QUAD_IO;
+               break;
+
+       case SNOR_PROTO_2_2_2:
+               ifr |= QSPI_IFR_WIDTH_DUAL_CMD;
+               break;
+
+       case SNOR_PROTO_4_4_4:
+               ifr |= QSPI_IFR_WIDTH_QUAD_CMD;
+               break;
+
+       default:
+               return -EINVAL;
+       }
 
        /* Compute instruction parameters */
        if (cmd->enable.bits.instruction) {
@@ -434,7 +468,7 @@ static int atmel_qspi_read_reg(struct spi_nor *nor, u8 opcode,
        cmd.rx_buf = buf;
        cmd.buf_len = len;
        return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ,
-                                     QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+                                     nor->reg_proto);
 }
 
 static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
@@ -450,7 +484,7 @@ static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
        cmd.tx_buf = buf;
        cmd.buf_len = len;
        return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
-                                     QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+                                     nor->reg_proto);
 }
 
 static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
@@ -469,7 +503,7 @@ static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
        cmd.tx_buf = write_buf;
        cmd.buf_len = len;
        ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE_MEM,
-                                    QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+                                    nor->write_proto);
        return (ret < 0) ? ret : len;
 }
 
@@ -484,7 +518,7 @@ static int atmel_qspi_erase(struct spi_nor *nor, loff_t offs)
        cmd.instruction = nor->erase_opcode;
        cmd.address = (u32)offs;
        return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
-                                     QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+                                     nor->reg_proto);
 }
 
 static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
@@ -493,27 +527,8 @@ static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
        struct atmel_qspi *aq = nor->priv;
        struct atmel_qspi_command cmd;
        u8 num_mode_cycles, num_dummy_cycles;
-       u32 ifr_width;
        ssize_t ret;
 
-       switch (nor->flash_read) {
-       case SPI_NOR_NORMAL:
-       case SPI_NOR_FAST:
-               ifr_width = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
-               break;
-
-       case SPI_NOR_DUAL:
-               ifr_width = QSPI_IFR_WIDTH_DUAL_OUTPUT;
-               break;
-
-       case SPI_NOR_QUAD:
-               ifr_width = QSPI_IFR_WIDTH_QUAD_OUTPUT;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
        if (nor->read_dummy >= 2) {
                num_mode_cycles = 2;
                num_dummy_cycles = nor->read_dummy - 2;
@@ -536,7 +551,7 @@ static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
        cmd.rx_buf = read_buf;
        cmd.buf_len = len;
        ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ_MEM,
-                                    ifr_width);
+                                    nor->read_proto);
        return (ret < 0) ? ret : len;
 }
 
@@ -590,6 +605,20 @@ static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id)
 
 static int atmel_qspi_probe(struct platform_device *pdev)
 {
+       const struct spi_nor_hwcaps hwcaps = {
+               .mask = SNOR_HWCAPS_READ |
+                       SNOR_HWCAPS_READ_FAST |
+                       SNOR_HWCAPS_READ_1_1_2 |
+                       SNOR_HWCAPS_READ_1_2_2 |
+                       SNOR_HWCAPS_READ_2_2_2 |
+                       SNOR_HWCAPS_READ_1_1_4 |
+                       SNOR_HWCAPS_READ_1_4_4 |
+                       SNOR_HWCAPS_READ_4_4_4 |
+                       SNOR_HWCAPS_PP |
+                       SNOR_HWCAPS_PP_1_1_4 |
+                       SNOR_HWCAPS_PP_1_4_4 |
+                       SNOR_HWCAPS_PP_4_4_4,
+       };
        struct device_node *child, *np = pdev->dev.of_node;
        struct atmel_qspi *aq;
        struct resource *res;
@@ -679,7 +708,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
        if (err)
                goto disable_clk;
 
-       err = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+       err = spi_nor_scan(nor, NULL, &hwcaps);
        if (err)
                goto disable_clk;
 
index 9f8102d..53c7d8e 100644 (file)
@@ -855,15 +855,14 @@ static int cqspi_set_protocol(struct spi_nor *nor, const int read)
        f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
 
        if (read) {
-               switch (nor->flash_read) {
-               case SPI_NOR_NORMAL:
-               case SPI_NOR_FAST:
+               switch (nor->read_proto) {
+               case SNOR_PROTO_1_1_1:
                        f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
                        break;
-               case SPI_NOR_DUAL:
+               case SNOR_PROTO_1_1_2:
                        f_pdata->data_width = CQSPI_INST_TYPE_DUAL;
                        break;
-               case SPI_NOR_QUAD:
+               case SNOR_PROTO_1_1_4:
                        f_pdata->data_width = CQSPI_INST_TYPE_QUAD;
                        break;
                default:
@@ -1069,6 +1068,13 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
 
 static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
 {
+       const struct spi_nor_hwcaps hwcaps = {
+               .mask = SNOR_HWCAPS_READ |
+                       SNOR_HWCAPS_READ_FAST |
+                       SNOR_HWCAPS_READ_1_1_2 |
+                       SNOR_HWCAPS_READ_1_1_4 |
+                       SNOR_HWCAPS_PP,
+       };
        struct platform_device *pdev = cqspi->pdev;
        struct device *dev = &pdev->dev;
        struct cqspi_flash_pdata *f_pdata;
@@ -1123,7 +1129,7 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
                        goto err;
                }
 
-               ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+               ret = spi_nor_scan(nor, NULL, &hwcaps);
                if (ret)
                        goto err;
 
@@ -1277,7 +1283,7 @@ static const struct dev_pm_ops cqspi__dev_pm_ops = {
 #define CQSPI_DEV_PM_OPS       NULL
 #endif
 
-static struct of_device_id const cqspi_dt_ids[] = {
+static const struct of_device_id cqspi_dt_ids[] = {
        {.compatible = "cdns,qspi-nor",},
        { /* end of table */ }
 };
index 1476135..f17d224 100644 (file)
@@ -957,6 +957,10 @@ static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
 
 static int fsl_qspi_probe(struct platform_device *pdev)
 {
+       const struct spi_nor_hwcaps hwcaps = {
+               .mask = SNOR_HWCAPS_READ_1_1_4 |
+                       SNOR_HWCAPS_PP,
+       };
        struct device_node *np = pdev->dev.of_node;
        struct device *dev = &pdev->dev;
        struct fsl_qspi *q;
@@ -1065,7 +1069,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
                /* set the chip address for READID */
                fsl_qspi_set_base_addr(q, nor);
 
-               ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+               ret = spi_nor_scan(nor, NULL, &hwcaps);
                if (ret)
                        goto mutex_failed;
 
index a286350..d110683 100644 (file)
@@ -120,19 +120,24 @@ static inline int wait_op_finish(struct hifmc_host *host)
                (reg & FMC_INT_OP_DONE), 0, FMC_WAIT_TIMEOUT);
 }
 
-static int get_if_type(enum read_mode flash_read)
+static int get_if_type(enum spi_nor_protocol proto)
 {
        enum hifmc_iftype if_type;
 
-       switch (flash_read) {
-       case SPI_NOR_DUAL:
+       switch (proto) {
+       case SNOR_PROTO_1_1_2:
                if_type = IF_TYPE_DUAL;
                break;
-       case SPI_NOR_QUAD:
+       case SNOR_PROTO_1_2_2:
+               if_type = IF_TYPE_DIO;
+               break;
+       case SNOR_PROTO_1_1_4:
                if_type = IF_TYPE_QUAD;
                break;
-       case SPI_NOR_NORMAL:
-       case SPI_NOR_FAST:
+       case SNOR_PROTO_1_4_4:
+               if_type = IF_TYPE_QIO;
+               break;
+       case SNOR_PROTO_1_1_1:
        default:
                if_type = IF_TYPE_STD;
                break;
@@ -253,7 +258,10 @@ static int hisi_spi_nor_dma_transfer(struct spi_nor *nor, loff_t start_off,
        writel(FMC_DMA_LEN_SET(len), host->regbase + FMC_DMA_LEN);
 
        reg = OP_CFG_FM_CS(priv->chipselect);
-       if_type = get_if_type(nor->flash_read);
+       if (op_type == FMC_OP_READ)
+               if_type = get_if_type(nor->read_proto);
+       else
+               if_type = get_if_type(nor->write_proto);
        reg |= OP_CFG_MEM_IF_TYPE(if_type);
        if (op_type == FMC_OP_READ)
                reg |= OP_CFG_DUMMY_NUM(nor->read_dummy >> 3);
@@ -321,6 +329,13 @@ static ssize_t hisi_spi_nor_write(struct spi_nor *nor, loff_t to,
 static int hisi_spi_nor_register(struct device_node *np,
                                struct hifmc_host *host)
 {
+       const struct spi_nor_hwcaps hwcaps = {
+               .mask = SNOR_HWCAPS_READ |
+                       SNOR_HWCAPS_READ_FAST |
+                       SNOR_HWCAPS_READ_1_1_2 |
+                       SNOR_HWCAPS_READ_1_1_4 |
+                       SNOR_HWCAPS_PP,
+       };
        struct device *dev = host->dev;
        struct spi_nor *nor;
        struct hifmc_priv *priv;
@@ -362,7 +377,7 @@ static int hisi_spi_nor_register(struct device_node *np,
        nor->read = hisi_spi_nor_read;
        nor->write = hisi_spi_nor_write;
        nor->erase = NULL;
-       ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+       ret = spi_nor_scan(nor, NULL, &hwcaps);
        if (ret)
                return ret;
 
index 986a3d0..8a596bf 100644 (file)
@@ -715,6 +715,11 @@ static void intel_spi_fill_partition(struct intel_spi *ispi,
 struct intel_spi *intel_spi_probe(struct device *dev,
        struct resource *mem, const struct intel_spi_boardinfo *info)
 {
+       const struct spi_nor_hwcaps hwcaps = {
+               .mask = SNOR_HWCAPS_READ |
+                       SNOR_HWCAPS_READ_FAST |
+                       SNOR_HWCAPS_PP,
+       };
        struct mtd_partition part;
        struct intel_spi *ispi;
        int ret;
@@ -746,7 +751,7 @@ struct intel_spi *intel_spi_probe(struct device *dev,
        ispi->nor.write = intel_spi_write;
        ispi->nor.erase = intel_spi_erase;
 
-       ret = spi_nor_scan(&ispi->nor, NULL, SPI_NOR_NORMAL);
+       ret = spi_nor_scan(&ispi->nor, NULL, &hwcaps);
        if (ret) {
                dev_info(dev, "failed to locate the chip\n");
                return ERR_PTR(ret);
index b637770..8a20ec4 100644 (file)
@@ -123,20 +123,20 @@ static void mt8173_nor_set_read_mode(struct mt8173_nor *mt8173_nor)
 {
        struct spi_nor *nor = &mt8173_nor->nor;
 
-       switch (nor->flash_read) {
-       case SPI_NOR_FAST:
+       switch (nor->read_proto) {
+       case SNOR_PROTO_1_1_1:
                writeb(nor->read_opcode, mt8173_nor->base +
                       MTK_NOR_PRGDATA3_REG);
                writeb(MTK_NOR_FAST_READ, mt8173_nor->base +
                       MTK_NOR_CFG1_REG);
                break;
-       case SPI_NOR_DUAL:
+       case SNOR_PROTO_1_1_2:
                writeb(nor->read_opcode, mt8173_nor->base +
                       MTK_NOR_PRGDATA3_REG);
                writeb(MTK_NOR_DUAL_READ_EN, mt8173_nor->base +
                       MTK_NOR_DUAL_REG);
                break;
-       case SPI_NOR_QUAD:
+       case SNOR_PROTO_1_1_4:
                writeb(nor->read_opcode, mt8173_nor->base +
                       MTK_NOR_PRGDATA4_REG);
                writeb(MTK_NOR_QUAD_READ_EN, mt8173_nor->base +
@@ -408,6 +408,11 @@ static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
 static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
                        struct device_node *flash_node)
 {
+       const struct spi_nor_hwcaps hwcaps = {
+               .mask = SNOR_HWCAPS_READ_FAST |
+                       SNOR_HWCAPS_READ_1_1_2 |
+                       SNOR_HWCAPS_PP,
+       };
        int ret;
        struct spi_nor *nor;
 
@@ -426,7 +431,7 @@ static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
        nor->write_reg = mt8173_nor_write_reg;
        nor->mtd.name = "mtk_nor";
        /* initialized with NULL */
-       ret = spi_nor_scan(nor, NULL, SPI_NOR_DUAL);
+       ret = spi_nor_scan(nor, NULL, &hwcaps);
        if (ret)
                return ret;
 
index 73a14f4..1537421 100644 (file)
@@ -240,13 +240,12 @@ static int nxp_spifi_erase(struct spi_nor *nor, loff_t offs)
 
 static int nxp_spifi_setup_memory_cmd(struct nxp_spifi *spifi)
 {
-       switch (spifi->nor.flash_read) {
-       case SPI_NOR_NORMAL:
-       case SPI_NOR_FAST:
+       switch (spifi->nor.read_proto) {
+       case SNOR_PROTO_1_1_1:
                spifi->mcmd = SPIFI_CMD_FIELDFORM_ALL_SERIAL;
                break;
-       case SPI_NOR_DUAL:
-       case SPI_NOR_QUAD:
+       case SNOR_PROTO_1_1_2:
+       case SNOR_PROTO_1_1_4:
                spifi->mcmd = SPIFI_CMD_FIELDFORM_QUAD_DUAL_DATA;
                break;
        default:
@@ -274,7 +273,11 @@ static void nxp_spifi_dummy_id_read(struct spi_nor *nor)
 static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
                                 struct device_node *np)
 {
-       enum read_mode flash_read;
+       struct spi_nor_hwcaps hwcaps = {
+               .mask = SNOR_HWCAPS_READ |
+                       SNOR_HWCAPS_READ_FAST |
+                       SNOR_HWCAPS_PP,
+       };
        u32 ctrl, property;
        u16 mode = 0;
        int ret;
@@ -308,13 +311,12 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
 
        if (mode & SPI_RX_DUAL) {
                ctrl |= SPIFI_CTRL_DUAL;
-               flash_read = SPI_NOR_DUAL;
+               hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
        } else if (mode & SPI_RX_QUAD) {
                ctrl &= ~SPIFI_CTRL_DUAL;
-               flash_read = SPI_NOR_QUAD;
+               hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
        } else {
                ctrl |= SPIFI_CTRL_DUAL;
-               flash_read = SPI_NOR_NORMAL;
        }
 
        switch (mode & (SPI_CPHA | SPI_CPOL)) {
@@ -351,7 +353,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
         */
        nxp_spifi_dummy_id_read(&spifi->nor);
 
-       ret = spi_nor_scan(&spifi->nor, NULL, flash_read);
+       ret = spi_nor_scan(&spifi->nor, NULL, &hwcaps);
        if (ret) {
                dev_err(spifi->dev, "device scan failed\n");
                return ret;
index dea8c9c..1413828 100644 (file)
@@ -150,24 +150,6 @@ static int read_cr(struct spi_nor *nor)
 }
 
 /*
- * Dummy Cycle calculation for different type of read.
- * It can be used to support more commands with
- * different dummy cycle requirements.
- */
-static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
-{
-       switch (nor->flash_read) {
-       case SPI_NOR_FAST:
-       case SPI_NOR_DUAL:
-       case SPI_NOR_QUAD:
-               return 8;
-       case SPI_NOR_NORMAL:
-               return 0;
-       }
-       return 0;
-}
-
-/*
  * Write status register 1 byte
  * Returns negative if error occurred.
  */
@@ -221,6 +203,10 @@ static inline u8 spi_nor_convert_3to4_read(u8 opcode)
                { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B },
                { SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B },
                { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B },
+
+               { SPINOR_OP_READ_1_1_1_DTR,     SPINOR_OP_READ_1_1_1_DTR_4B },
+               { SPINOR_OP_READ_1_2_2_DTR,     SPINOR_OP_READ_1_2_2_DTR_4B },
+               { SPINOR_OP_READ_1_4_4_DTR,     SPINOR_OP_READ_1_4_4_DTR_4B },
        };
 
        return spi_nor_convert_opcode(opcode, spi_nor_3to4_read,
@@ -1022,10 +1008,12 @@ static const struct flash_info spi_nor_ids[] = {
        { "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
        { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
        { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
-       { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
+       { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
        { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
-       { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
+       { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "mx66u51235f", INFO(0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+       { "mx66l1g45g",  INFO(0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
 
        /* Micron */
@@ -1036,7 +1024,7 @@ static const struct flash_info spi_nor_ids[] = {
        { "n25q064a",    INFO(0x20bb17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
        { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
        { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
-       { "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
+       { "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "n25q256ax1",  INFO(0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
        { "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
        { "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
@@ -1076,6 +1064,7 @@ static const struct flash_info spi_nor_ids[] = {
        { "s25fl164k",  INFO(0x014017,      0,  64 * 1024, 128, SECT_4K) },
        { "s25fl204k",  INFO(0x014013,      0,  64 * 1024,   8, SECT_4K | SPI_NOR_DUAL_READ) },
        { "s25fl208k",  INFO(0x014014,      0,  64 * 1024,  16, SECT_4K | SPI_NOR_DUAL_READ) },
+       { "s25fl064l",  INFO(0x016017,      0,  64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
 
        /* SST -- large erase sizes are "overlays", "sectors" are 4K */
        { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
@@ -1159,7 +1148,9 @@ static const struct flash_info spi_nor_ids[] = {
        { "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
-       { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
+       { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024,
+                       SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) },
 
        /* Catalyst / On Semiconductor -- non-JEDEC */
        { "cat25c11", CAT25_INFO(  16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
@@ -1403,8 +1394,9 @@ static int macronix_quad_enable(struct spi_nor *nor)
 
        write_sr(nor, val | SR_QUAD_EN_MX);
 
-       if (spi_nor_wait_till_ready(nor))
-               return 1;
+       ret = spi_nor_wait_till_ready(nor);
+       if (ret)
+               return ret;
 
        ret = read_sr(nor);
        if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
@@ -1460,30 +1452,6 @@ static int spansion_quad_enable(struct spi_nor *nor)
        return 0;
 }
 
-static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
-{
-       int status;
-
-       switch (JEDEC_MFR(info)) {
-       case SNOR_MFR_MACRONIX:
-               status = macronix_quad_enable(nor);
-               if (status) {
-                       dev_err(nor->dev, "Macronix quad-read not enabled\n");
-                       return -EINVAL;
-               }
-               return status;
-       case SNOR_MFR_MICRON:
-               return 0;
-       default:
-               status = spansion_quad_enable(nor);
-               if (status) {
-                       dev_err(nor->dev, "Spansion quad-read not enabled\n");
-                       return -EINVAL;
-               }
-               return status;
-       }
-}
-
 static int spi_nor_check(struct spi_nor *nor)
 {
        if (!nor->dev || !nor->read || !nor->write ||
@@ -1536,8 +1504,349 @@ static int s3an_nor_scan(const struct flash_info *info, struct spi_nor *nor)
        return 0;
 }
 
-int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+struct spi_nor_read_command {
+       u8                      num_mode_clocks;
+       u8                      num_wait_states;
+       u8                      opcode;
+       enum spi_nor_protocol   proto;
+};
+
+struct spi_nor_pp_command {
+       u8                      opcode;
+       enum spi_nor_protocol   proto;
+};
+
+enum spi_nor_read_command_index {
+       SNOR_CMD_READ,
+       SNOR_CMD_READ_FAST,
+       SNOR_CMD_READ_1_1_1_DTR,
+
+       /* Dual SPI */
+       SNOR_CMD_READ_1_1_2,
+       SNOR_CMD_READ_1_2_2,
+       SNOR_CMD_READ_2_2_2,
+       SNOR_CMD_READ_1_2_2_DTR,
+
+       /* Quad SPI */
+       SNOR_CMD_READ_1_1_4,
+       SNOR_CMD_READ_1_4_4,
+       SNOR_CMD_READ_4_4_4,
+       SNOR_CMD_READ_1_4_4_DTR,
+
+       /* Octo SPI */
+       SNOR_CMD_READ_1_1_8,
+       SNOR_CMD_READ_1_8_8,
+       SNOR_CMD_READ_8_8_8,
+       SNOR_CMD_READ_1_8_8_DTR,
+
+       SNOR_CMD_READ_MAX
+};
+
+enum spi_nor_pp_command_index {
+       SNOR_CMD_PP,
+
+       /* Quad SPI */
+       SNOR_CMD_PP_1_1_4,
+       SNOR_CMD_PP_1_4_4,
+       SNOR_CMD_PP_4_4_4,
+
+       /* Octo SPI */
+       SNOR_CMD_PP_1_1_8,
+       SNOR_CMD_PP_1_8_8,
+       SNOR_CMD_PP_8_8_8,
+
+       SNOR_CMD_PP_MAX
+};
+
+struct spi_nor_flash_parameter {
+       u64                             size;
+       u32                             page_size;
+
+       struct spi_nor_hwcaps           hwcaps;
+       struct spi_nor_read_command     reads[SNOR_CMD_READ_MAX];
+       struct spi_nor_pp_command       page_programs[SNOR_CMD_PP_MAX];
+
+       int (*quad_enable)(struct spi_nor *nor);
+};
+
+static void
+spi_nor_set_read_settings(struct spi_nor_read_command *read,
+                         u8 num_mode_clocks,
+                         u8 num_wait_states,
+                         u8 opcode,
+                         enum spi_nor_protocol proto)
 {
+       read->num_mode_clocks = num_mode_clocks;
+       read->num_wait_states = num_wait_states;
+       read->opcode = opcode;
+       read->proto = proto;
+}
+
+static void
+spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
+                       u8 opcode,
+                       enum spi_nor_protocol proto)
+{
+       pp->opcode = opcode;
+       pp->proto = proto;
+}
+
+static int spi_nor_init_params(struct spi_nor *nor,
+                              const struct flash_info *info,
+                              struct spi_nor_flash_parameter *params)
+{
+       /* Set legacy flash parameters as default. */
+       memset(params, 0, sizeof(*params));
+
+       /* Set SPI NOR sizes. */
+       params->size = info->sector_size * info->n_sectors;
+       params->page_size = info->page_size;
+
+       /* (Fast) Read settings. */
+       params->hwcaps.mask |= SNOR_HWCAPS_READ;
+       spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ],
+                                 0, 0, SPINOR_OP_READ,
+                                 SNOR_PROTO_1_1_1);
+
+       if (!(info->flags & SPI_NOR_NO_FR)) {
+               params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
+               spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_FAST],
+                                         0, 8, SPINOR_OP_READ_FAST,
+                                         SNOR_PROTO_1_1_1);
+       }
+
+       if (info->flags & SPI_NOR_DUAL_READ) {
+               params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
+               spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_1_1_2],
+                                         0, 8, SPINOR_OP_READ_1_1_2,
+                                         SNOR_PROTO_1_1_2);
+       }
+
+       if (info->flags & SPI_NOR_QUAD_READ) {
+               params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
+               spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_1_1_4],
+                                         0, 8, SPINOR_OP_READ_1_1_4,
+                                         SNOR_PROTO_1_1_4);
+       }
+
+       /* Page Program settings. */
+       params->hwcaps.mask |= SNOR_HWCAPS_PP;
+       spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
+                               SPINOR_OP_PP, SNOR_PROTO_1_1_1);
+
+       /* Select the procedure to set the Quad Enable bit. */
+       if (params->hwcaps.mask & (SNOR_HWCAPS_READ_QUAD |
+                                  SNOR_HWCAPS_PP_QUAD)) {
+               switch (JEDEC_MFR(info)) {
+               case SNOR_MFR_MACRONIX:
+                       params->quad_enable = macronix_quad_enable;
+                       break;
+
+               case SNOR_MFR_MICRON:
+                       break;
+
+               default:
+                       params->quad_enable = spansion_quad_enable;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int spi_nor_hwcaps2cmd(u32 hwcaps, const int table[][2], size_t size)
+{
+       size_t i;
+
+       for (i = 0; i < size; i++)
+               if (table[i][0] == (int)hwcaps)
+                       return table[i][1];
+
+       return -EINVAL;
+}
+
+static int spi_nor_hwcaps_read2cmd(u32 hwcaps)
+{
+       static const int hwcaps_read2cmd[][2] = {
+               { SNOR_HWCAPS_READ,             SNOR_CMD_READ },
+               { SNOR_HWCAPS_READ_FAST,        SNOR_CMD_READ_FAST },
+               { SNOR_HWCAPS_READ_1_1_1_DTR,   SNOR_CMD_READ_1_1_1_DTR },
+               { SNOR_HWCAPS_READ_1_1_2,       SNOR_CMD_READ_1_1_2 },
+               { SNOR_HWCAPS_READ_1_2_2,       SNOR_CMD_READ_1_2_2 },
+               { SNOR_HWCAPS_READ_2_2_2,       SNOR_CMD_READ_2_2_2 },
+               { SNOR_HWCAPS_READ_1_2_2_DTR,   SNOR_CMD_READ_1_2_2_DTR },
+               { SNOR_HWCAPS_READ_1_1_4,       SNOR_CMD_READ_1_1_4 },
+               { SNOR_HWCAPS_READ_1_4_4,       SNOR_CMD_READ_1_4_4 },
+               { SNOR_HWCAPS_READ_4_4_4,       SNOR_CMD_READ_4_4_4 },
+               { SNOR_HWCAPS_READ_1_4_4_DTR,   SNOR_CMD_READ_1_4_4_DTR },
+               { SNOR_HWCAPS_READ_1_1_8,       SNOR_CMD_READ_1_1_8 },
+               { SNOR_HWCAPS_READ_1_8_8,       SNOR_CMD_READ_1_8_8 },
+               { SNOR_HWCAPS_READ_8_8_8,       SNOR_CMD_READ_8_8_8 },
+               { SNOR_HWCAPS_READ_1_8_8_DTR,   SNOR_CMD_READ_1_8_8_DTR },
+       };
+
+       return spi_nor_hwcaps2cmd(hwcaps, hwcaps_read2cmd,
+                                 ARRAY_SIZE(hwcaps_read2cmd));
+}
+
+static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
+{
+       static const int hwcaps_pp2cmd[][2] = {
+               { SNOR_HWCAPS_PP,               SNOR_CMD_PP },
+               { SNOR_HWCAPS_PP_1_1_4,         SNOR_CMD_PP_1_1_4 },
+               { SNOR_HWCAPS_PP_1_4_4,         SNOR_CMD_PP_1_4_4 },
+               { SNOR_HWCAPS_PP_4_4_4,         SNOR_CMD_PP_4_4_4 },
+               { SNOR_HWCAPS_PP_1_1_8,         SNOR_CMD_PP_1_1_8 },
+               { SNOR_HWCAPS_PP_1_8_8,         SNOR_CMD_PP_1_8_8 },
+               { SNOR_HWCAPS_PP_8_8_8,         SNOR_CMD_PP_8_8_8 },
+       };
+
+       return spi_nor_hwcaps2cmd(hwcaps, hwcaps_pp2cmd,
+                                 ARRAY_SIZE(hwcaps_pp2cmd));
+}
+
+static int spi_nor_select_read(struct spi_nor *nor,
+                              const struct spi_nor_flash_parameter *params,
+                              u32 shared_hwcaps)
+{
+       int cmd, best_match = fls(shared_hwcaps & SNOR_HWCAPS_READ_MASK) - 1;
+       const struct spi_nor_read_command *read;
+
+       if (best_match < 0)
+               return -EINVAL;
+
+       cmd = spi_nor_hwcaps_read2cmd(BIT(best_match));
+       if (cmd < 0)
+               return -EINVAL;
+
+       read = &params->reads[cmd];
+       nor->read_opcode = read->opcode;
+       nor->read_proto = read->proto;
+
+       /*
+        * In the spi-nor framework, we don't need to make the difference
+        * between mode clock cycles and wait state clock cycles.
+        * Indeed, the value of the mode clock cycles is used by a QSPI
+        * flash memory to know whether it should enter or leave its 0-4-4
+        * (Continuous Read / XIP) mode.
+        * eXecution In Place is out of the scope of the mtd sub-system.
+        * Hence we choose to merge both mode and wait state clock cycles
+        * into the so called dummy clock cycles.
+        */
+       nor->read_dummy = read->num_mode_clocks + read->num_wait_states;
+       return 0;
+}
+
+static int spi_nor_select_pp(struct spi_nor *nor,
+                            const struct spi_nor_flash_parameter *params,
+                            u32 shared_hwcaps)
+{
+       int cmd, best_match = fls(shared_hwcaps & SNOR_HWCAPS_PP_MASK) - 1;
+       const struct spi_nor_pp_command *pp;
+
+       if (best_match < 0)
+               return -EINVAL;
+
+       cmd = spi_nor_hwcaps_pp2cmd(BIT(best_match));
+       if (cmd < 0)
+               return -EINVAL;
+
+       pp = &params->page_programs[cmd];
+       nor->program_opcode = pp->opcode;
+       nor->write_proto = pp->proto;
+       return 0;
+}
+
+static int spi_nor_select_erase(struct spi_nor *nor,
+                               const struct flash_info *info)
+{
+       struct mtd_info *mtd = &nor->mtd;
+
+#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
+       /* prefer "small sector" erase if possible */
+       if (info->flags & SECT_4K) {
+               nor->erase_opcode = SPINOR_OP_BE_4K;
+               mtd->erasesize = 4096;
+       } else if (info->flags & SECT_4K_PMC) {
+               nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
+               mtd->erasesize = 4096;
+       } else
+#endif
+       {
+               nor->erase_opcode = SPINOR_OP_SE;
+               mtd->erasesize = info->sector_size;
+       }
+       return 0;
+}
+
+static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
+                        const struct spi_nor_flash_parameter *params,
+                        const struct spi_nor_hwcaps *hwcaps)
+{
+       u32 ignored_mask, shared_mask;
+       bool enable_quad_io;
+       int err;
+
+       /*
+        * Keep only the hardware capabilities supported by both the SPI
+        * controller and the SPI flash memory.
+        */
+       shared_mask = hwcaps->mask & params->hwcaps.mask;
+
+       /* SPI n-n-n protocols are not supported yet. */
+       ignored_mask = (SNOR_HWCAPS_READ_2_2_2 |
+                       SNOR_HWCAPS_READ_4_4_4 |
+                       SNOR_HWCAPS_READ_8_8_8 |
+                       SNOR_HWCAPS_PP_4_4_4 |
+                       SNOR_HWCAPS_PP_8_8_8);
+       if (shared_mask & ignored_mask) {
+               dev_dbg(nor->dev,
+                       "SPI n-n-n protocols are not supported yet.\n");
+               shared_mask &= ~ignored_mask;
+       }
+
+       /* Select the (Fast) Read command. */
+       err = spi_nor_select_read(nor, params, shared_mask);
+       if (err) {
+               dev_err(nor->dev,
+                       "can't select read settings supported by both the SPI controller and memory.\n");
+               return err;
+       }
+
+       /* Select the Page Program command. */
+       err = spi_nor_select_pp(nor, params, shared_mask);
+       if (err) {
+               dev_err(nor->dev,
+                       "can't select write settings supported by both the SPI controller and memory.\n");
+               return err;
+       }
+
+       /* Select the Sector Erase command. */
+       err = spi_nor_select_erase(nor, info);
+       if (err) {
+               dev_err(nor->dev,
+                       "can't select erase settings supported by both the SPI controller and memory.\n");
+               return err;
+       }
+
+       /* Enable Quad I/O if needed. */
+       enable_quad_io = (spi_nor_get_protocol_width(nor->read_proto) == 4 ||
+                         spi_nor_get_protocol_width(nor->write_proto) == 4);
+       if (enable_quad_io && params->quad_enable) {
+               err = params->quad_enable(nor);
+               if (err) {
+                       dev_err(nor->dev, "quad mode not supported\n");
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+int spi_nor_scan(struct spi_nor *nor, const char *name,
+                const struct spi_nor_hwcaps *hwcaps)
+{
+       struct spi_nor_flash_parameter params;
        const struct flash_info *info = NULL;
        struct device *dev = nor->dev;
        struct mtd_info *mtd = &nor->mtd;
@@ -1549,6 +1858,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
        if (ret)
                return ret;
 
+       /* Reset SPI protocol for all commands. */
+       nor->reg_proto = SNOR_PROTO_1_1_1;
+       nor->read_proto = SNOR_PROTO_1_1_1;
+       nor->write_proto = SNOR_PROTO_1_1_1;
+
        if (name)
                info = spi_nor_match_id(name);
        /* Try to auto-detect if chip name wasn't specified or not found */
@@ -1591,6 +1905,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
        if (info->flags & SPI_S3AN)
                nor->flags |=  SNOR_F_READY_XSR_RDY;
 
+       /* Parse the Serial Flash Discoverable Parameters table. */
+       ret = spi_nor_init_params(nor, info, &params);
+       if (ret)
+               return ret;
+
        /*
         * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
         * with the software protection bits set
@@ -1611,7 +1930,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
        mtd->type = MTD_NORFLASH;
        mtd->writesize = 1;
        mtd->flags = MTD_CAP_NORFLASH;
-       mtd->size = info->sector_size * info->n_sectors;
+       mtd->size = params.size;
        mtd->_erase = spi_nor_erase;
        mtd->_read = spi_nor_read;
 
@@ -1642,75 +1961,38 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
        if (info->flags & NO_CHIP_ERASE)
                nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
 
-#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
-       /* prefer "small sector" erase if possible */
-       if (info->flags & SECT_4K) {
-               nor->erase_opcode = SPINOR_OP_BE_4K;
-               mtd->erasesize = 4096;
-       } else if (info->flags & SECT_4K_PMC) {
-               nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
-               mtd->erasesize = 4096;
-       } else
-#endif
-       {
-               nor->erase_opcode = SPINOR_OP_SE;
-               mtd->erasesize = info->sector_size;
-       }
-
        if (info->flags & SPI_NOR_NO_ERASE)
                mtd->flags |= MTD_NO_ERASE;
 
        mtd->dev.parent = dev;
-       nor->page_size = info->page_size;
+       nor->page_size = params.page_size;
        mtd->writebufsize = nor->page_size;
 
        if (np) {
                /* If we were instantiated by DT, use it */
                if (of_property_read_bool(np, "m25p,fast-read"))
-                       nor->flash_read = SPI_NOR_FAST;
+                       params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
                else
-                       nor->flash_read = SPI_NOR_NORMAL;
+                       params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
        } else {
                /* If we weren't instantiated by DT, default to fast-read */
-               nor->flash_read = SPI_NOR_FAST;
+               params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
        }
 
        /* Some devices cannot do fast-read, no matter what DT tells us */
        if (info->flags & SPI_NOR_NO_FR)
-               nor->flash_read = SPI_NOR_NORMAL;
-
-       /* Quad/Dual-read mode takes precedence over fast/normal */
-       if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
-               ret = set_quad_mode(nor, info);
-               if (ret) {
-                       dev_err(dev, "quad mode not supported\n");
-                       return ret;
-               }
-               nor->flash_read = SPI_NOR_QUAD;
-       } else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) {
-               nor->flash_read = SPI_NOR_DUAL;
-       }
-
-       /* Default commands */
-       switch (nor->flash_read) {
-       case SPI_NOR_QUAD:
-               nor->read_opcode = SPINOR_OP_READ_1_1_4;
-               break;
-       case SPI_NOR_DUAL:
-               nor->read_opcode = SPINOR_OP_READ_1_1_2;
-               break;
-       case SPI_NOR_FAST:
-               nor->read_opcode = SPINOR_OP_READ_FAST;
-               break;
-       case SPI_NOR_NORMAL:
-               nor->read_opcode = SPINOR_OP_READ;
-               break;
-       default:
-               dev_err(dev, "No Read opcode defined\n");
-               return -EINVAL;
-       }
+               params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
 
-       nor->program_opcode = SPINOR_OP_PP;
+       /*
+        * Configure the SPI memory:
+        * - select op codes for (Fast) Read, Page Program and Sector Erase.
+        * - set the number of dummy cycles (mode cycles + wait states).
+        * - set the SPI protocols for register and memory accesses.
+        * - set the Quad Enable bit if needed (required by SPI x-y-4 protos).
+        */
+       ret = spi_nor_setup(nor, info, &params, hwcaps);
+       if (ret)
+               return ret;
 
        if (info->addr_width)
                nor->addr_width = info->addr_width;
@@ -1732,8 +2014,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
                return -EINVAL;
        }
 
-       nor->read_dummy = spi_nor_read_dummy_cycles(nor);
-
        if (info->flags & SPI_S3AN) {
                ret = s3an_nor_scan(info, nor);
                if (ret)
index ae45f81..86c0931 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/reset.h>
+#include <linux/sizes.h>
 
 #define QUADSPI_CR             0x00
 #define CR_EN                  BIT(0)
@@ -192,15 +193,15 @@ static void stm32_qspi_set_framemode(struct spi_nor *nor,
        cmd->framemode = CCR_IMODE_1;
 
        if (read) {
-               switch (nor->flash_read) {
-               case SPI_NOR_NORMAL:
-               case SPI_NOR_FAST:
+               switch (nor->read_proto) {
+               default:
+               case SNOR_PROTO_1_1_1:
                        dmode = CCR_DMODE_1;
                        break;
-               case SPI_NOR_DUAL:
+               case SNOR_PROTO_1_1_2:
                        dmode = CCR_DMODE_2;
                        break;
-               case SPI_NOR_QUAD:
+               case SNOR_PROTO_1_1_4:
                        dmode = CCR_DMODE_4;
                        break;
                }
@@ -375,7 +376,7 @@ static ssize_t stm32_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
        struct stm32_qspi_cmd cmd;
        int err;
 
-       dev_dbg(qspi->dev, "read(%#.2x): buf:%p from:%#.8x len:%#x\n",
+       dev_dbg(qspi->dev, "read(%#.2x): buf:%p from:%#.8x len:%#zx\n",
                nor->read_opcode, buf, (u32)from, len);
 
        memset(&cmd, 0, sizeof(cmd));
@@ -402,7 +403,7 @@ static ssize_t stm32_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
        struct stm32_qspi_cmd cmd;
        int err;
 
-       dev_dbg(dev, "write(%#.2x): buf:%p to:%#.8x len:%#x\n",
+       dev_dbg(dev, "write(%#.2x): buf:%p to:%#.8x len:%#zx\n",
                nor->program_opcode, buf, (u32)to, len);
 
        memset(&cmd, 0, sizeof(cmd));
@@ -480,7 +481,12 @@ static void stm32_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
 static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
                                  struct device_node *np)
 {
-       u32 width, flash_read, presc, cs_num, max_rate = 0;
+       struct spi_nor_hwcaps hwcaps = {
+               .mask = SNOR_HWCAPS_READ |
+                       SNOR_HWCAPS_READ_FAST |
+                       SNOR_HWCAPS_PP,
+       };
+       u32 width, presc, cs_num, max_rate = 0;
        struct stm32_qspi_flash *flash;
        struct mtd_info *mtd;
        int ret;
@@ -499,12 +505,10 @@ static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
                width = 1;
 
        if (width == 4)
-               flash_read = SPI_NOR_QUAD;
+               hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
        else if (width == 2)
-               flash_read = SPI_NOR_DUAL;
-       else if (width == 1)
-               flash_read = SPI_NOR_NORMAL;
-       else
+               hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
+       else if (width != 1)
                return -EINVAL;
 
        flash = &qspi->flash[cs_num];
@@ -539,7 +543,7 @@ static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
         */
        flash->fsize = FSIZE_VAL(SZ_1K);
 
-       ret = spi_nor_scan(&flash->nor, NULL, flash_read);
+       ret = spi_nor_scan(&flash->nor, NULL, &hwcaps);
        if (ret) {
                dev_err(qspi->dev, "device scan failed\n");
                return ret;
index aecc6ce..fa2519a 100644 (file)
@@ -102,7 +102,7 @@ static int write_eraseblock2(int ebnum)
                if (unlikely(err || written != subpgsize * k)) {
                        pr_err("error: write failed at %#llx\n",
                               (long long)addr);
-                       if (written != subpgsize) {
+                       if (written != subpgsize * k) {
                                pr_err("  write size: %#x\n",
                                       subpgsize * k);
                                pr_err("  written: %#08zx\n",
index 7c754a0..19e4e90 100644 (file)
@@ -2,20 +2,11 @@
 # Multiplexer devices
 #
 
-menuconfig MULTIPLEXER
-       tristate "Multiplexer subsystem"
-       help
-         Multiplexer controller subsystem. Multiplexers are used in a
-         variety of settings, and this subsystem abstracts their use
-         so that the rest of the kernel sees a common interface. When
-         multiple parallel multiplexers are controlled by one single
-         multiplexer controller, this subsystem also coordinates the
-         multiplexer accesses.
-
-         To compile the subsystem as a module, choose M here: the module will
-         be called mux-core.
+config MULTIPLEXER
+       tristate
 
-if MULTIPLEXER
+menu "Multiplexer drivers"
+       depends on MULTIPLEXER
 
 config MUX_ADG792A
        tristate "Analog Devices ADG792A/ADG792G Multiplexers"
@@ -56,4 +47,4 @@ config MUX_MMIO
          To compile the driver as a module, choose M here: the module will
          be called mux-mmio.
 
-endif
+endmenu
index 90b8995..2fe96c4 100644 (file)
@@ -46,7 +46,7 @@ static int __init mux_init(void)
 
 static void __exit mux_exit(void)
 {
-       class_register(&mux_class);
+       class_unregister(&mux_class);
        ida_destroy(&mux_ida);
 }
 
index a306de4..9375cef 100644 (file)
@@ -311,9 +311,7 @@ module_param(ipddp_mode, int, 0);
 static int __init ipddp_init_module(void)
 {
        dev_ipddp = ipddp_init();
-        if (IS_ERR(dev_ipddp))
-                return PTR_ERR(dev_ipddp);
-       return 0;
+       return PTR_ERR_OR_ZERO(dev_ipddp);
 }
 
 static void __exit ipddp_cleanup_module(void)
index 14ff622..9bee6c1 100644 (file)
@@ -2050,6 +2050,7 @@ static int bond_miimon_inspect(struct bonding *bond)
                                continue;
 
                        bond_propose_link_state(slave, BOND_LINK_FAIL);
+                       commit++;
                        slave->delay = bond->params.downdelay;
                        if (slave->delay) {
                                netdev_info(bond->dev, "link status down for %sinterface %s, disabling it in %d ms\n",
@@ -2088,6 +2089,7 @@ static int bond_miimon_inspect(struct bonding *bond)
                                continue;
 
                        bond_propose_link_state(slave, BOND_LINK_BACK);
+                       commit++;
                        slave->delay = bond->params.updelay;
 
                        if (slave->delay) {
@@ -4596,7 +4598,7 @@ static int bond_check_params(struct bond_params *params)
        }
        ad_user_port_key = valptr->value;
 
-       if (bond_mode == BOND_MODE_TLB) {
+       if ((bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) {
                bond_opt_initstr(&newval, "default");
                valptr = bond_opt_parse(bond_opt_get(BOND_OPT_TLB_DYNAMIC_LB),
                                        &newval);
index e68d368..7f36d3e 100644 (file)
@@ -1665,6 +1665,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
                .dev_name = "BCM53125",
                .vlans = 4096,
                .enabled_ports = 0xff,
+               .arl_entries = 4,
                .cpu_port = B53_CPU_PORT,
                .vta_regs = B53_VTA_REGS,
                .duplex_reg = B53_DUPLEX_STAT_GE,
index cd76e61..8e430d1 100644 (file)
@@ -20,6 +20,9 @@
 
 #include "lan9303.h"
 
+/* 13.2 System Control and Status Registers
+ * Multiply register number by 4 to get address offset.
+ */
 #define LAN9303_CHIP_REV 0x14
 # define LAN9303_CHIP_ID 0x9303
 #define LAN9303_IRQ_CFG 0x15
@@ -53,6 +56,9 @@
 #define LAN9303_VIRT_PHY_BASE 0x70
 #define LAN9303_VIRT_SPECIAL_CTRL 0x77
 
+/*13.4 Switch Fabric Control and Status Registers
+ * Accessed indirectly via SWITCH_CSR_CMD, SWITCH_CSR_DATA.
+ */
 #define LAN9303_SW_DEV_ID 0x0000
 #define LAN9303_SW_RESET 0x0001
 #define LAN9303_SW_RESET_RESET BIT(0)
@@ -242,7 +248,7 @@ static int lan9303_virt_phy_reg_write(struct lan9303 *chip, int regnum, u16 val)
        return regmap_write(chip->regmap, LAN9303_VIRT_PHY_BASE + regnum, val);
 }
 
-static int lan9303_port_phy_reg_wait_for_completion(struct lan9303 *chip)
+static int lan9303_indirect_phy_wait_for_completion(struct lan9303 *chip)
 {
        int ret, i;
        u32 reg;
@@ -262,7 +268,7 @@ static int lan9303_port_phy_reg_wait_for_completion(struct lan9303 *chip)
        return -EIO;
 }
 
-static int lan9303_port_phy_reg_read(struct lan9303 *chip, int addr, int regnum)
+static int lan9303_indirect_phy_read(struct lan9303 *chip, int addr, int regnum)
 {
        int ret;
        u32 val;
@@ -272,7 +278,7 @@ static int lan9303_port_phy_reg_read(struct lan9303 *chip, int addr, int regnum)
 
        mutex_lock(&chip->indirect_mutex);
 
-       ret = lan9303_port_phy_reg_wait_for_completion(chip);
+       ret = lan9303_indirect_phy_wait_for_completion(chip);
        if (ret)
                goto on_error;
 
@@ -281,7 +287,7 @@ static int lan9303_port_phy_reg_read(struct lan9303 *chip, int addr, int regnum)
        if (ret)
                goto on_error;
 
-       ret = lan9303_port_phy_reg_wait_for_completion(chip);
+       ret = lan9303_indirect_phy_wait_for_completion(chip);
        if (ret)
                goto on_error;
 
@@ -299,8 +305,8 @@ on_error:
        return ret;
 }
 
-static int lan9303_phy_reg_write(struct lan9303 *chip, int addr, int regnum,
-                                unsigned int val)
+static int lan9303_indirect_phy_write(struct lan9303 *chip, int addr,
+                                     int regnum, u16 val)
 {
        int ret;
        u32 reg;
@@ -311,7 +317,7 @@ static int lan9303_phy_reg_write(struct lan9303 *chip, int addr, int regnum,
 
        mutex_lock(&chip->indirect_mutex);
 
-       ret = lan9303_port_phy_reg_wait_for_completion(chip);
+       ret = lan9303_indirect_phy_wait_for_completion(chip);
        if (ret)
                goto on_error;
 
@@ -328,6 +334,12 @@ on_error:
        return ret;
 }
 
+const struct lan9303_phy_ops lan9303_indirect_phy_ops = {
+       .phy_read = lan9303_indirect_phy_read,
+       .phy_write = lan9303_indirect_phy_write,
+};
+EXPORT_SYMBOL_GPL(lan9303_indirect_phy_ops);
+
 static int lan9303_switch_wait_for_completion(struct lan9303 *chip)
 {
        int ret, i;
@@ -427,14 +439,15 @@ static int lan9303_detect_phy_setup(struct lan9303 *chip)
         * Special reg 18 of phy 3 reads as 0x0000, if 'phy_addr_sel_strap' is 0
         * and the IDs are 0-1-2, else it contains something different from
         * 0x0000, which means 'phy_addr_sel_strap' is 1 and the IDs are 1-2-3.
+        * 0xffff is returned on MDIO read with no response.
         */
-       reg = lan9303_port_phy_reg_read(chip, 3, MII_LAN911X_SPECIAL_MODES);
+       reg = chip->ops->phy_read(chip, 3, MII_LAN911X_SPECIAL_MODES);
        if (reg < 0) {
                dev_err(chip->dev, "Failed to detect phy config: %d\n", reg);
                return reg;
        }
 
-       if (reg != 0)
+       if ((reg != 0) && (reg != 0xffff))
                chip->phy_addr_sel_strap = 1;
        else
                chip->phy_addr_sel_strap = 0;
@@ -719,7 +732,7 @@ static int lan9303_phy_read(struct dsa_switch *ds, int phy, int regnum)
        if (phy > phy_base + 2)
                return -ENODEV;
 
-       return lan9303_port_phy_reg_read(chip, phy, regnum);
+       return chip->ops->phy_read(chip, phy, regnum);
 }
 
 static int lan9303_phy_write(struct dsa_switch *ds, int phy, int regnum,
@@ -733,7 +746,7 @@ static int lan9303_phy_write(struct dsa_switch *ds, int phy, int regnum,
        if (phy > phy_base + 2)
                return -ENODEV;
 
-       return lan9303_phy_reg_write(chip, phy, regnum, val);
+       return chip->ops->phy_write(chip, phy, regnum, val);
 }
 
 static int lan9303_port_enable(struct dsa_switch *ds, int port,
@@ -766,13 +779,13 @@ static void lan9303_port_disable(struct dsa_switch *ds, int port,
        switch (port) {
        case 1:
                lan9303_disable_packet_processing(chip, LAN9303_PORT_1_OFFSET);
-               lan9303_phy_reg_write(chip, chip->phy_addr_sel_strap + 1,
-                                     MII_BMCR, BMCR_PDOWN);
+               lan9303_phy_write(ds, chip->phy_addr_sel_strap + 1,
+                                 MII_BMCR, BMCR_PDOWN);
                break;
        case 2:
                lan9303_disable_packet_processing(chip, LAN9303_PORT_2_OFFSET);
-               lan9303_phy_reg_write(chip, chip->phy_addr_sel_strap + 2,
-                                     MII_BMCR, BMCR_PDOWN);
+               lan9303_phy_write(ds, chip->phy_addr_sel_strap + 2,
+                                 MII_BMCR, BMCR_PDOWN);
                break;
        default:
                dev_dbg(chip->dev,
index d1512da..4d8be55 100644 (file)
@@ -2,6 +2,15 @@
 #include <linux/device.h>
 #include <net/dsa.h>
 
+struct lan9303;
+
+struct lan9303_phy_ops {
+       /* PHY 1 and 2 access*/
+       int     (*phy_read)(struct lan9303 *chip, int port, int regnum);
+       int     (*phy_write)(struct lan9303 *chip, int port,
+                            int regnum, u16 val);
+};
+
 struct lan9303 {
        struct device *dev;
        struct regmap *regmap;
@@ -11,9 +20,11 @@ struct lan9303 {
        bool phy_addr_sel_strap;
        struct dsa_switch *ds;
        struct mutex indirect_mutex; /* protect indexed register access */
+       const struct lan9303_phy_ops *ops;
 };
 
 extern const struct regmap_access_table lan9303_register_set;
+extern const struct lan9303_phy_ops lan9303_indirect_phy_ops;
 
 int lan9303_probe(struct lan9303 *chip, struct device_node *np);
 int lan9303_remove(struct lan9303 *chip);
index ab3ce0d..24ec20f 100644 (file)
@@ -63,6 +63,8 @@ static int lan9303_i2c_probe(struct i2c_client *client,
        i2c_set_clientdata(client, sw_dev);
        sw_dev->chip.dev = &client->dev;
 
+       sw_dev->chip.ops = &lan9303_indirect_phy_ops;
+
        ret = lan9303_probe(&sw_dev->chip, client->dev.of_node);
        if (ret != 0)
                return ret;
index 93c36c0..fc16668 100644 (file)
@@ -40,6 +40,7 @@ static int lan9303_mdio_write(void *ctx, uint32_t reg, uint32_t val)
 {
        struct lan9303_mdio *sw_dev = (struct lan9303_mdio *)ctx;
 
+       reg <<= 2; /* reg num to offset */
        mutex_lock(&sw_dev->device->bus->mdio_lock);
        lan9303_mdio_real_write(sw_dev->device, reg, val & 0xffff);
        lan9303_mdio_real_write(sw_dev->device, reg + 2, (val >> 16) & 0xffff);
@@ -57,6 +58,7 @@ static int lan9303_mdio_read(void *ctx, uint32_t reg, uint32_t *val)
 {
        struct lan9303_mdio *sw_dev = (struct lan9303_mdio *)ctx;
 
+       reg <<= 2; /* reg num to offset */
        mutex_lock(&sw_dev->device->bus->mdio_lock);
        *val = lan9303_mdio_real_read(sw_dev->device, reg);
        *val |= (lan9303_mdio_real_read(sw_dev->device, reg + 2) << 16);
@@ -65,6 +67,25 @@ static int lan9303_mdio_read(void *ctx, uint32_t reg, uint32_t *val)
        return 0;
 }
 
+int lan9303_mdio_phy_write(struct lan9303 *chip, int phy, int reg, u16 val)
+{
+       struct lan9303_mdio *sw_dev = dev_get_drvdata(chip->dev);
+
+       return mdiobus_write_nested(sw_dev->device->bus, phy, reg, val);
+}
+
+int lan9303_mdio_phy_read(struct lan9303 *chip, int phy,  int reg)
+{
+       struct lan9303_mdio *sw_dev = dev_get_drvdata(chip->dev);
+
+       return mdiobus_read_nested(sw_dev->device->bus, phy, reg);
+}
+
+static const struct lan9303_phy_ops lan9303_mdio_phy_ops = {
+       .phy_read = lan9303_mdio_phy_read,
+       .phy_write = lan9303_mdio_phy_write,
+};
+
 static const struct regmap_config lan9303_mdio_regmap_config = {
        .reg_bits = 8,
        .val_bits = 32,
@@ -106,6 +127,8 @@ static int lan9303_mdio_probe(struct mdio_device *mdiodev)
        dev_set_drvdata(&mdiodev->dev, sw_dev);
        sw_dev->chip.dev = &mdiodev->dev;
 
+       sw_dev->chip.ops = &lan9303_mdio_phy_ops;
+
        ret = lan9303_probe(&sw_dev->chip, mdiodev->dev.of_node);
        if (ret != 0)
                return ret;
index 947ea35..647d5d4 100644 (file)
@@ -2242,7 +2242,7 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
 
        if (np) {
                bus->name = np->full_name;
-               snprintf(bus->id, MII_BUS_ID_SIZE, "%s", np->full_name);
+               snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
        } else {
                bus->name = "mv88e6xxx SMI";
                snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
@@ -3233,6 +3233,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
        .port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
        .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
        .port_pause_limit = mv88e6390_port_pause_limit,
+       .port_set_cmode = mv88e6390x_port_set_cmode,
        .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
        .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
        .stats_snapshot = mv88e6390_g1_stats_snapshot,
index d3906f6..86058a9 100644 (file)
@@ -1785,16 +1785,18 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
 
        xgene_enet_gpiod_get(pdata);
 
-       pdata->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(pdata->clk)) {
-               /* Abort if the clock is defined but couldn't be retrived.
-                * Always abort if the clock is missing on DT system as
-                * the driver can't cope with this case.
-                */
-               if (PTR_ERR(pdata->clk) != -ENOENT || dev->of_node)
-                       return PTR_ERR(pdata->clk);
-               /* Firmware may have set up the clock already. */
-               dev_info(dev, "clocks have been setup already\n");
+       if (pdata->phy_mode != PHY_INTERFACE_MODE_SGMII) {
+               pdata->clk = devm_clk_get(&pdev->dev, NULL);
+               if (IS_ERR(pdata->clk)) {
+                       /* Abort if the clock is defined but couldn't be
+                        * retrived. Always abort if the clock is missing on
+                        * DT system as the driver can't cope with this case.
+                        */
+                       if (PTR_ERR(pdata->clk) != -ENOENT || dev->of_node)
+                               return PTR_ERR(pdata->clk);
+                       /* Firmware may have set up the clock already. */
+                       dev_info(dev, "clocks have been setup already\n");
+               }
        }
 
        if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII)
index 96dd530..e58b157 100644 (file)
@@ -114,8 +114,8 @@ static int mace_probe(struct macio_dev *mdev, const struct of_device_id *match)
        int j, rev, rc = -EBUSY;
 
        if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
-               printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n",
-                      mace->full_name);
+               printk(KERN_ERR "can't use MACE %pOF: need 3 addrs and 3 irqs\n",
+                      mace);
                return -ENODEV;
        }
 
@@ -123,8 +123,8 @@ static int mace_probe(struct macio_dev *mdev, const struct of_device_id *match)
        if (addr == NULL) {
                addr = of_get_property(mace, "local-mac-address", NULL);
                if (addr == NULL) {
-                       printk(KERN_ERR "Can't get mac-address for MACE %s\n",
-                              mace->full_name);
+                       printk(KERN_ERR "Can't get mac-address for MACE %pOF\n",
+                              mace);
                        return -ENODEV;
                }
        }
index 041cfb7..e941595 100644 (file)
@@ -609,7 +609,7 @@ static void nb8800_mac_config(struct net_device *dev)
                mac_mode |= HALF_DUPLEX;
 
        if (gigabit) {
-               if (priv->phy_mode == PHY_INTERFACE_MODE_RGMII)
+               if (phy_interface_is_rgmii(dev->phydev))
                        mac_mode |= RGMII_MODE;
 
                mac_mode |= GMAC_MODE;
@@ -1268,11 +1268,10 @@ static int nb8800_tangox_init(struct net_device *dev)
                break;
 
        case PHY_INTERFACE_MODE_RGMII:
-               pad_mode = PAD_MODE_RGMII;
-               break;
-
+       case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_RXID:
        case PHY_INTERFACE_MODE_RGMII_TXID:
-               pad_mode = PAD_MODE_RGMII | PAD_MODE_GTX_CLK_DELAY;
+               pad_mode = PAD_MODE_RGMII;
                break;
 
        default:
index 9641380..4577539 100644 (file)
@@ -61,10 +61,12 @@ config BCM63XX_ENET
 
 config BCMGENET
        tristate "Broadcom GENET internal MAC support"
+       depends on (OF && HAS_IOMEM) || COMPILE_TEST
        select MII
        select PHYLIB
        select FIXED_PHY
        select BCM7XXX_PHY
+       select MDIO_BCM_UNIMAC
        help
          This driver supports the built-in Ethernet MACs found in the
          Broadcom BCM7xxx Set Top Box family chipset.
@@ -193,6 +195,7 @@ config SYSTEMPORT
 config BNXT
        tristate "Broadcom NetXtreme-C/E support"
        depends on PCI
+       depends on MAY_USE_DEVLINK
        select FW_LOADER
        select LIBCRC32C
        ---help---
index 73aca97..d937083 100644 (file)
@@ -50,11 +50,14 @@ static u32 platform_bgmac_idm_read(struct bgmac *bgmac, u16 offset)
 
 static void platform_bgmac_idm_write(struct bgmac *bgmac, u16 offset, u32 value)
 {
-       return writel(value, bgmac->plat.idm_base + offset);
+       writel(value, bgmac->plat.idm_base + offset);
 }
 
 static bool platform_bgmac_clk_enabled(struct bgmac *bgmac)
 {
+       if (!bgmac->plat.idm_base)
+               return true;
+
        if ((bgmac_idm_read(bgmac, BCMA_IOCTL) & BGMAC_CLK_EN) != BGMAC_CLK_EN)
                return false;
        if (bgmac_idm_read(bgmac, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET)
@@ -66,6 +69,9 @@ static void platform_bgmac_clk_enable(struct bgmac *bgmac, u32 flags)
 {
        u32 val;
 
+       if (!bgmac->plat.idm_base)
+               return;
+
        /* The Reset Control register only contains a single bit to show if the
         * controller is currently in reset.  Do a sanity check here, just in
         * case the bootloader happened to leave the device in reset.
@@ -180,6 +186,7 @@ static int bgmac_probe(struct platform_device *pdev)
        bgmac->feature_flags |= BGMAC_FEAT_CMDCFG_SR_REV4;
        bgmac->feature_flags |= BGMAC_FEAT_TX_MASK_SETUP;
        bgmac->feature_flags |= BGMAC_FEAT_RX_MASK_SETUP;
+       bgmac->feature_flags |= BGMAC_FEAT_IDM_MASK;
 
        bgmac->dev = &pdev->dev;
        bgmac->dma_dev = &pdev->dev;
@@ -207,15 +214,13 @@ static int bgmac_probe(struct platform_device *pdev)
                return PTR_ERR(bgmac->plat.base);
 
        regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "idm_base");
-       if (!regs) {
-               dev_err(&pdev->dev, "Unable to obtain idm resource\n");
-               return -EINVAL;
+       if (regs) {
+               bgmac->plat.idm_base = devm_ioremap_resource(&pdev->dev, regs);
+               if (IS_ERR(bgmac->plat.idm_base))
+                       return PTR_ERR(bgmac->plat.idm_base);
+               bgmac->feature_flags &= ~BGMAC_FEAT_IDM_MASK;
        }
 
-       bgmac->plat.idm_base = devm_ioremap_resource(&pdev->dev, regs);
-       if (IS_ERR(bgmac->plat.idm_base))
-               return PTR_ERR(bgmac->plat.idm_base);
-
        regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nicpm_base");
        if (regs) {
                bgmac->plat.nicpm_base = devm_ioremap_resource(&pdev->dev,
index ba4d2e1..48d672b 100644 (file)
@@ -622,9 +622,11 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
        BUILD_BUG_ON(BGMAC_MAX_TX_RINGS > ARRAY_SIZE(ring_base));
        BUILD_BUG_ON(BGMAC_MAX_RX_RINGS > ARRAY_SIZE(ring_base));
 
-       if (!(bgmac_idm_read(bgmac, BCMA_IOST) & BCMA_IOST_DMA64)) {
-               dev_err(bgmac->dev, "Core does not report 64-bit DMA\n");
-               return -ENOTSUPP;
+       if (!(bgmac->feature_flags & BGMAC_FEAT_IDM_MASK)) {
+               if (!(bgmac_idm_read(bgmac, BCMA_IOST) & BCMA_IOST_DMA64)) {
+                       dev_err(bgmac->dev, "Core does not report 64-bit DMA\n");
+                       return -ENOTSUPP;
+               }
        }
 
        for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
@@ -855,9 +857,11 @@ static void bgmac_mac_speed(struct bgmac *bgmac)
 static void bgmac_miiconfig(struct bgmac *bgmac)
 {
        if (bgmac->feature_flags & BGMAC_FEAT_FORCE_SPEED_2500) {
-               bgmac_idm_write(bgmac, BCMA_IOCTL,
-                               bgmac_idm_read(bgmac, BCMA_IOCTL) | 0x40 |
-                               BGMAC_BCMA_IOCTL_SW_CLKEN);
+               if (!(bgmac->feature_flags & BGMAC_FEAT_IDM_MASK)) {
+                       bgmac_idm_write(bgmac, BCMA_IOCTL,
+                                       bgmac_idm_read(bgmac, BCMA_IOCTL) |
+                                       0x40 | BGMAC_BCMA_IOCTL_SW_CLKEN);
+               }
                bgmac->mac_speed = SPEED_2500;
                bgmac->mac_duplex = DUPLEX_FULL;
                bgmac_mac_speed(bgmac);
@@ -874,11 +878,36 @@ static void bgmac_miiconfig(struct bgmac *bgmac)
        }
 }
 
+static void bgmac_chip_reset_idm_config(struct bgmac *bgmac)
+{
+       u32 iost;
+
+       iost = bgmac_idm_read(bgmac, BCMA_IOST);
+       if (bgmac->feature_flags & BGMAC_FEAT_IOST_ATTACHED)
+               iost &= ~BGMAC_BCMA_IOST_ATTACHED;
+
+       /* 3GMAC: for BCM4707 & BCM47094, only do core reset at bgmac_probe() */
+       if (!(bgmac->feature_flags & BGMAC_FEAT_NO_RESET)) {
+               u32 flags = 0;
+
+               if (iost & BGMAC_BCMA_IOST_ATTACHED) {
+                       flags = BGMAC_BCMA_IOCTL_SW_CLKEN;
+                       if (!bgmac->has_robosw)
+                               flags |= BGMAC_BCMA_IOCTL_SW_RESET;
+               }
+               bgmac_clk_enable(bgmac, flags);
+       }
+
+       if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw)
+               bgmac_idm_write(bgmac, BCMA_IOCTL,
+                               bgmac_idm_read(bgmac, BCMA_IOCTL) &
+                               ~BGMAC_BCMA_IOCTL_SW_RESET);
+}
+
 /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipreset */
 static void bgmac_chip_reset(struct bgmac *bgmac)
 {
        u32 cmdcfg_sr;
-       u32 iost;
        int i;
 
        if (bgmac_clk_enabled(bgmac)) {
@@ -899,20 +928,8 @@ static void bgmac_chip_reset(struct bgmac *bgmac)
                /* TODO: Clear software multicast filter list */
        }
 
-       iost = bgmac_idm_read(bgmac, BCMA_IOST);
-       if (bgmac->feature_flags & BGMAC_FEAT_IOST_ATTACHED)
-               iost &= ~BGMAC_BCMA_IOST_ATTACHED;
-
-       /* 3GMAC: for BCM4707 & BCM47094, only do core reset at bgmac_probe() */
-       if (!(bgmac->feature_flags & BGMAC_FEAT_NO_RESET)) {
-               u32 flags = 0;
-               if (iost & BGMAC_BCMA_IOST_ATTACHED) {
-                       flags = BGMAC_BCMA_IOCTL_SW_CLKEN;
-                       if (!bgmac->has_robosw)
-                               flags |= BGMAC_BCMA_IOCTL_SW_RESET;
-               }
-               bgmac_clk_enable(bgmac, flags);
-       }
+       if (!(bgmac->feature_flags & BGMAC_FEAT_IDM_MASK))
+               bgmac_chip_reset_idm_config(bgmac);
 
        /* Request Misc PLL for corerev > 2 */
        if (bgmac->feature_flags & BGMAC_FEAT_MISC_PLL_REQ) {
@@ -970,11 +987,6 @@ static void bgmac_chip_reset(struct bgmac *bgmac)
                                      BGMAC_CHIPCTL_7_IF_TYPE_RGMII);
        }
 
-       if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw)
-               bgmac_idm_write(bgmac, BCMA_IOCTL,
-                               bgmac_idm_read(bgmac, BCMA_IOCTL) &
-                               ~BGMAC_BCMA_IOCTL_SW_RESET);
-
        /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_reset
         * Specs don't say about using BGMAC_CMDCFG_SR, but in this routine
         * BGMAC_CMDCFG is read _after_ putting chip in a reset. So it has to
@@ -1497,8 +1509,10 @@ int bgmac_enet_probe(struct bgmac *bgmac)
        bgmac_clk_enable(bgmac, 0);
 
        /* This seems to be fixing IRQ by assigning OOB #6 to the core */
-       if (bgmac->feature_flags & BGMAC_FEAT_IRQ_ID_OOB_6)
-               bgmac_idm_write(bgmac, BCMA_OOB_SEL_OUT_A30, 0x86);
+       if (!(bgmac->feature_flags & BGMAC_FEAT_IDM_MASK)) {
+               if (bgmac->feature_flags & BGMAC_FEAT_IRQ_ID_OOB_6)
+                       bgmac_idm_write(bgmac, BCMA_OOB_SEL_OUT_A30, 0x86);
+       }
 
        bgmac_chip_reset(bgmac);
 
index c181876..443d57b 100644 (file)
 #define BGMAC_FEAT_CC4_IF_SW_TYPE      BIT(17)
 #define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII        BIT(18)
 #define BGMAC_FEAT_CC7_IF_TYPE_RGMII   BIT(19)
+#define BGMAC_FEAT_IDM_MASK            BIT(20)
 
 struct bgmac_slot_info {
        union {
index 4342374..1e33abd 100644 (file)
@@ -2886,7 +2886,7 @@ static int bnx2x_test_nvram_tbl(struct bnx2x *bp,
 
 static int bnx2x_test_nvram(struct bnx2x *bp)
 {
-       const struct crc_pair nvram_tbl[] = {
+       static const struct crc_pair nvram_tbl[] = {
                {     0,  0x14 }, /* bootstrap */
                {  0x14,  0xec }, /* dir */
                { 0x100, 0x350 }, /* manuf_info */
@@ -2895,7 +2895,7 @@ static int bnx2x_test_nvram(struct bnx2x *bp)
                { 0x708,  0x70 }, /* manuf_key_info */
                {     0,     0 }
        };
-       const struct crc_pair nvram_tbl2[] = {
+       static const struct crc_pair nvram_tbl2[] = {
                { 0x7e8, 0x350 }, /* manuf_info2 */
                { 0xb38,  0xf0 }, /* feature_info */
                {     0,     0 }
@@ -3162,7 +3162,8 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
                if (is_multi(bp)) {
                        for_each_eth_queue(bp, i) {
                                memset(queue_name, 0, sizeof(queue_name));
-                               sprintf(queue_name, "%d", i);
+                               snprintf(queue_name, sizeof(queue_name),
+                                        "%d", i);
                                for (j = 0; j < BNX2X_NUM_Q_STATS; j++)
                                        snprintf(buf + (k + j)*ETH_GSTRING_LEN,
                                                ETH_GSTRING_LEN,
index a7ca45b..d141a22 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_BNXT) += bnxt_en.o
 
-bnxt_en-y := bnxt.o bnxt_sriov.o bnxt_ethtool.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o
+bnxt_en-y := bnxt.o bnxt_sriov.o bnxt_ethtool.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o bnxt_vfr.o
index e7c8539..156fb37 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/mii.h>
 #include <linux/if.h>
 #include <linux/if_vlan.h>
+#include <linux/if_bridge.h>
 #include <linux/rtc.h>
 #include <linux/bpf.h>
 #include <net/ip.h>
@@ -56,6 +57,7 @@
 #include "bnxt_ethtool.h"
 #include "bnxt_dcb.h"
 #include "bnxt_xdp.h"
+#include "bnxt_vfr.h"
 
 #define BNXT_TX_TIMEOUT                (5 * HZ)
 
@@ -243,6 +245,16 @@ const u16 bnxt_lhint_arr[] = {
        TX_BD_FLAGS_LHINT_2048_AND_LARGER,
 };
 
+static u16 bnxt_xmit_get_cfa_action(struct sk_buff *skb)
+{
+       struct metadata_dst *md_dst = skb_metadata_dst(skb);
+
+       if (!md_dst || md_dst->type != METADATA_HW_PORT_MUX)
+               return 0;
+
+       return md_dst->u.port_info.port_id;
+}
+
 static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct bnxt *bp = netdev_priv(dev);
@@ -287,7 +299,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
        tx_buf->nr_frags = last_frag;
 
        vlan_tag_flags = 0;
-       cfa_action = 0;
+       cfa_action = bnxt_xmit_get_cfa_action(skb);
        if (skb_vlan_tag_present(skb)) {
                vlan_tag_flags = TX_BD_CFA_META_KEY_VLAN |
                                 skb_vlan_tag_get(skb);
@@ -322,7 +334,8 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        tx_push1->tx_bd_hsize_lflags = 0;
 
                tx_push1->tx_bd_cfa_meta = cpu_to_le32(vlan_tag_flags);
-               tx_push1->tx_bd_cfa_action = cpu_to_le32(cfa_action);
+               tx_push1->tx_bd_cfa_action =
+                       cpu_to_le32(cfa_action << TX_BD_CFA_ACTION_SHIFT);
 
                end = pdata + length;
                end = PTR_ALIGN(end, 8) - 1;
@@ -427,7 +440,8 @@ normal_tx:
        txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
 
        txbd1->tx_bd_cfa_meta = cpu_to_le32(vlan_tag_flags);
-       txbd1->tx_bd_cfa_action = cpu_to_le32(cfa_action);
+       txbd1->tx_bd_cfa_action =
+                       cpu_to_le32(cfa_action << TX_BD_CFA_ACTION_SHIFT);
        for (i = 0; i < last_frag; i++) {
                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
@@ -1032,7 +1046,10 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
                bnxt_sched_reset(bp, rxr);
                return;
        }
-
+       /* Store cfa_code in tpa_info to use in tpa_end
+        * completion processing.
+        */
+       tpa_info->cfa_code = TPA_START_CFA_CODE(tpa_start1);
        prod_rx_buf->data = tpa_info->data;
        prod_rx_buf->data_ptr = tpa_info->data_ptr;
 
@@ -1267,6 +1284,17 @@ static inline struct sk_buff *bnxt_gro_skb(struct bnxt *bp,
        return skb;
 }
 
+/* Given the cfa_code of a received packet determine which
+ * netdev (vf-rep or PF) the packet is destined to.
+ */
+static struct net_device *bnxt_get_pkt_dev(struct bnxt *bp, u16 cfa_code)
+{
+       struct net_device *dev = bnxt_get_vf_rep(bp, cfa_code);
+
+       /* if vf-rep dev is NULL, the must belongs to the PF */
+       return dev ? dev : bp->dev;
+}
+
 static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
                                           struct bnxt_napi *bnapi,
                                           u32 *raw_cons,
@@ -1360,7 +1388,9 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
                        return NULL;
                }
        }
-       skb->protocol = eth_type_trans(skb, bp->dev);
+
+       skb->protocol =
+               eth_type_trans(skb, bnxt_get_pkt_dev(bp, tpa_info->cfa_code));
 
        if (tpa_info->hash_type != PKT_HASH_TYPE_NONE)
                skb_set_hash(skb, tpa_info->rss_hash, tpa_info->hash_type);
@@ -1387,6 +1417,18 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
        return skb;
 }
 
+static void bnxt_deliver_skb(struct bnxt *bp, struct bnxt_napi *bnapi,
+                            struct sk_buff *skb)
+{
+       if (skb->dev != bp->dev) {
+               /* this packet belongs to a vf-rep */
+               bnxt_vf_rep_rx(bp, skb);
+               return;
+       }
+       skb_record_rx_queue(skb, bnapi->index);
+       napi_gro_receive(&bnapi->napi, skb);
+}
+
 /* returns the following:
  * 1       - 1 packet successfully received
  * 0       - successful TPA_START, packet not completed yet
@@ -1403,7 +1445,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
        struct rx_cmp *rxcmp;
        struct rx_cmp_ext *rxcmp1;
        u32 tmp_raw_cons = *raw_cons;
-       u16 cons, prod, cp_cons = RING_CMP(tmp_raw_cons);
+       u16 cfa_code, cons, prod, cp_cons = RING_CMP(tmp_raw_cons);
        struct bnxt_sw_rx_bd *rx_buf;
        unsigned int len;
        u8 *data_ptr, agg_bufs, cmp_type;
@@ -1445,8 +1487,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
 
                rc = -ENOMEM;
                if (likely(skb)) {
-                       skb_record_rx_queue(skb, bnapi->index);
-                       napi_gro_receive(&bnapi->napi, skb);
+                       bnxt_deliver_skb(bp, bnapi, skb);
                        rc = 1;
                }
                *event |= BNXT_RX_EVENT;
@@ -1535,7 +1576,8 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
                skb_set_hash(skb, le32_to_cpu(rxcmp->rx_cmp_rss_hash), type);
        }
 
-       skb->protocol = eth_type_trans(skb, dev);
+       cfa_code = RX_CMP_CFA_CODE(rxcmp1);
+       skb->protocol = eth_type_trans(skb, bnxt_get_pkt_dev(bp, cfa_code));
 
        if ((rxcmp1->rx_cmp_flags2 &
             cpu_to_le32(RX_CMP_FLAGS2_META_FORMAT_VLAN)) &&
@@ -1560,8 +1602,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
                }
        }
 
-       skb_record_rx_queue(skb, bnapi->index);
-       napi_gro_receive(&bnapi->napi, skb);
+       bnxt_deliver_skb(bp, bnapi, skb);
        rc = 1;
 
 next_rx:
@@ -4577,6 +4618,7 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp)
 {
        struct hwrm_func_qcfg_input req = {0};
        struct hwrm_func_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
+       u16 flags;
        int rc;
 
        bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCFG, -1, -1);
@@ -4593,15 +4635,15 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp)
                vf->vlan = le16_to_cpu(resp->vlan) & VLAN_VID_MASK;
        }
 #endif
-       if (BNXT_PF(bp)) {
-               u16 flags = le16_to_cpu(resp->flags);
-
-               if (flags & (FUNC_QCFG_RESP_FLAGS_FW_DCBX_AGENT_ENABLED |
-                            FUNC_QCFG_RESP_FLAGS_FW_LLDP_AGENT_ENABLED))
-                       bp->flags |= BNXT_FLAG_FW_LLDP_AGENT;
-               if (flags & FUNC_QCFG_RESP_FLAGS_MULTI_HOST)
-                       bp->flags |= BNXT_FLAG_MULTI_HOST;
+       flags = le16_to_cpu(resp->flags);
+       if (flags & (FUNC_QCFG_RESP_FLAGS_FW_DCBX_AGENT_ENABLED |
+                    FUNC_QCFG_RESP_FLAGS_FW_LLDP_AGENT_ENABLED)) {
+               bp->flags |= BNXT_FLAG_FW_LLDP_AGENT;
+               if (flags & FUNC_QCFG_RESP_FLAGS_FW_DCBX_AGENT_ENABLED)
+                       bp->flags |= BNXT_FLAG_FW_DCBX_AGENT;
        }
+       if (BNXT_PF(bp) && (flags & FUNC_QCFG_RESP_FLAGS_MULTI_HOST))
+               bp->flags |= BNXT_FLAG_MULTI_HOST;
 
        switch (resp->port_partition_type) {
        case FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_0:
@@ -4610,6 +4652,13 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp)
                bp->port_partition_type = resp->port_partition_type;
                break;
        }
+       if (bp->hwrm_spec_code < 0x10707 ||
+           resp->evb_mode == FUNC_QCFG_RESP_EVB_MODE_VEB)
+               bp->br_mode = BRIDGE_MODE_VEB;
+       else if (resp->evb_mode == FUNC_QCFG_RESP_EVB_MODE_VEPA)
+               bp->br_mode = BRIDGE_MODE_VEPA;
+       else
+               bp->br_mode = BRIDGE_MODE_UNDEF;
 
 func_qcfg_exit:
        mutex_unlock(&bp->hwrm_cmd_lock);
@@ -4911,6 +4960,26 @@ static void bnxt_hwrm_resource_free(struct bnxt *bp, bool close_path,
        }
 }
 
+static int bnxt_hwrm_set_br_mode(struct bnxt *bp, u16 br_mode)
+{
+       struct hwrm_func_cfg_input req = {0};
+       int rc;
+
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
+       req.fid = cpu_to_le16(0xffff);
+       req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_EVB_MODE);
+       if (br_mode == BRIDGE_MODE_VEB)
+               req.evb_mode = FUNC_CFG_REQ_EVB_MODE_VEB;
+       else if (br_mode == BRIDGE_MODE_VEPA)
+               req.evb_mode = FUNC_CFG_REQ_EVB_MODE_VEPA;
+       else
+               return -EINVAL;
+       rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (rc)
+               rc = -EIO;
+       return rc;
+}
+
 static int bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id)
 {
        struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id];
@@ -5559,12 +5628,10 @@ void bnxt_tx_disable(struct bnxt *bp)
 {
        int i;
        struct bnxt_tx_ring_info *txr;
-       struct netdev_queue *txq;
 
        if (bp->tx_ring) {
                for (i = 0; i < bp->tx_nr_rings; i++) {
                        txr = &bp->tx_ring[i];
-                       txq = netdev_get_tx_queue(bp->dev, i);
                        txr->dev_state = BNXT_DEV_STATE_CLOSING;
                }
        }
@@ -5577,11 +5644,9 @@ void bnxt_tx_enable(struct bnxt *bp)
 {
        int i;
        struct bnxt_tx_ring_info *txr;
-       struct netdev_queue *txq;
 
        for (i = 0; i < bp->tx_nr_rings; i++) {
                txr = &bp->tx_ring[i];
-               txq = netdev_get_tx_queue(bp->dev, i);
                txr->dev_state = 0;
        }
        netif_tx_wake_all_queues(bp->dev);
@@ -5646,7 +5711,7 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp)
        if (rc)
                goto hwrm_phy_qcaps_exit;
 
-       if (resp->eee_supported & PORT_PHY_QCAPS_RESP_EEE_SUPPORTED) {
+       if (resp->flags & PORT_PHY_QCAPS_RESP_FLAGS_EEE_SUPPORTED) {
                struct ethtool_eee *eee = &bp->eee;
                u16 fw_speeds = le16_to_cpu(resp->supported_speeds_eee_mode);
 
@@ -5686,13 +5751,15 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state)
 
        memcpy(&link_info->phy_qcfg_resp, resp, sizeof(*resp));
        link_info->phy_link_status = resp->link;
-       link_info->duplex =  resp->duplex;
+       link_info->duplex = resp->duplex_cfg;
+       if (bp->hwrm_spec_code >= 0x10800)
+               link_info->duplex = resp->duplex_state;
        link_info->pause = resp->pause;
        link_info->auto_mode = resp->auto_mode;
        link_info->auto_pause_setting = resp->auto_pause;
        link_info->lp_pause = resp->link_partner_adv_pause;
        link_info->force_pause_setting = resp->force_pause;
-       link_info->duplex_setting = resp->duplex;
+       link_info->duplex_setting = resp->duplex_cfg;
        if (link_info->phy_link_status == BNXT_LINK_LINK)
                link_info->link_speed = le16_to_cpu(resp->link_speed);
        else
@@ -6214,6 +6281,9 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
        /* Poll link status and check for SFP+ module status */
        bnxt_get_port_module_status(bp);
 
+       /* VF-reps may need to be re-opened after the PF is re-opened */
+       if (BNXT_PF(bp))
+               bnxt_vf_reps_open(bp);
        return 0;
 
 open_err:
@@ -6302,6 +6372,10 @@ int bnxt_close_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
                if (rc)
                        netdev_warn(bp->dev, "timeout waiting for SRIOV config operation to complete!\n");
        }
+
+       /* Close the VF-reps before closing PF */
+       if (BNXT_PF(bp))
+               bnxt_vf_reps_close(bp);
 #endif
        /* Change device state to avoid TX queue wake up's */
        bnxt_tx_disable(bp);
@@ -6813,7 +6887,8 @@ static void bnxt_timer(unsigned long data)
        if (atomic_read(&bp->intr_sem) != 0)
                goto bnxt_restart_timer;
 
-       if (bp->link_info.link_up && (bp->flags & BNXT_FLAG_PORT_STATS)) {
+       if (bp->link_info.link_up && (bp->flags & BNXT_FLAG_PORT_STATS) &&
+           bp->stats_coal_ticks) {
                set_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event);
                schedule_work(&bp->sp_task);
        }
@@ -7422,6 +7497,102 @@ static void bnxt_udp_tunnel_del(struct net_device *dev,
        schedule_work(&bp->sp_task);
 }
 
+static int bnxt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
+                              struct net_device *dev, u32 filter_mask,
+                              int nlflags)
+{
+       struct bnxt *bp = netdev_priv(dev);
+
+       return ndo_dflt_bridge_getlink(skb, pid, seq, dev, bp->br_mode, 0, 0,
+                                      nlflags, filter_mask, NULL);
+}
+
+static int bnxt_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
+                              u16 flags)
+{
+       struct bnxt *bp = netdev_priv(dev);
+       struct nlattr *attr, *br_spec;
+       int rem, rc = 0;
+
+       if (bp->hwrm_spec_code < 0x10708 || !BNXT_SINGLE_PF(bp))
+               return -EOPNOTSUPP;
+
+       br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+       if (!br_spec)
+               return -EINVAL;
+
+       nla_for_each_nested(attr, br_spec, rem) {
+               u16 mode;
+
+               if (nla_type(attr) != IFLA_BRIDGE_MODE)
+                       continue;
+
+               if (nla_len(attr) < sizeof(mode))
+                       return -EINVAL;
+
+               mode = nla_get_u16(attr);
+               if (mode == bp->br_mode)
+                       break;
+
+               rc = bnxt_hwrm_set_br_mode(bp, mode);
+               if (!rc)
+                       bp->br_mode = mode;
+               break;
+       }
+       return rc;
+}
+
+static int bnxt_get_phys_port_name(struct net_device *dev, char *buf,
+                                  size_t len)
+{
+       struct bnxt *bp = netdev_priv(dev);
+       int rc;
+
+       /* The PF and it's VF-reps only support the switchdev framework */
+       if (!BNXT_PF(bp))
+               return -EOPNOTSUPP;
+
+       rc = snprintf(buf, len, "p%d", bp->pf.port_id);
+
+       if (rc >= len)
+               return -EOPNOTSUPP;
+       return 0;
+}
+
+int bnxt_port_attr_get(struct bnxt *bp, struct switchdev_attr *attr)
+{
+       if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV)
+               return -EOPNOTSUPP;
+
+       /* The PF and it's VF-reps only support the switchdev framework */
+       if (!BNXT_PF(bp))
+               return -EOPNOTSUPP;
+
+       switch (attr->id) {
+       case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
+               /* In SRIOV each PF-pool (PF + child VFs) serves as a
+                * switching domain, the PF's perm mac-addr can be used
+                * as the unique parent-id
+                */
+               attr->u.ppid.id_len = ETH_ALEN;
+               ether_addr_copy(attr->u.ppid.id, bp->pf.mac_addr);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+static int bnxt_swdev_port_attr_get(struct net_device *dev,
+                                   struct switchdev_attr *attr)
+{
+       return bnxt_port_attr_get(netdev_priv(dev), attr);
+}
+
+static const struct switchdev_ops bnxt_switchdev_ops = {
+       .switchdev_port_attr_get        = bnxt_swdev_port_attr_get
+};
+
 static const struct net_device_ops bnxt_netdev_ops = {
        .ndo_open               = bnxt_open,
        .ndo_start_xmit         = bnxt_start_xmit,
@@ -7453,6 +7624,9 @@ static const struct net_device_ops bnxt_netdev_ops = {
        .ndo_udp_tunnel_add     = bnxt_udp_tunnel_add,
        .ndo_udp_tunnel_del     = bnxt_udp_tunnel_del,
        .ndo_xdp                = bnxt_xdp,
+       .ndo_bridge_getlink     = bnxt_bridge_getlink,
+       .ndo_bridge_setlink     = bnxt_bridge_setlink,
+       .ndo_get_phys_port_name = bnxt_get_phys_port_name
 };
 
 static void bnxt_remove_one(struct pci_dev *pdev)
@@ -7460,8 +7634,10 @@ static void bnxt_remove_one(struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata(pdev);
        struct bnxt *bp = netdev_priv(dev);
 
-       if (BNXT_PF(bp))
+       if (BNXT_PF(bp)) {
                bnxt_sriov_disable(bp);
+               bnxt_dl_unregister(bp);
+       }
 
        pci_disable_pcie_error_reporting(pdev);
        unregister_netdev(dev);
@@ -7710,6 +7886,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        dev->netdev_ops = &bnxt_netdev_ops;
        dev->watchdog_timeo = BNXT_TX_TIMEOUT;
        dev->ethtool_ops = &bnxt_ethtool_ops;
+       SWITCHDEV_SET_OPS(dev, &bnxt_switchdev_ops);
        pci_set_drvdata(pdev, dev);
 
        rc = bnxt_alloc_hwrm_resources(bp);
@@ -7764,6 +7941,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 #ifdef CONFIG_BNXT_SRIOV
        init_waitqueue_head(&bp->sriov_cfg_wait);
+       mutex_init(&bp->sriov_lock);
 #endif
        bp->gro_func = bnxt_gro_func_5730x;
        if (BNXT_CHIP_P4_PLUS(bp))
@@ -7855,6 +8033,9 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                goto init_err_clr_int;
 
+       if (BNXT_PF(bp))
+               bnxt_dl_register(bp);
+
        netdev_info(dev, "%s found at mem %lx, node addr %pM\n",
                    board_info[ent->driver_data].name,
                    (long)pci_resource_start(pdev, 0), dev->dev_addr);
index f34691f..2d84d57 100644 (file)
 #define BNXT_H
 
 #define DRV_MODULE_NAME                "bnxt_en"
-#define DRV_MODULE_VERSION     "1.7.0"
+#define DRV_MODULE_VERSION     "1.8.0"
 
 #define DRV_VER_MAJ    1
-#define DRV_VER_MIN    7
+#define DRV_VER_MIN    8
 #define DRV_VER_UPD    0
 
 #include <linux/interrupt.h>
+#include <net/devlink.h>
+#include <net/dst_metadata.h>
+#include <net/switchdev.h>
 
 struct tx_bd {
        __le32 tx_bd_len_flags_type;
@@ -242,6 +245,10 @@ struct rx_cmp_ext {
            ((le32_to_cpu((rxcmp1)->rx_cmp_flags2) &                    \
             RX_CMP_FLAGS2_T_L4_CS_CALC) >> 3)
 
+#define RX_CMP_CFA_CODE(rxcmpl1)                                       \
+       ((le32_to_cpu((rxcmpl1)->rx_cmp_cfa_code_errors_v2) &           \
+         RX_CMPL_CFA_CODE_MASK) >> RX_CMPL_CFA_CODE_SFT)
+
 struct rx_agg_cmp {
        __le32 rx_agg_cmp_len_flags_type;
        #define RX_AGG_CMP_TYPE                                 (0x3f << 0)
@@ -311,6 +318,10 @@ struct rx_tpa_start_cmp_ext {
        __le32 rx_tpa_start_cmp_hdr_info;
 };
 
+#define TPA_START_CFA_CODE(rx_tpa_start)                               \
+       ((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_cfa_code_v2) &   \
+        RX_TPA_START_CMP_CFA_CODE) >> RX_TPA_START_CMPL_CFA_CODE_SHIFT)
+
 struct rx_tpa_end_cmp {
        __le32 rx_tpa_end_cmp_len_flags_type;
        #define RX_TPA_END_CMP_TYPE                             (0x3f << 0)
@@ -618,6 +629,8 @@ struct bnxt_tpa_info {
 
 #define BNXT_TPA_OUTER_L3_OFF(hdr_info)        \
        ((hdr_info) & 0x1ff)
+
+       u16                     cfa_code; /* cfa_code in TPA start compl */
 };
 
 struct bnxt_rx_ring_info {
@@ -825,8 +838,8 @@ struct bnxt_link_info {
        u8                      loop_back;
        u8                      link_up;
        u8                      duplex;
-#define BNXT_LINK_DUPLEX_HALF  PORT_PHY_QCFG_RESP_DUPLEX_HALF
-#define BNXT_LINK_DUPLEX_FULL  PORT_PHY_QCFG_RESP_DUPLEX_FULL
+#define BNXT_LINK_DUPLEX_HALF  PORT_PHY_QCFG_RESP_DUPLEX_STATE_HALF
+#define BNXT_LINK_DUPLEX_FULL  PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL
        u8                      pause;
 #define BNXT_LINK_PAUSE_TX     PORT_PHY_QCFG_RESP_PAUSE_TX
 #define BNXT_LINK_PAUSE_RX     PORT_PHY_QCFG_RESP_PAUSE_RX
@@ -928,6 +941,24 @@ struct bnxt_test_info {
 #define BNXT_CAG_REG_LEGACY_INT_STATUS 0x4014
 #define BNXT_CAG_REG_BASE              0x300000
 
+struct bnxt_vf_rep_stats {
+       u64                     packets;
+       u64                     bytes;
+       u64                     dropped;
+};
+
+struct bnxt_vf_rep {
+       struct bnxt                     *bp;
+       struct net_device               *dev;
+       struct metadata_dst             *dst;
+       u16                             vf_idx;
+       u16                             tx_cfa_action;
+       u16                             rx_cfa_code;
+
+       struct bnxt_vf_rep_stats        rx_stats;
+       struct bnxt_vf_rep_stats        tx_stats;
+};
+
 struct bnxt {
        void __iomem            *bar0;
        void __iomem            *bar1;
@@ -1027,6 +1058,7 @@ struct bnxt {
        #define BNXT_FLAG_MULTI_HOST    0x100000
        #define BNXT_FLAG_SHORT_CMD     0x200000
        #define BNXT_FLAG_DOUBLE_DB     0x400000
+       #define BNXT_FLAG_FW_DCBX_AGENT 0x800000
        #define BNXT_FLAG_CHIP_NITRO_A0 0x1000000
 
        #define BNXT_FLAG_ALL_CONFIG_FEATS (BNXT_FLAG_TPA |             \
@@ -1164,6 +1196,7 @@ struct bnxt {
        u8                      nge_port_cnt;
        __le16                  nge_fw_dst_port_id;
        u8                      port_partition_type;
+       u16                     br_mode;
 
        u16                     rx_coal_ticks;
        u16                     rx_coal_ticks_irq;
@@ -1206,6 +1239,12 @@ struct bnxt {
        wait_queue_head_t       sriov_cfg_wait;
        bool                    sriov_cfg;
 #define BNXT_SRIOV_CFG_WAIT_TMO        msecs_to_jiffies(10000)
+
+       /* lock to protect VF-rep creation/cleanup via
+        * multiple paths such as ->sriov_configure() and
+        * devlink ->eswitch_mode_set()
+        */
+       struct mutex            sriov_lock;
 #endif
 
 #define BNXT_NTP_FLTR_MAX_FLTR 4096
@@ -1232,6 +1271,12 @@ struct bnxt {
        struct bnxt_led_info    leds[BNXT_MAX_LED];
 
        struct bpf_prog         *xdp_prog;
+
+       /* devlink interface and vf-rep structs */
+       struct devlink          *dl;
+       enum devlink_eswitch_mode eswitch_mode;
+       struct bnxt_vf_rep      **vf_reps; /* array of vf-rep ptrs */
+       u16                     *cfa_code_map; /* cfa_code -> vf_idx map */
 };
 
 #define BNXT_RX_STATS_OFFSET(counter)                  \
@@ -1306,4 +1351,5 @@ int bnxt_reserve_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
 int bnxt_setup_mq_tc(struct net_device *dev, u8 tc);
 int bnxt_get_max_rings(struct bnxt *, int *, int *, bool);
 void bnxt_restore_pf_fw_resources(struct bnxt *bp);
+int bnxt_port_attr_get(struct bnxt *bp, struct switchdev_attr *attr);
 #endif
index 5c6dd0c..aa1f3a2 100644 (file)
@@ -93,6 +93,12 @@ static int bnxt_hwrm_queue_cos2bw_cfg(struct bnxt *bp, struct ieee_ets *ets,
                        cos2bw.tsa =
                                QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_ETS;
                        cos2bw.bw_weight = ets->tc_tx_bw[i];
+                       /* older firmware requires min_bw to be set to the
+                        * same weight value in percent.
+                        */
+                       cos2bw.min_bw =
+                               cpu_to_le32((ets->tc_tx_bw[i] * 100) |
+                                           BW_VALUE_UNIT_PERCENT1_100);
                }
                memcpy(data, &cos2bw.queue_id, sizeof(cos2bw) - 4);
                if (i == 0) {
@@ -549,13 +555,18 @@ static u8 bnxt_dcbnl_setdcbx(struct net_device *dev, u8 mode)
 {
        struct bnxt *bp = netdev_priv(dev);
 
-       /* only support IEEE */
-       if ((mode & DCB_CAP_DCBX_VER_CEE) || !(mode & DCB_CAP_DCBX_VER_IEEE))
+       /* All firmware DCBX settings are set in NVRAM */
+       if (bp->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED)
                return 1;
 
        if (mode & DCB_CAP_DCBX_HOST) {
                if (BNXT_VF(bp) || (bp->flags & BNXT_FLAG_FW_LLDP_AGENT))
                        return 1;
+
+               /* only support IEEE */
+               if ((mode & DCB_CAP_DCBX_VER_CEE) ||
+                   !(mode & DCB_CAP_DCBX_VER_IEEE))
+                       return 1;
        }
 
        if (mode == bp->dcbx_cap)
@@ -584,7 +595,7 @@ void bnxt_dcb_init(struct bnxt *bp)
        bp->dcbx_cap = DCB_CAP_DCBX_VER_IEEE;
        if (BNXT_PF(bp) && !(bp->flags & BNXT_FLAG_FW_LLDP_AGENT))
                bp->dcbx_cap |= DCB_CAP_DCBX_HOST;
-       else
+       else if (bp->flags & BNXT_FLAG_FW_DCBX_AGENT)
                bp->dcbx_cap |= DCB_CAP_DCBX_LLD_MANAGED;
        bp->dev->dcbnl_ops = &dcbnl_ops;
 }
index ecd0a5e..d2e0af9 100644 (file)
@@ -26,6 +26,7 @@ struct bnxt_cos2bw_cfg {
        u8                      queue_id;
        __le32                  min_bw;
        __le32                  max_bw;
+#define BW_VALUE_UNIT_PERCENT1_100             (0x1UL << 29)
        u8                      tsa;
        u8                      pri_lvl;
        u8                      bw_weight;
index be6acad..08b870d 100644 (file)
@@ -86,9 +86,11 @@ static int bnxt_set_coalesce(struct net_device *dev,
        if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) {
                u32 stats_ticks = coal->stats_block_coalesce_usecs;
 
-               stats_ticks = clamp_t(u32, stats_ticks,
-                                     BNXT_MIN_STATS_COAL_TICKS,
-                                     BNXT_MAX_STATS_COAL_TICKS);
+               /* Allow 0, which means disable. */
+               if (stats_ticks)
+                       stats_ticks = clamp_t(u32, stats_ticks,
+                                             BNXT_MIN_STATS_COAL_TICKS,
+                                             BNXT_MAX_STATS_COAL_TICKS);
                stats_ticks = rounddown(stats_ticks, BNXT_MIN_STATS_COAL_TICKS);
                bp->stats_coal_ticks = stats_ticks;
                update_stats = true;
@@ -198,19 +200,23 @@ static const struct {
 
 #define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr)
 
+static int bnxt_get_num_stats(struct bnxt *bp)
+{
+       int num_stats = BNXT_NUM_STATS * bp->cp_nr_rings;
+
+       if (bp->flags & BNXT_FLAG_PORT_STATS)
+               num_stats += BNXT_NUM_PORT_STATS;
+
+       return num_stats;
+}
+
 static int bnxt_get_sset_count(struct net_device *dev, int sset)
 {
        struct bnxt *bp = netdev_priv(dev);
 
        switch (sset) {
-       case ETH_SS_STATS: {
-               int num_stats = BNXT_NUM_STATS * bp->cp_nr_rings;
-
-               if (bp->flags & BNXT_FLAG_PORT_STATS)
-                       num_stats += BNXT_NUM_PORT_STATS;
-
-               return num_stats;
-       }
+       case ETH_SS_STATS:
+               return bnxt_get_num_stats(bp);
        case ETH_SS_TEST:
                if (!bp->num_tests)
                        return -EOPNOTSUPP;
@@ -225,11 +231,8 @@ static void bnxt_get_ethtool_stats(struct net_device *dev,
 {
        u32 i, j = 0;
        struct bnxt *bp = netdev_priv(dev);
-       u32 buf_size = sizeof(struct ctx_hw_stats) * bp->cp_nr_rings;
        u32 stat_fields = sizeof(struct ctx_hw_stats) / 8;
 
-       memset(buf, 0, buf_size);
-
        if (!bp->bnapi)
                return;
 
@@ -520,7 +523,7 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
        struct flow_keys *fkeys;
        int i, rc = -EINVAL;
 
-       if (fs->location < 0 || fs->location >= BNXT_NTP_FLTR_MAX_FLTR)
+       if (fs->location >= BNXT_NTP_FLTR_MAX_FLTR)
                return rc;
 
        for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) {
@@ -835,7 +838,7 @@ static void bnxt_get_drvinfo(struct net_device *dev,
                strlcpy(info->fw_version, bp->fw_ver_str,
                        sizeof(info->fw_version));
        strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
-       info->n_stats = BNXT_NUM_STATS * bp->cp_nr_rings;
+       info->n_stats = bnxt_get_num_stats(bp);
        info->testinfo_len = bp->num_tests;
        /* TODO CHIMP_FW: eeprom dump details */
        info->eedump_len = 0;
index 7dc71bb..3ba22e8 100644 (file)
 #ifndef BNXT_HSI_H
 #define BNXT_HSI_H
 
-/* HSI and HWRM Specification 1.7.6 */
+/* HSI and HWRM Specification 1.8.0 */
 #define HWRM_VERSION_MAJOR     1
-#define HWRM_VERSION_MINOR     7
-#define HWRM_VERSION_UPDATE    6
+#define HWRM_VERSION_MINOR     8
+#define HWRM_VERSION_UPDATE    0
 
-#define HWRM_VERSION_RSVD      2 /* non-zero means beta version */
+#define HWRM_VERSION_RSVD      0 /* non-zero means beta version */
 
-#define HWRM_VERSION_STR       "1.7.6.2"
+#define HWRM_VERSION_STR       "1.8.0.0"
 /*
  * Following is the signature for HWRM message field that indicates not
  * applicable (All F's). Need to cast it the size of the field if needed.
@@ -813,7 +813,7 @@ struct hwrm_func_qcfg_output {
        #define FUNC_QCFG_RESP_FLAGS_FW_DCBX_AGENT_ENABLED          0x4UL
        #define FUNC_QCFG_RESP_FLAGS_STD_TX_RING_MODE_ENABLED      0x8UL
        #define FUNC_QCFG_RESP_FLAGS_FW_LLDP_AGENT_ENABLED          0x10UL
-       #define FUNC_QCFG_RESP_FLAGS_MULTI_HOST                     0x20UL
+       #define FUNC_QCFG_RESP_FLAGS_MULTI_HOST             0x20UL
        u8 mac_address[6];
        __le16 pci_id;
        __le16 alloc_rsscos_ctx;
@@ -835,9 +835,8 @@ struct hwrm_func_qcfg_output {
        u8 port_pf_cnt;
        #define FUNC_QCFG_RESP_PORT_PF_CNT_UNAVAIL                 0x0UL
        __le16 dflt_vnic_id;
-       u8 host_cnt;
-       #define FUNC_QCFG_RESP_HOST_CNT_UNAVAIL            0x0UL
        u8 unused_0;
+       u8 unused_1;
        __le32 min_bw;
        #define FUNC_QCFG_RESP_MIN_BW_BW_VALUE_MASK                 0xfffffffUL
        #define FUNC_QCFG_RESP_MIN_BW_BW_VALUE_SFT                  0
@@ -874,12 +873,56 @@ struct hwrm_func_qcfg_output {
        #define FUNC_QCFG_RESP_EVB_MODE_NO_EVB                     0x0UL
        #define FUNC_QCFG_RESP_EVB_MODE_VEB                        0x1UL
        #define FUNC_QCFG_RESP_EVB_MODE_VEPA                       0x2UL
-       u8 unused_1;
+       u8 unused_2;
        __le16 alloc_vfs;
        __le32 alloc_mcast_filters;
        __le32 alloc_hw_ring_grps;
        __le16 alloc_sp_tx_rings;
+       u8 unused_3;
+       u8 valid;
+};
+
+/* hwrm_func_vlan_cfg */
+/* Input (48 bytes) */
+struct hwrm_func_vlan_cfg_input {
+       __le16 req_type;
+       __le16 cmpl_ring;
+       __le16 seq_id;
+       __le16 target_id;
+       __le64 resp_addr;
+       __le16 fid;
+       u8 unused_0;
+       u8 unused_1;
+       __le32 enables;
+       #define FUNC_VLAN_CFG_REQ_ENABLES_STAG_VID                  0x1UL
+       #define FUNC_VLAN_CFG_REQ_ENABLES_CTAG_VID                  0x2UL
+       #define FUNC_VLAN_CFG_REQ_ENABLES_STAG_PCP                  0x4UL
+       #define FUNC_VLAN_CFG_REQ_ENABLES_CTAG_PCP                  0x8UL
+       #define FUNC_VLAN_CFG_REQ_ENABLES_STAG_TPID                 0x10UL
+       #define FUNC_VLAN_CFG_REQ_ENABLES_CTAG_TPID                 0x20UL
+       __le16 stag_vid;
+       u8 stag_pcp;
        u8 unused_2;
+       __be16 stag_tpid;
+       __le16 ctag_vid;
+       u8 ctag_pcp;
+       u8 unused_3;
+       __be16 ctag_tpid;
+       __le32 rsvd1;
+       __le32 rsvd2;
+       __le32 unused_4;
+};
+
+/* Output (16 bytes) */
+struct hwrm_func_vlan_cfg_output {
+       __le16 error_code;
+       __le16 req_type;
+       __le16 seq_id;
+       __le16 resp_len;
+       __le32 unused_0;
+       u8 unused_1;
+       u8 unused_2;
+       u8 unused_3;
        u8 valid;
 };
 
@@ -902,6 +945,7 @@ struct hwrm_func_cfg_input {
        #define FUNC_CFG_REQ_FLAGS_STD_TX_RING_MODE_ENABLE          0x200UL
        #define FUNC_CFG_REQ_FLAGS_STD_TX_RING_MODE_DISABLE         0x400UL
        #define FUNC_CFG_REQ_FLAGS_VIRT_MAC_PERSIST                 0x800UL
+       #define FUNC_CFG_REQ_FLAGS_NO_AUTOCLEAR_STATISTIC           0x1000UL
        __le32 enables;
        #define FUNC_CFG_REQ_ENABLES_MTU                            0x1UL
        #define FUNC_CFG_REQ_ENABLES_MRU                            0x2UL
@@ -1456,9 +1500,9 @@ struct hwrm_port_phy_qcfg_output {
        #define PORT_PHY_QCFG_RESP_LINK_SPEED_50GB                 0x1f4UL
        #define PORT_PHY_QCFG_RESP_LINK_SPEED_100GB                0x3e8UL
        #define PORT_PHY_QCFG_RESP_LINK_SPEED_10MB                 0xffffUL
-       u8 duplex;
-       #define PORT_PHY_QCFG_RESP_DUPLEX_HALF                     0x0UL
-       #define PORT_PHY_QCFG_RESP_DUPLEX_FULL                     0x1UL
+       u8 duplex_cfg;
+       #define PORT_PHY_QCFG_RESP_DUPLEX_CFG_HALF                 0x0UL
+       #define PORT_PHY_QCFG_RESP_DUPLEX_CFG_FULL                 0x1UL
        u8 pause;
        #define PORT_PHY_QCFG_RESP_PAUSE_TX                         0x1UL
        #define PORT_PHY_QCFG_RESP_PAUSE_RX                         0x2UL
@@ -1573,6 +1617,9 @@ struct hwrm_port_phy_qcfg_output {
        #define PORT_PHY_QCFG_RESP_PHY_TYPE_40G_BASELR4    0x16UL
        #define PORT_PHY_QCFG_RESP_PHY_TYPE_40G_BASEER4    0x17UL
        #define PORT_PHY_QCFG_RESP_PHY_TYPE_40G_ACTIVE_CABLE      0x18UL
+       #define PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASET               0x19UL
+       #define PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASESX              0x1aUL
+       #define PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASECX              0x1bUL
        u8 media_type;
        #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_UNKNOWN              0x0UL
        #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP                   0x1UL
@@ -1651,14 +1698,16 @@ struct hwrm_port_phy_qcfg_output {
        #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE74_ENABLED    0x10UL
        #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE91_SUPPORTED  0x20UL
        #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE91_ENABLED    0x40UL
+       u8 duplex_state;
+       #define PORT_PHY_QCFG_RESP_DUPLEX_STATE_HALF               0x0UL
+       #define PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL               0x1UL
        u8 unused_1;
-       u8 unused_2;
        char phy_vendor_name[16];
        char phy_vendor_partnumber[16];
-       __le32 unused_3;
+       __le32 unused_2;
+       u8 unused_3;
        u8 unused_4;
        u8 unused_5;
-       u8 unused_6;
        u8 valid;
 };
 
@@ -1744,6 +1793,51 @@ struct hwrm_port_mac_cfg_output {
        u8 valid;
 };
 
+/* hwrm_port_mac_ptp_qcfg */
+/* Input (24 bytes) */
+struct hwrm_port_mac_ptp_qcfg_input {
+       __le16 req_type;
+       __le16 cmpl_ring;
+       __le16 seq_id;
+       __le16 target_id;
+       __le64 resp_addr;
+       __le16 port_id;
+       __le16 unused_0[3];
+};
+
+/* Output (80 bytes) */
+struct hwrm_port_mac_ptp_qcfg_output {
+       __le16 error_code;
+       __le16 req_type;
+       __le16 seq_id;
+       __le16 resp_len;
+       u8 flags;
+       #define PORT_MAC_PTP_QCFG_RESP_FLAGS_DIRECT_ACCESS          0x1UL
+       #define PORT_MAC_PTP_QCFG_RESP_FLAGS_HWRM_ACCESS            0x2UL
+       u8 unused_0;
+       __le16 unused_1;
+       __le32 rx_ts_reg_off_lower;
+       __le32 rx_ts_reg_off_upper;
+       __le32 rx_ts_reg_off_seq_id;
+       __le32 rx_ts_reg_off_src_id_0;
+       __le32 rx_ts_reg_off_src_id_1;
+       __le32 rx_ts_reg_off_src_id_2;
+       __le32 rx_ts_reg_off_domain_id;
+       __le32 rx_ts_reg_off_fifo;
+       __le32 rx_ts_reg_off_fifo_adv;
+       __le32 rx_ts_reg_off_granularity;
+       __le32 tx_ts_reg_off_lower;
+       __le32 tx_ts_reg_off_upper;
+       __le32 tx_ts_reg_off_seq_id;
+       __le32 tx_ts_reg_off_fifo;
+       __le32 tx_ts_reg_off_granularity;
+       __le32 unused_2;
+       u8 unused_3;
+       u8 unused_4;
+       u8 unused_5;
+       u8 valid;
+};
+
 /* hwrm_port_qstats */
 /* Input (40 bytes) */
 struct hwrm_port_qstats_input {
@@ -1874,10 +1968,10 @@ struct hwrm_port_phy_qcaps_output {
        __le16 req_type;
        __le16 seq_id;
        __le16 resp_len;
-       u8 eee_supported;
-       #define PORT_PHY_QCAPS_RESP_EEE_SUPPORTED                   0x1UL
-       #define PORT_PHY_QCAPS_RESP_RSVD1_MASK                      0xfeUL
-       #define PORT_PHY_QCAPS_RESP_RSVD1_SFT                       1
+       u8 flags;
+       #define PORT_PHY_QCAPS_RESP_FLAGS_EEE_SUPPORTED     0x1UL
+       #define PORT_PHY_QCAPS_RESP_FLAGS_RSVD1_MASK                0xfeUL
+       #define PORT_PHY_QCAPS_RESP_FLAGS_RSVD1_SFT                 1
        u8 unused_0;
        __le16 supported_speeds_force_mode;
        #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS_FORCE_MODE_100MBHD 0x1UL
@@ -3152,6 +3246,95 @@ struct hwrm_queue_cos2bw_cfg_output {
        u8 valid;
 };
 
+/* hwrm_queue_dscp_qcaps */
+/* Input (24 bytes) */
+struct hwrm_queue_dscp_qcaps_input {
+       __le16 req_type;
+       __le16 cmpl_ring;
+       __le16 seq_id;
+       __le16 target_id;
+       __le64 resp_addr;
+       u8 port_id;
+       u8 unused_0[7];
+};
+
+/* Output (16 bytes) */
+struct hwrm_queue_dscp_qcaps_output {
+       __le16 error_code;
+       __le16 req_type;
+       __le16 seq_id;
+       __le16 resp_len;
+       u8 num_dscp_bits;
+       u8 unused_0;
+       __le16 max_entries;
+       u8 unused_1;
+       u8 unused_2;
+       u8 unused_3;
+       u8 valid;
+};
+
+/* hwrm_queue_dscp2pri_qcfg */
+/* Input (32 bytes) */
+struct hwrm_queue_dscp2pri_qcfg_input {
+       __le16 req_type;
+       __le16 cmpl_ring;
+       __le16 seq_id;
+       __le16 target_id;
+       __le64 resp_addr;
+       __le64 dest_data_addr;
+       u8 port_id;
+       u8 unused_0;
+       __le16 dest_data_buffer_size;
+       __le32 unused_1;
+};
+
+/* Output (16 bytes) */
+struct hwrm_queue_dscp2pri_qcfg_output {
+       __le16 error_code;
+       __le16 req_type;
+       __le16 seq_id;
+       __le16 resp_len;
+       __le16 entry_cnt;
+       u8 default_pri;
+       u8 unused_0;
+       u8 unused_1;
+       u8 unused_2;
+       u8 unused_3;
+       u8 valid;
+};
+
+/* hwrm_queue_dscp2pri_cfg */
+/* Input (40 bytes) */
+struct hwrm_queue_dscp2pri_cfg_input {
+       __le16 req_type;
+       __le16 cmpl_ring;
+       __le16 seq_id;
+       __le16 target_id;
+       __le64 resp_addr;
+       __le64 src_data_addr;
+       __le32 flags;
+       #define QUEUE_DSCP2PRI_CFG_REQ_FLAGS_USE_HW_DEFAULT_PRI    0x1UL
+       __le32 enables;
+       #define QUEUE_DSCP2PRI_CFG_REQ_ENABLES_DEFAULT_PRI          0x1UL
+       u8 port_id;
+       u8 default_pri;
+       __le16 entry_cnt;
+       __le32 unused_0;
+};
+
+/* Output (16 bytes) */
+struct hwrm_queue_dscp2pri_cfg_output {
+       __le16 error_code;
+       __le16 req_type;
+       __le16 seq_id;
+       __le16 resp_len;
+       __le32 unused_0;
+       u8 unused_1;
+       u8 unused_2;
+       u8 unused_3;
+       u8 valid;
+};
+
 /* hwrm_vnic_alloc */
 /* Input (24 bytes) */
 struct hwrm_vnic_alloc_input {
@@ -4038,7 +4221,7 @@ struct hwrm_cfa_encap_record_alloc_input {
        #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPGRE       0x8UL
        u8 unused_0;
        __le16 unused_1;
-       __le32 encap_data[16];
+       __le32 encap_data[20];
 };
 
 /* Output (16 bytes) */
@@ -4120,8 +4303,8 @@ struct hwrm_cfa_ntuple_filter_alloc_input {
        #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_ADDR_TYPE_IPV6     0x6UL
        u8 ip_protocol;
        #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_UNKNOWN   0x0UL
-       #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_UDP       0x6UL
-       #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_TCP       0x11UL
+       #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_TCP       0x6UL
+       #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_UDP       0x11UL
        __le16 dst_id;
        __le16 mirror_vnic_id;
        u8 tunnel_type;
@@ -4224,6 +4407,58 @@ struct hwrm_cfa_ntuple_filter_cfg_output {
        u8 valid;
 };
 
+/* hwrm_cfa_vfr_alloc */
+/* Input (32 bytes) */
+struct hwrm_cfa_vfr_alloc_input {
+       __le16 req_type;
+       __le16 cmpl_ring;
+       __le16 seq_id;
+       __le16 target_id;
+       __le64 resp_addr;
+       __le16 vf_id;
+       __le16 reserved;
+       __le32 unused_0;
+       char vfr_name[32];
+};
+
+/* Output (16 bytes) */
+struct hwrm_cfa_vfr_alloc_output {
+       __le16 error_code;
+       __le16 req_type;
+       __le16 seq_id;
+       __le16 resp_len;
+       __le16 rx_cfa_code;
+       __le16 tx_cfa_action;
+       u8 unused_0;
+       u8 unused_1;
+       u8 unused_2;
+       u8 valid;
+};
+
+/* hwrm_cfa_vfr_free */
+/* Input (24 bytes) */
+struct hwrm_cfa_vfr_free_input {
+       __le16 req_type;
+       __le16 cmpl_ring;
+       __le16 seq_id;
+       __le16 target_id;
+       __le64 resp_addr;
+       char vfr_name[32];
+};
+
+/* Output (16 bytes) */
+struct hwrm_cfa_vfr_free_output {
+       __le16 error_code;
+       __le16 req_type;
+       __le16 seq_id;
+       __le16 resp_len;
+       __le32 unused_0;
+       u8 unused_1;
+       u8 unused_2;
+       u8 unused_3;
+       u8 valid;
+};
+
 /* hwrm_tunnel_dst_port_query */
 /* Input (24 bytes) */
 struct hwrm_tunnel_dst_port_query_input {
@@ -4448,12 +4683,13 @@ struct hwrm_fw_reset_input {
        #define FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT               0x1UL
        #define FW_RESET_REQ_EMBEDDED_PROC_TYPE_NETCTRL    0x2UL
        #define FW_RESET_REQ_EMBEDDED_PROC_TYPE_ROCE               0x3UL
-       #define FW_RESET_REQ_EMBEDDED_PROC_TYPE_RSVD               0x4UL
+       #define FW_RESET_REQ_EMBEDDED_PROC_TYPE_HOST               0x4UL
        u8 selfrst_status;
        #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE    0x0UL
        #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP    0x1UL
        #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST         0x2UL
-       __le16 unused_0[3];
+       u8 host_idx;
+       u8 unused_0[5];
 };
 
 /* Output (16 bytes) */
@@ -4487,7 +4723,7 @@ struct hwrm_fw_qstatus_input {
        #define FW_QSTATUS_REQ_EMBEDDED_PROC_TYPE_MGMT             0x1UL
        #define FW_QSTATUS_REQ_EMBEDDED_PROC_TYPE_NETCTRL          0x2UL
        #define FW_QSTATUS_REQ_EMBEDDED_PROC_TYPE_ROCE             0x3UL
-       #define FW_QSTATUS_REQ_EMBEDDED_PROC_TYPE_RSVD             0x4UL
+       #define FW_QSTATUS_REQ_EMBEDDED_PROC_TYPE_HOST             0x4UL
        u8 unused_0[7];
 };
 
@@ -4572,6 +4808,16 @@ struct hwrm_fw_set_structured_data_output {
        u8 valid;
 };
 
+/* Command specific Error Codes (8 bytes) */
+struct hwrm_fw_set_structured_data_cmd_err {
+       u8 code;
+       #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_UNKNOWN       0x0UL
+       #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_BAD_HDR_CNT   0x1UL
+       #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_BAD_FMT       0x2UL
+       #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_BAD_ID         0x3UL
+       u8 unused_0[7];
+};
+
 /* hwrm_fw_get_structured_data */
 /* Input (32 bytes) */
 struct hwrm_fw_get_structured_data_input {
@@ -4611,6 +4857,14 @@ struct hwrm_fw_get_structured_data_output {
        u8 valid;
 };
 
+/* Command specific Error Codes (8 bytes) */
+struct hwrm_fw_get_structured_data_cmd_err {
+       u8 code;
+       #define FW_GET_STRUCTURED_DATA_CMD_ERR_CODE_UNKNOWN       0x0UL
+       #define FW_GET_STRUCTURED_DATA_CMD_ERR_CODE_BAD_ID         0x3UL
+       u8 unused_0[7];
+};
+
 /* hwrm_exec_fwd_resp */
 /* Input (128 bytes) */
 struct hwrm_exec_fwd_resp_input {
@@ -5411,7 +5665,7 @@ struct cmd_nums {
        #define HWRM_PORT_LPBK_CLR_STATS                           (0x26UL)
        #define HWRM_PORT_PHY_QCFG                                 (0x27UL)
        #define HWRM_PORT_MAC_QCFG                                 (0x28UL)
-       #define RESERVED7                                          (0x29UL)
+       #define HWRM_PORT_MAC_PTP_QCFG                             (0x29UL)
        #define HWRM_PORT_PHY_QCAPS                                (0x2aUL)
        #define HWRM_PORT_PHY_I2C_WRITE                    (0x2bUL)
        #define HWRM_PORT_PHY_I2C_READ                             (0x2cUL)
@@ -5421,14 +5675,17 @@ struct cmd_nums {
        #define HWRM_QUEUE_QPORTCFG                                (0x30UL)
        #define HWRM_QUEUE_QCFG                            (0x31UL)
        #define HWRM_QUEUE_CFG                                     (0x32UL)
-       #define RESERVED2                                          (0x33UL)
-       #define RESERVED3                                          (0x34UL)
+       #define HWRM_FUNC_VLAN_CFG                                 (0x33UL)
+       #define HWRM_FUNC_VLAN_QCFG                                (0x34UL)
        #define HWRM_QUEUE_PFCENABLE_QCFG                          (0x35UL)
        #define HWRM_QUEUE_PFCENABLE_CFG                           (0x36UL)
        #define HWRM_QUEUE_PRI2COS_QCFG                    (0x37UL)
        #define HWRM_QUEUE_PRI2COS_CFG                             (0x38UL)
        #define HWRM_QUEUE_COS2BW_QCFG                             (0x39UL)
        #define HWRM_QUEUE_COS2BW_CFG                              (0x3aUL)
+       #define HWRM_QUEUE_DSCP_QCAPS                              (0x3bUL)
+       #define HWRM_QUEUE_DSCP2PRI_QCFG                           (0x3cUL)
+       #define HWRM_QUEUE_DSCP2PRI_CFG                    (0x3dUL)
        #define HWRM_VNIC_ALLOC                            (0x40UL)
        #define HWRM_VNIC_FREE                                     (0x41UL)
        #define HWRM_VNIC_CFG                                      (0x42UL)
@@ -5455,7 +5712,7 @@ struct cmd_nums {
        #define HWRM_CFA_L2_FILTER_FREE                    (0x91UL)
        #define HWRM_CFA_L2_FILTER_CFG                             (0x92UL)
        #define HWRM_CFA_L2_SET_RX_MASK                    (0x93UL)
-       #define RESERVED4                                          (0x94UL)
+       #define HWRM_CFA_VLAN_ANTISPOOF_CFG                        (0x94UL)
        #define HWRM_CFA_TUNNEL_FILTER_ALLOC                       (0x95UL)
        #define HWRM_CFA_TUNNEL_FILTER_FREE                        (0x96UL)
        #define HWRM_CFA_ENCAP_RECORD_ALLOC                        (0x97UL)
@@ -5494,6 +5751,8 @@ struct cmd_nums {
        #define HWRM_CFA_METER_PROFILE_CFG                         (0xf7UL)
        #define HWRM_CFA_METER_INSTANCE_ALLOC                      (0xf8UL)
        #define HWRM_CFA_METER_INSTANCE_FREE                       (0xf9UL)
+       #define HWRM_CFA_VFR_ALLOC                                 (0xfdUL)
+       #define HWRM_CFA_VFR_FREE                                  (0xfeUL)
        #define HWRM_CFA_VF_PAIR_ALLOC                             (0x100UL)
        #define HWRM_CFA_VF_PAIR_FREE                              (0x101UL)
        #define HWRM_CFA_VF_PAIR_INFO                              (0x102UL)
@@ -5502,6 +5761,9 @@ struct cmd_nums {
        #define HWRM_CFA_FLOW_FLUSH                                (0x105UL)
        #define HWRM_CFA_FLOW_STATS                                (0x106UL)
        #define HWRM_CFA_FLOW_INFO                                 (0x107UL)
+       #define HWRM_CFA_DECAP_FILTER_ALLOC                        (0x108UL)
+       #define HWRM_CFA_DECAP_FILTER_FREE                         (0x109UL)
+       #define HWRM_CFA_VLAN_ANTISPOOF_QCFG                       (0x10aUL)
        #define HWRM_SELFTEST_QLIST                                (0x200UL)
        #define HWRM_SELFTEST_EXEC                                 (0x201UL)
        #define HWRM_SELFTEST_IRQ                                  (0x202UL)
@@ -5510,6 +5772,8 @@ struct cmd_nums {
        #define HWRM_DBG_WRITE_DIRECT                              (0xff12UL)
        #define HWRM_DBG_WRITE_INDIRECT                    (0xff13UL)
        #define HWRM_DBG_DUMP                                      (0xff14UL)
+       #define HWRM_DBG_ERASE_NVM                                 (0xff15UL)
+       #define HWRM_DBG_CFG                                       (0xff16UL)
        #define HWRM_NVM_FACTORY_DEFAULTS                          (0xffeeUL)
        #define HWRM_NVM_VALIDATE_OPTION                           (0xffefUL)
        #define HWRM_NVM_FLUSH                                     (0xfff0UL)
index b8e7248..d37925a 100644 (file)
@@ -18,6 +18,7 @@
 #include "bnxt.h"
 #include "bnxt_ulp.h"
 #include "bnxt_sriov.h"
+#include "bnxt_vfr.h"
 #include "bnxt_ethtool.h"
 
 #ifdef CONFIG_BNXT_SRIOV
@@ -587,6 +588,10 @@ void bnxt_sriov_disable(struct bnxt *bp)
        if (!num_vfs)
                return;
 
+       /* synchronize VF and VF-rep create and destroy */
+       mutex_lock(&bp->sriov_lock);
+       bnxt_vf_reps_destroy(bp);
+
        if (pci_vfs_assigned(bp->pdev)) {
                bnxt_hwrm_fwd_async_event_cmpl(
                        bp, NULL, ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD);
@@ -597,6 +602,7 @@ void bnxt_sriov_disable(struct bnxt *bp)
                /* Free the HW resources reserved for various VF's */
                bnxt_hwrm_func_vf_resource_free(bp, num_vfs);
        }
+       mutex_unlock(&bp->sriov_lock);
 
        bnxt_free_vf_resources(bp);
 
@@ -794,8 +800,10 @@ static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf)
                                        PORT_PHY_QCFG_RESP_LINK_LINK;
                                phy_qcfg_resp.link_speed = cpu_to_le16(
                                        PORT_PHY_QCFG_RESP_LINK_SPEED_10GB);
-                               phy_qcfg_resp.duplex =
-                                       PORT_PHY_QCFG_RESP_DUPLEX_FULL;
+                               phy_qcfg_resp.duplex_cfg =
+                                       PORT_PHY_QCFG_RESP_DUPLEX_CFG_FULL;
+                               phy_qcfg_resp.duplex_state =
+                                       PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL;
                                phy_qcfg_resp.pause =
                                        (PORT_PHY_QCFG_RESP_PAUSE_TX |
                                         PORT_PHY_QCFG_RESP_PAUSE_RX);
@@ -804,7 +812,8 @@ static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf)
                        /* force link down */
                        phy_qcfg_resp.link = PORT_PHY_QCFG_RESP_LINK_NO_LINK;
                        phy_qcfg_resp.link_speed = 0;
-                       phy_qcfg_resp.duplex = PORT_PHY_QCFG_RESP_DUPLEX_HALF;
+                       phy_qcfg_resp.duplex_state =
+                               PORT_PHY_QCFG_RESP_DUPLEX_STATE_HALF;
                        phy_qcfg_resp.pause = 0;
                }
                rc = bnxt_hwrm_fwd_resp(bp, vf, &phy_qcfg_resp,
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
new file mode 100644 (file)
index 0000000..b05c5d0
--- /dev/null
@@ -0,0 +1,495 @@
+/* Broadcom NetXtreme-C/E network driver.
+ *
+ * Copyright (c) 2016-2017 Broadcom Limited
+ *
+ * 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.
+ */
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/jhash.h>
+
+#include "bnxt_hsi.h"
+#include "bnxt.h"
+#include "bnxt_vfr.h"
+
+#ifdef CONFIG_BNXT_SRIOV
+
+#define CFA_HANDLE_INVALID             0xffff
+#define VF_IDX_INVALID                 0xffff
+
+static int hwrm_cfa_vfr_alloc(struct bnxt *bp, u16 vf_idx,
+                             u16 *tx_cfa_action, u16 *rx_cfa_code)
+{
+       struct hwrm_cfa_vfr_alloc_output *resp = bp->hwrm_cmd_resp_addr;
+       struct hwrm_cfa_vfr_alloc_input req = { 0 };
+       int rc;
+
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_CFA_VFR_ALLOC, -1, -1);
+       req.vf_id = cpu_to_le16(vf_idx);
+       sprintf(req.vfr_name, "vfr%d", vf_idx);
+
+       mutex_lock(&bp->hwrm_cmd_lock);
+       rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (!rc) {
+               *tx_cfa_action = le16_to_cpu(resp->tx_cfa_action);
+               *rx_cfa_code = le16_to_cpu(resp->rx_cfa_code);
+               netdev_dbg(bp->dev, "tx_cfa_action=0x%x, rx_cfa_code=0x%x",
+                          *tx_cfa_action, *rx_cfa_code);
+       } else {
+               netdev_info(bp->dev, "%s error rc=%d", __func__, rc);
+       }
+
+       mutex_unlock(&bp->hwrm_cmd_lock);
+       return rc;
+}
+
+static int hwrm_cfa_vfr_free(struct bnxt *bp, u16 vf_idx)
+{
+       struct hwrm_cfa_vfr_free_input req = { 0 };
+       int rc;
+
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_CFA_VFR_FREE, -1, -1);
+       sprintf(req.vfr_name, "vfr%d", vf_idx);
+
+       rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (rc)
+               netdev_info(bp->dev, "%s error rc=%d", __func__, rc);
+       return rc;
+}
+
+static int bnxt_vf_rep_open(struct net_device *dev)
+{
+       struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
+       struct bnxt *bp = vf_rep->bp;
+
+       /* Enable link and TX only if the parent PF is open. */
+       if (netif_running(bp->dev)) {
+               netif_carrier_on(dev);
+               netif_tx_start_all_queues(dev);
+       }
+       return 0;
+}
+
+static int bnxt_vf_rep_close(struct net_device *dev)
+{
+       netif_carrier_off(dev);
+       netif_tx_disable(dev);
+
+       return 0;
+}
+
+static netdev_tx_t bnxt_vf_rep_xmit(struct sk_buff *skb,
+                                   struct net_device *dev)
+{
+       struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
+       int rc, len = skb->len;
+
+       skb_dst_drop(skb);
+       dst_hold((struct dst_entry *)vf_rep->dst);
+       skb_dst_set(skb, (struct dst_entry *)vf_rep->dst);
+       skb->dev = vf_rep->dst->u.port_info.lower_dev;
+
+       rc = dev_queue_xmit(skb);
+       if (!rc) {
+               vf_rep->tx_stats.packets++;
+               vf_rep->tx_stats.bytes += len;
+       }
+       return rc;
+}
+
+static void
+bnxt_vf_rep_get_stats64(struct net_device *dev,
+                       struct rtnl_link_stats64 *stats)
+{
+       struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
+
+       stats->rx_packets = vf_rep->rx_stats.packets;
+       stats->rx_bytes = vf_rep->rx_stats.bytes;
+       stats->tx_packets = vf_rep->tx_stats.packets;
+       stats->tx_bytes = vf_rep->tx_stats.bytes;
+}
+
+struct net_device *bnxt_get_vf_rep(struct bnxt *bp, u16 cfa_code)
+{
+       u16 vf_idx;
+
+       if (cfa_code && bp->cfa_code_map && BNXT_PF(bp)) {
+               vf_idx = bp->cfa_code_map[cfa_code];
+               if (vf_idx != VF_IDX_INVALID)
+                       return bp->vf_reps[vf_idx]->dev;
+       }
+       return NULL;
+}
+
+void bnxt_vf_rep_rx(struct bnxt *bp, struct sk_buff *skb)
+{
+       struct bnxt_vf_rep *vf_rep = netdev_priv(skb->dev);
+       struct bnxt_vf_rep_stats *rx_stats;
+
+       rx_stats = &vf_rep->rx_stats;
+       vf_rep->rx_stats.bytes += skb->len;
+       vf_rep->rx_stats.packets++;
+
+       netif_receive_skb(skb);
+}
+
+static int bnxt_vf_rep_get_phys_port_name(struct net_device *dev, char *buf,
+                                         size_t len)
+{
+       struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
+       struct pci_dev *pf_pdev = vf_rep->bp->pdev;
+       int rc;
+
+       rc = snprintf(buf, len, "pf%dvf%d", PCI_FUNC(pf_pdev->devfn),
+                     vf_rep->vf_idx);
+       if (rc >= len)
+               return -EOPNOTSUPP;
+       return 0;
+}
+
+static void bnxt_vf_rep_get_drvinfo(struct net_device *dev,
+                                   struct ethtool_drvinfo *info)
+{
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+}
+
+static int bnxt_vf_rep_port_attr_get(struct net_device *dev,
+                                    struct switchdev_attr *attr)
+{
+       struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
+
+       /* as only PORT_PARENT_ID is supported currently use common code
+        * between PF and VF-rep for now.
+        */
+       return bnxt_port_attr_get(vf_rep->bp, attr);
+}
+
+static const struct switchdev_ops bnxt_vf_rep_switchdev_ops = {
+       .switchdev_port_attr_get        = bnxt_vf_rep_port_attr_get
+};
+
+static const struct ethtool_ops bnxt_vf_rep_ethtool_ops = {
+       .get_drvinfo            = bnxt_vf_rep_get_drvinfo
+};
+
+static const struct net_device_ops bnxt_vf_rep_netdev_ops = {
+       .ndo_open               = bnxt_vf_rep_open,
+       .ndo_stop               = bnxt_vf_rep_close,
+       .ndo_start_xmit         = bnxt_vf_rep_xmit,
+       .ndo_get_stats64        = bnxt_vf_rep_get_stats64,
+       .ndo_get_phys_port_name = bnxt_vf_rep_get_phys_port_name
+};
+
+/* Called when the parent PF interface is closed:
+ * As the mode transition from SWITCHDEV to LEGACY
+ * happens under the rtnl_lock() this routine is safe
+ * under the rtnl_lock()
+ */
+void bnxt_vf_reps_close(struct bnxt *bp)
+{
+       struct bnxt_vf_rep *vf_rep;
+       u16 num_vfs, i;
+
+       if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV)
+               return;
+
+       num_vfs = pci_num_vf(bp->pdev);
+       for (i = 0; i < num_vfs; i++) {
+               vf_rep = bp->vf_reps[i];
+               if (netif_running(vf_rep->dev))
+                       bnxt_vf_rep_close(vf_rep->dev);
+       }
+}
+
+/* Called when the parent PF interface is opened (re-opened):
+ * As the mode transition from SWITCHDEV to LEGACY
+ * happen under the rtnl_lock() this routine is safe
+ * under the rtnl_lock()
+ */
+void bnxt_vf_reps_open(struct bnxt *bp)
+{
+       int i;
+
+       if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV)
+               return;
+
+       for (i = 0; i < pci_num_vf(bp->pdev); i++)
+               bnxt_vf_rep_open(bp->vf_reps[i]->dev);
+}
+
+static void __bnxt_vf_reps_destroy(struct bnxt *bp)
+{
+       u16 num_vfs = pci_num_vf(bp->pdev);
+       struct bnxt_vf_rep *vf_rep;
+       int i;
+
+       for (i = 0; i < num_vfs; i++) {
+               vf_rep = bp->vf_reps[i];
+               if (vf_rep) {
+                       dst_release((struct dst_entry *)vf_rep->dst);
+
+                       if (vf_rep->tx_cfa_action != CFA_HANDLE_INVALID)
+                               hwrm_cfa_vfr_free(bp, vf_rep->vf_idx);
+
+                       if (vf_rep->dev) {
+                               /* if register_netdev failed, then netdev_ops
+                                * would have been set to NULL
+                                */
+                               if (vf_rep->dev->netdev_ops)
+                                       unregister_netdev(vf_rep->dev);
+                               free_netdev(vf_rep->dev);
+                       }
+               }
+       }
+
+       kfree(bp->vf_reps);
+       bp->vf_reps = NULL;
+}
+
+void bnxt_vf_reps_destroy(struct bnxt *bp)
+{
+       bool closed = false;
+
+       if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV)
+               return;
+
+       if (!bp->vf_reps)
+               return;
+
+       /* Ensure that parent PF's and VF-reps' RX/TX has been quiesced
+        * before proceeding with VF-rep cleanup.
+        */
+       rtnl_lock();
+       if (netif_running(bp->dev)) {
+               bnxt_close_nic(bp, false, false);
+               closed = true;
+       }
+       /* un-publish cfa_code_map so that RX path can't see it anymore */
+       kfree(bp->cfa_code_map);
+       bp->cfa_code_map = NULL;
+       bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
+
+       if (closed)
+               bnxt_open_nic(bp, false, false);
+       rtnl_unlock();
+
+       /* Need to call vf_reps_destroy() outside of rntl_lock
+        * as unregister_netdev takes rtnl_lock
+        */
+       __bnxt_vf_reps_destroy(bp);
+}
+
+/* Use the OUI of the PF's perm addr and report the same mac addr
+ * for the same VF-rep each time
+ */
+static void bnxt_vf_rep_eth_addr_gen(u8 *src_mac, u16 vf_idx, u8 *mac)
+{
+       u32 addr;
+
+       ether_addr_copy(mac, src_mac);
+
+       addr = jhash(src_mac, ETH_ALEN, 0) + vf_idx;
+       mac[3] = (u8)(addr & 0xFF);
+       mac[4] = (u8)((addr >> 8) & 0xFF);
+       mac[5] = (u8)((addr >> 16) & 0xFF);
+}
+
+static void bnxt_vf_rep_netdev_init(struct bnxt *bp, struct bnxt_vf_rep *vf_rep,
+                                   struct net_device *dev)
+{
+       struct net_device *pf_dev = bp->dev;
+
+       dev->netdev_ops = &bnxt_vf_rep_netdev_ops;
+       dev->ethtool_ops = &bnxt_vf_rep_ethtool_ops;
+       SWITCHDEV_SET_OPS(dev, &bnxt_vf_rep_switchdev_ops);
+       /* Just inherit all the featues of the parent PF as the VF-R
+        * uses the RX/TX rings of the parent PF
+        */
+       dev->hw_features = pf_dev->hw_features;
+       dev->gso_partial_features = pf_dev->gso_partial_features;
+       dev->vlan_features = pf_dev->vlan_features;
+       dev->hw_enc_features = pf_dev->hw_enc_features;
+       dev->features |= pf_dev->features;
+       bnxt_vf_rep_eth_addr_gen(bp->pf.mac_addr, vf_rep->vf_idx,
+                                dev->perm_addr);
+       ether_addr_copy(dev->dev_addr, dev->perm_addr);
+}
+
+static int bnxt_vf_reps_create(struct bnxt *bp)
+{
+       u16 *cfa_code_map = NULL, num_vfs = pci_num_vf(bp->pdev);
+       struct bnxt_vf_rep *vf_rep;
+       struct net_device *dev;
+       int rc, i;
+
+       bp->vf_reps = kcalloc(num_vfs, sizeof(vf_rep), GFP_KERNEL);
+       if (!bp->vf_reps)
+               return -ENOMEM;
+
+       /* storage for cfa_code to vf-idx mapping */
+       cfa_code_map = kmalloc(sizeof(*bp->cfa_code_map) * MAX_CFA_CODE,
+                              GFP_KERNEL);
+       if (!cfa_code_map) {
+               rc = -ENOMEM;
+               goto err;
+       }
+       for (i = 0; i < MAX_CFA_CODE; i++)
+               cfa_code_map[i] = VF_IDX_INVALID;
+
+       for (i = 0; i < num_vfs; i++) {
+               dev = alloc_etherdev(sizeof(*vf_rep));
+               if (!dev) {
+                       rc = -ENOMEM;
+                       goto err;
+               }
+
+               vf_rep = netdev_priv(dev);
+               bp->vf_reps[i] = vf_rep;
+               vf_rep->dev = dev;
+               vf_rep->bp = bp;
+               vf_rep->vf_idx = i;
+               vf_rep->tx_cfa_action = CFA_HANDLE_INVALID;
+
+               /* get cfa handles from FW */
+               rc = hwrm_cfa_vfr_alloc(bp, vf_rep->vf_idx,
+                                       &vf_rep->tx_cfa_action,
+                                       &vf_rep->rx_cfa_code);
+               if (rc) {
+                       rc = -ENOLINK;
+                       goto err;
+               }
+               cfa_code_map[vf_rep->rx_cfa_code] = vf_rep->vf_idx;
+
+               vf_rep->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX,
+                                                GFP_KERNEL);
+               if (!vf_rep->dst) {
+                       rc = -ENOMEM;
+                       goto err;
+               }
+               /* only cfa_action is needed to mux a packet while TXing */
+               vf_rep->dst->u.port_info.port_id = vf_rep->tx_cfa_action;
+               vf_rep->dst->u.port_info.lower_dev = bp->dev;
+
+               bnxt_vf_rep_netdev_init(bp, vf_rep, dev);
+               rc = register_netdev(dev);
+               if (rc) {
+                       /* no need for unregister_netdev in cleanup */
+                       dev->netdev_ops = NULL;
+                       goto err;
+               }
+       }
+
+       /* publish cfa_code_map only after all VF-reps have been initialized */
+       bp->cfa_code_map = cfa_code_map;
+       bp->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
+       netif_keep_dst(bp->dev);
+       return 0;
+
+err:
+       netdev_info(bp->dev, "%s error=%d", __func__, rc);
+       kfree(cfa_code_map);
+       __bnxt_vf_reps_destroy(bp);
+       return rc;
+}
+
+/* Devlink related routines */
+static int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode)
+{
+       struct bnxt *bp = bnxt_get_bp_from_dl(devlink);
+
+       *mode = bp->eswitch_mode;
+       return 0;
+}
+
+static int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode)
+{
+       struct bnxt *bp = bnxt_get_bp_from_dl(devlink);
+       int rc = 0;
+
+       mutex_lock(&bp->sriov_lock);
+       if (bp->eswitch_mode == mode) {
+               netdev_info(bp->dev, "already in %s eswitch mode",
+                           mode == DEVLINK_ESWITCH_MODE_LEGACY ?
+                           "legacy" : "switchdev");
+               rc = -EINVAL;
+               goto done;
+       }
+
+       switch (mode) {
+       case DEVLINK_ESWITCH_MODE_LEGACY:
+               bnxt_vf_reps_destroy(bp);
+               break;
+
+       case DEVLINK_ESWITCH_MODE_SWITCHDEV:
+               if (pci_num_vf(bp->pdev) == 0) {
+                       netdev_info(bp->dev,
+                                   "Enable VFs before setting swtichdev mode");
+                       rc = -EPERM;
+                       goto done;
+               }
+               rc = bnxt_vf_reps_create(bp);
+               break;
+
+       default:
+               rc = -EINVAL;
+               goto done;
+       }
+done:
+       mutex_unlock(&bp->sriov_lock);
+       return rc;
+}
+
+static const struct devlink_ops bnxt_dl_ops = {
+       .eswitch_mode_set = bnxt_dl_eswitch_mode_set,
+       .eswitch_mode_get = bnxt_dl_eswitch_mode_get
+};
+
+int bnxt_dl_register(struct bnxt *bp)
+{
+       struct devlink *dl;
+       int rc;
+
+       if (!pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV))
+               return 0;
+
+       if (bp->hwrm_spec_code < 0x10800) {
+               netdev_warn(bp->dev, "Firmware does not support SR-IOV E-Switch SWITCHDEV mode.\n");
+               return -ENOTSUPP;
+       }
+
+       dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
+       if (!dl) {
+               netdev_warn(bp->dev, "devlink_alloc failed");
+               return -ENOMEM;
+       }
+
+       bnxt_link_bp_to_dl(dl, bp);
+       bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
+       rc = devlink_register(dl, &bp->pdev->dev);
+       if (rc) {
+               bnxt_link_bp_to_dl(dl, NULL);
+               devlink_free(dl);
+               netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
+               return rc;
+       }
+
+       return 0;
+}
+
+void bnxt_dl_unregister(struct bnxt *bp)
+{
+       struct devlink *dl = bp->dl;
+
+       if (!dl)
+               return;
+
+       devlink_unregister(dl);
+       devlink_free(dl);
+}
+
+#endif
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h
new file mode 100644 (file)
index 0000000..e55a3b6
--- /dev/null
@@ -0,0 +1,72 @@
+/* Broadcom NetXtreme-C/E network driver.
+ *
+ * Copyright (c) 2016-2017 Broadcom Limited
+ *
+ * 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.
+ */
+
+#ifndef BNXT_VFR_H
+#define BNXT_VFR_H
+
+#ifdef CONFIG_BNXT_SRIOV
+
+#define        MAX_CFA_CODE                    65536
+
+/* Struct to hold housekeeping info needed by devlink interface */
+struct bnxt_dl {
+       struct bnxt *bp;        /* back ptr to the controlling dev */
+};
+
+static inline struct bnxt *bnxt_get_bp_from_dl(struct devlink *dl)
+{
+       return ((struct bnxt_dl *)devlink_priv(dl))->bp;
+}
+
+static inline void bnxt_link_bp_to_dl(struct devlink *dl, struct bnxt *bp)
+{
+       struct bnxt_dl *bp_dl = devlink_priv(dl);
+
+       bp_dl->bp = bp;
+       if (bp)
+               bp->dl = dl;
+}
+
+int bnxt_dl_register(struct bnxt *bp);
+void bnxt_dl_unregister(struct bnxt *bp);
+void bnxt_vf_reps_destroy(struct bnxt *bp);
+void bnxt_vf_reps_close(struct bnxt *bp);
+void bnxt_vf_reps_open(struct bnxt *bp);
+void bnxt_vf_rep_rx(struct bnxt *bp, struct sk_buff *skb);
+struct net_device *bnxt_get_vf_rep(struct bnxt *bp, u16 cfa_code);
+
+#else
+
+static inline int bnxt_dl_register(struct bnxt *bp)
+{
+       return 0;
+}
+
+static inline void bnxt_dl_unregister(struct bnxt *bp)
+{
+}
+
+static inline void bnxt_vf_reps_close(struct bnxt *bp)
+{
+}
+
+static inline void bnxt_vf_reps_open(struct bnxt *bp)
+{
+}
+
+static inline void bnxt_vf_rep_rx(struct bnxt *bp, struct sk_buff *skb)
+{
+}
+
+static inline struct net_device *bnxt_get_vf_rep(struct bnxt *bp, u16 cfa_code)
+{
+       return NULL;
+}
+#endif /* CONFIG_BNXT_SRIOV */
+#endif /* BNXT_VFR_H */
index daca1c9..a981c4e 100644 (file)
@@ -1202,12 +1202,21 @@ static struct enet_cb *bcmgenet_get_txcb(struct bcmgenet_priv *priv,
        return tx_cb_ptr;
 }
 
-/* Simple helper to free a control block's resources */
-static void bcmgenet_free_cb(struct enet_cb *cb)
+static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv,
+                                        struct bcmgenet_tx_ring *ring)
 {
-       dev_kfree_skb_any(cb->skb);
-       cb->skb = NULL;
-       dma_unmap_addr_set(cb, dma_addr, 0);
+       struct enet_cb *tx_cb_ptr;
+
+       tx_cb_ptr = ring->cbs;
+       tx_cb_ptr += ring->write_ptr - ring->cb_ptr;
+
+       /* Rewinding local write pointer */
+       if (ring->write_ptr == ring->cb_ptr)
+               ring->write_ptr = ring->end_ptr;
+       else
+               ring->write_ptr--;
+
+       return tx_cb_ptr;
 }
 
 static inline void bcmgenet_rx_ring16_int_disable(struct bcmgenet_rx_ring *ring)
@@ -1260,18 +1269,72 @@ static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_tx_ring *ring)
                                 INTRL2_CPU_MASK_SET);
 }
 
+/* Simple helper to free a transmit control block's resources
+ * Returns an skb when the last transmit control block associated with the
+ * skb is freed.  The skb should be freed by the caller if necessary.
+ */
+static struct sk_buff *bcmgenet_free_tx_cb(struct device *dev,
+                                          struct enet_cb *cb)
+{
+       struct sk_buff *skb;
+
+       skb = cb->skb;
+
+       if (skb) {
+               cb->skb = NULL;
+               if (cb == GENET_CB(skb)->first_cb)
+                       dma_unmap_single(dev, dma_unmap_addr(cb, dma_addr),
+                                        dma_unmap_len(cb, dma_len),
+                                        DMA_TO_DEVICE);
+               else
+                       dma_unmap_page(dev, dma_unmap_addr(cb, dma_addr),
+                                      dma_unmap_len(cb, dma_len),
+                                      DMA_TO_DEVICE);
+               dma_unmap_addr_set(cb, dma_addr, 0);
+
+               if (cb == GENET_CB(skb)->last_cb)
+                       return skb;
+
+       } else if (dma_unmap_addr(cb, dma_addr)) {
+               dma_unmap_page(dev,
+                              dma_unmap_addr(cb, dma_addr),
+                              dma_unmap_len(cb, dma_len),
+                              DMA_TO_DEVICE);
+               dma_unmap_addr_set(cb, dma_addr, 0);
+       }
+
+       return 0;
+}
+
+/* Simple helper to free a receive control block's resources */
+static struct sk_buff *bcmgenet_free_rx_cb(struct device *dev,
+                                          struct enet_cb *cb)
+{
+       struct sk_buff *skb;
+
+       skb = cb->skb;
+       cb->skb = NULL;
+
+       if (dma_unmap_addr(cb, dma_addr)) {
+               dma_unmap_single(dev, dma_unmap_addr(cb, dma_addr),
+                                dma_unmap_len(cb, dma_len), DMA_FROM_DEVICE);
+               dma_unmap_addr_set(cb, dma_addr, 0);
+       }
+
+       return skb;
+}
+
 /* Unlocked version of the reclaim routine */
 static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
                                          struct bcmgenet_tx_ring *ring)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
-       struct device *kdev = &priv->pdev->dev;
-       struct enet_cb *tx_cb_ptr;
-       unsigned int pkts_compl = 0;
+       unsigned int txbds_processed = 0;
        unsigned int bytes_compl = 0;
-       unsigned int c_index;
+       unsigned int pkts_compl = 0;
        unsigned int txbds_ready;
-       unsigned int txbds_processed = 0;
+       unsigned int c_index;
+       struct sk_buff *skb;
 
        /* Clear status before servicing to reduce spurious interrupts */
        if (ring->index == DESC_INDEX)
@@ -1292,21 +1355,12 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
 
        /* Reclaim transmitted buffers */
        while (txbds_processed < txbds_ready) {
-               tx_cb_ptr = &priv->tx_cbs[ring->clean_ptr];
-               if (tx_cb_ptr->skb) {
+               skb = bcmgenet_free_tx_cb(&priv->pdev->dev,
+                                         &priv->tx_cbs[ring->clean_ptr]);
+               if (skb) {
                        pkts_compl++;
-                       bytes_compl += GENET_CB(tx_cb_ptr->skb)->bytes_sent;
-                       dma_unmap_single(kdev,
-                                        dma_unmap_addr(tx_cb_ptr, dma_addr),
-                                        dma_unmap_len(tx_cb_ptr, dma_len),
-                                        DMA_TO_DEVICE);
-                       bcmgenet_free_cb(tx_cb_ptr);
-               } else if (dma_unmap_addr(tx_cb_ptr, dma_addr)) {
-                       dma_unmap_page(kdev,
-                                      dma_unmap_addr(tx_cb_ptr, dma_addr),
-                                      dma_unmap_len(tx_cb_ptr, dma_len),
-                                      DMA_TO_DEVICE);
-                       dma_unmap_addr_set(tx_cb_ptr, dma_addr, 0);
+                       bytes_compl += GENET_CB(skb)->bytes_sent;
+                       dev_kfree_skb_any(skb);
                }
 
                txbds_processed++;
@@ -1380,95 +1434,6 @@ static void bcmgenet_tx_reclaim_all(struct net_device *dev)
        bcmgenet_tx_reclaim(dev, &priv->tx_rings[DESC_INDEX]);
 }
 
-/* Transmits a single SKB (either head of a fragment or a single SKB)
- * caller must hold priv->lock
- */
-static int bcmgenet_xmit_single(struct net_device *dev,
-                               struct sk_buff *skb,
-                               u16 dma_desc_flags,
-                               struct bcmgenet_tx_ring *ring)
-{
-       struct bcmgenet_priv *priv = netdev_priv(dev);
-       struct device *kdev = &priv->pdev->dev;
-       struct enet_cb *tx_cb_ptr;
-       unsigned int skb_len;
-       dma_addr_t mapping;
-       u32 length_status;
-       int ret;
-
-       tx_cb_ptr = bcmgenet_get_txcb(priv, ring);
-
-       if (unlikely(!tx_cb_ptr))
-               BUG();
-
-       tx_cb_ptr->skb = skb;
-
-       skb_len = skb_headlen(skb);
-
-       mapping = dma_map_single(kdev, skb->data, skb_len, DMA_TO_DEVICE);
-       ret = dma_mapping_error(kdev, mapping);
-       if (ret) {
-               priv->mib.tx_dma_failed++;
-               netif_err(priv, tx_err, dev, "Tx DMA map failed\n");
-               dev_kfree_skb(skb);
-               return ret;
-       }
-
-       dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);
-       dma_unmap_len_set(tx_cb_ptr, dma_len, skb_len);
-       length_status = (skb_len << DMA_BUFLENGTH_SHIFT) | dma_desc_flags |
-                       (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT) |
-                       DMA_TX_APPEND_CRC;
-
-       if (skb->ip_summed == CHECKSUM_PARTIAL)
-               length_status |= DMA_TX_DO_CSUM;
-
-       dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping, length_status);
-
-       return 0;
-}
-
-/* Transmit a SKB fragment */
-static int bcmgenet_xmit_frag(struct net_device *dev,
-                             skb_frag_t *frag,
-                             u16 dma_desc_flags,
-                             struct bcmgenet_tx_ring *ring)
-{
-       struct bcmgenet_priv *priv = netdev_priv(dev);
-       struct device *kdev = &priv->pdev->dev;
-       struct enet_cb *tx_cb_ptr;
-       unsigned int frag_size;
-       dma_addr_t mapping;
-       int ret;
-
-       tx_cb_ptr = bcmgenet_get_txcb(priv, ring);
-
-       if (unlikely(!tx_cb_ptr))
-               BUG();
-
-       tx_cb_ptr->skb = NULL;
-
-       frag_size = skb_frag_size(frag);
-
-       mapping = skb_frag_dma_map(kdev, frag, 0, frag_size, DMA_TO_DEVICE);
-       ret = dma_mapping_error(kdev, mapping);
-       if (ret) {
-               priv->mib.tx_dma_failed++;
-               netif_err(priv, tx_err, dev, "%s: Tx DMA map failed\n",
-                         __func__);
-               return ret;
-       }
-
-       dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);
-       dma_unmap_len_set(tx_cb_ptr, dma_len, frag_size);
-
-       dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping,
-                   (frag_size << DMA_BUFLENGTH_SHIFT) | dma_desc_flags |
-                   (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT));
-
-       return 0;
-}
-
 /* Reallocate the SKB to put enough headroom in front of it and insert
  * the transmit checksum offsets in the descriptors
  */
@@ -1535,11 +1500,16 @@ static struct sk_buff *bcmgenet_put_tx_csum(struct net_device *dev,
 static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
+       struct device *kdev = &priv->pdev->dev;
        struct bcmgenet_tx_ring *ring = NULL;
+       struct enet_cb *tx_cb_ptr;
        struct netdev_queue *txq;
        unsigned long flags = 0;
        int nr_frags, index;
-       u16 dma_desc_flags;
+       dma_addr_t mapping;
+       unsigned int size;
+       skb_frag_t *frag;
+       u32 len_stat;
        int ret;
        int i;
 
@@ -1592,29 +1562,53 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        }
 
-       dma_desc_flags = DMA_SOP;
-       if (nr_frags == 0)
-               dma_desc_flags |= DMA_EOP;
+       for (i = 0; i <= nr_frags; i++) {
+               tx_cb_ptr = bcmgenet_get_txcb(priv, ring);
 
-       /* Transmit single SKB or head of fragment list */
-       ret = bcmgenet_xmit_single(dev, skb, dma_desc_flags, ring);
-       if (ret) {
-               ret = NETDEV_TX_OK;
-               goto out;
-       }
+               if (unlikely(!tx_cb_ptr))
+                       BUG();
+
+               if (!i) {
+                       /* Transmit single SKB or head of fragment list */
+                       GENET_CB(skb)->first_cb = tx_cb_ptr;
+                       size = skb_headlen(skb);
+                       mapping = dma_map_single(kdev, skb->data, size,
+                                                DMA_TO_DEVICE);
+               } else {
+                       /* xmit fragment */
+                       frag = &skb_shinfo(skb)->frags[i - 1];
+                       size = skb_frag_size(frag);
+                       mapping = skb_frag_dma_map(kdev, frag, 0, size,
+                                                  DMA_TO_DEVICE);
+               }
 
-       /* xmit fragment */
-       for (i = 0; i < nr_frags; i++) {
-               ret = bcmgenet_xmit_frag(dev,
-                                        &skb_shinfo(skb)->frags[i],
-                                        (i == nr_frags - 1) ? DMA_EOP : 0,
-                                        ring);
+               ret = dma_mapping_error(kdev, mapping);
                if (ret) {
+                       priv->mib.tx_dma_failed++;
+                       netif_err(priv, tx_err, dev, "Tx DMA map failed\n");
                        ret = NETDEV_TX_OK;
-                       goto out;
+                       goto out_unmap_frags;
+               }
+               dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);
+               dma_unmap_len_set(tx_cb_ptr, dma_len, size);
+
+               tx_cb_ptr->skb = skb;
+
+               len_stat = (size << DMA_BUFLENGTH_SHIFT) |
+                          (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT);
+
+               if (!i) {
+                       len_stat |= DMA_TX_APPEND_CRC | DMA_SOP;
+                       if (skb->ip_summed == CHECKSUM_PARTIAL)
+                               len_stat |= DMA_TX_DO_CSUM;
                }
+               if (i == nr_frags)
+                       len_stat |= DMA_EOP;
+
+               dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping, len_stat);
        }
 
+       GENET_CB(skb)->last_cb = tx_cb_ptr;
        skb_tx_timestamp(skb);
 
        /* Decrement total BD count and advance our write pointer */
@@ -1635,6 +1629,19 @@ out:
        spin_unlock_irqrestore(&ring->lock, flags);
 
        return ret;
+
+out_unmap_frags:
+       /* Back up for failed control block mapping */
+       bcmgenet_put_txcb(priv, ring);
+
+       /* Unmap successfully mapped control blocks */
+       while (i-- > 0) {
+               tx_cb_ptr = bcmgenet_put_txcb(priv, ring);
+               bcmgenet_free_tx_cb(kdev, tx_cb_ptr);
+       }
+
+       dev_kfree_skb(skb);
+       goto out;
 }
 
 static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv,
@@ -1666,14 +1673,12 @@ static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv,
        }
 
        /* Grab the current Rx skb from the ring and DMA-unmap it */
-       rx_skb = cb->skb;
-       if (likely(rx_skb))
-               dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
-                                priv->rx_buf_len, DMA_FROM_DEVICE);
+       rx_skb = bcmgenet_free_rx_cb(kdev, cb);
 
        /* Put the new Rx skb on the ring */
        cb->skb = skb;
        dma_unmap_addr_set(cb, dma_addr, mapping);
+       dma_unmap_len_set(cb, dma_len, priv->rx_buf_len);
        dmadesc_set_addr(priv, cb->bd_addr, mapping);
 
        /* Return the current Rx skb to caller */
@@ -1880,22 +1885,16 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv,
 
 static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)
 {
-       struct device *kdev = &priv->pdev->dev;
+       struct sk_buff *skb;
        struct enet_cb *cb;
        int i;
 
        for (i = 0; i < priv->num_rx_bds; i++) {
                cb = &priv->rx_cbs[i];
 
-               if (dma_unmap_addr(cb, dma_addr)) {
-                       dma_unmap_single(kdev,
-                                        dma_unmap_addr(cb, dma_addr),
-                                        priv->rx_buf_len, DMA_FROM_DEVICE);
-                       dma_unmap_addr_set(cb, dma_addr, 0);
-               }
-
-               if (cb->skb)
-                       bcmgenet_free_cb(cb);
+               skb = bcmgenet_free_rx_cb(&priv->pdev->dev, cb);
+               if (skb)
+                       dev_kfree_skb_any(skb);
        }
 }
 
@@ -2479,8 +2478,10 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv)
 
 static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
 {
-       int i;
        struct netdev_queue *txq;
+       struct sk_buff *skb;
+       struct enet_cb *cb;
+       int i;
 
        bcmgenet_fini_rx_napi(priv);
        bcmgenet_fini_tx_napi(priv);
@@ -2489,10 +2490,10 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
        bcmgenet_dma_teardown(priv);
 
        for (i = 0; i < priv->num_tx_bds; i++) {
-               if (priv->tx_cbs[i].skb != NULL) {
-                       dev_kfree_skb(priv->tx_cbs[i].skb);
-                       priv->tx_cbs[i].skb = NULL;
-               }
+               cb = priv->tx_cbs + i;
+               skb = bcmgenet_free_tx_cb(&priv->pdev->dev, cb);
+               if (skb)
+                       dev_kfree_skb(skb);
        }
 
        for (i = 0; i < priv->hw_params->tx_queues; i++) {
@@ -3668,7 +3669,7 @@ static int bcmgenet_resume(struct device *d)
 
        phy_init_hw(priv->phydev);
        /* Speed settings must be restored */
-       bcmgenet_mii_config(priv->dev);
+       bcmgenet_mii_config(priv->dev, false);
 
        /* disable ethernet MAC while updating its registers */
        umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false);
index efd0702..b1fdd3c 100644 (file)
@@ -544,6 +544,8 @@ struct bcmgenet_hw_params {
 };
 
 struct bcmgenet_skb_cb {
+       struct enet_cb *first_cb;       /* First control block of SKB */
+       struct enet_cb *last_cb;        /* Last control block of SKB */
        unsigned int bytes_sent;        /* bytes on the wire (no TSB) */
 };
 
@@ -655,6 +657,7 @@ struct bcmgenet_priv {
 
        struct clk *clk;
        struct platform_device *pdev;
+       struct platform_device *mii_pdev;
 
        /* WOL */
        struct clk *clk_wol;
@@ -696,7 +699,7 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF);
 
 /* MDIO routines */
 int bcmgenet_mii_init(struct net_device *dev);
-int bcmgenet_mii_config(struct net_device *dev);
+int bcmgenet_mii_config(struct net_device *dev, bool init);
 int bcmgenet_mii_probe(struct net_device *dev);
 void bcmgenet_mii_exit(struct net_device *dev);
 void bcmgenet_mii_reset(struct net_device *dev);
index 071fcbd..18f5723 100644 (file)
 #include <linux/of_net.h>
 #include <linux/of_mdio.h>
 #include <linux/platform_data/bcmgenet.h>
+#include <linux/platform_data/mdio-bcm-unimac.h>
 
 #include "bcmgenet.h"
 
-/* read a value from the MII */
-static int bcmgenet_mii_read(struct mii_bus *bus, int phy_id, int location)
-{
-       int ret;
-       struct net_device *dev = bus->priv;
-       struct bcmgenet_priv *priv = netdev_priv(dev);
-       u32 reg;
-
-       bcmgenet_umac_writel(priv, (MDIO_RD | (phy_id << MDIO_PMD_SHIFT) |
-                            (location << MDIO_REG_SHIFT)), UMAC_MDIO_CMD);
-       /* Start MDIO transaction*/
-       reg = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
-       reg |= MDIO_START_BUSY;
-       bcmgenet_umac_writel(priv, reg, UMAC_MDIO_CMD);
-       wait_event_timeout(priv->wq,
-                          !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD)
-                          & MDIO_START_BUSY),
-                          HZ / 100);
-       ret = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
-
-       /* Some broken devices are known not to release the line during
-        * turn-around, e.g: Broadcom BCM53125 external switches, so check for
-        * that condition here and ignore the MDIO controller read failure
-        * indication.
-        */
-       if (!(bus->phy_ignore_ta_mask & 1 << phy_id) && (ret & MDIO_READ_FAIL))
-               return -EIO;
-
-       return ret & 0xffff;
-}
-
-/* write a value to the MII */
-static int bcmgenet_mii_write(struct mii_bus *bus, int phy_id,
-                             int location, u16 val)
-{
-       struct net_device *dev = bus->priv;
-       struct bcmgenet_priv *priv = netdev_priv(dev);
-       u32 reg;
-
-       bcmgenet_umac_writel(priv, (MDIO_WR | (phy_id << MDIO_PMD_SHIFT) |
-                            (location << MDIO_REG_SHIFT) | (0xffff & val)),
-                            UMAC_MDIO_CMD);
-       reg = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
-       reg |= MDIO_START_BUSY;
-       bcmgenet_umac_writel(priv, reg, UMAC_MDIO_CMD);
-       wait_event_timeout(priv->wq,
-                          !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD) &
-                          MDIO_START_BUSY),
-                          HZ / 100);
-
-       return 0;
-}
-
 /* setup netdev link state when PHY link status change and
  * update UMAC and RGMII block when link up
  */
@@ -238,7 +186,7 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
                                          bcmgenet_fixed_phy_link_update);
 }
 
-int bcmgenet_mii_config(struct net_device *dev)
+int bcmgenet_mii_config(struct net_device *dev, bool init)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
        struct phy_device *phydev = priv->phydev;
@@ -327,7 +275,8 @@ int bcmgenet_mii_config(struct net_device *dev)
                bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
        }
 
-       dev_info_once(kdev, "configuring instance for %s\n", phy_name);
+       if (init)
+               dev_info(kdev, "configuring instance for %s\n", phy_name);
 
        return 0;
 }
@@ -375,7 +324,7 @@ int bcmgenet_mii_probe(struct net_device *dev)
         * PHY speed which is needed for bcmgenet_mii_config() to configure
         * things appropriately.
         */
-       ret = bcmgenet_mii_config(dev);
+       ret = bcmgenet_mii_config(dev, true);
        if (ret) {
                phy_disconnect(priv->phydev);
                return ret;
@@ -392,104 +341,121 @@ int bcmgenet_mii_probe(struct net_device *dev)
        return 0;
 }
 
-/* Workaround for integrated BCM7xxx Gigabit PHYs which have a problem with
- * their internal MDIO management controller making them fail to successfully
- * be read from or written to for the first transaction.  We insert a dummy
- * BMSR read here to make sure that phy_get_device() and get_phy_id() can
- * correctly read the PHY MII_PHYSID1/2 registers and successfully register a
- * PHY device for this peripheral.
- *
- * Once the PHY driver is registered, we can workaround subsequent reads from
- * there (e.g: during system-wide power management).
- *
- * bus->reset is invoked before mdiobus_scan during mdiobus_register and is
- * therefore the right location to stick that workaround. Since we do not want
- * to read from non-existing PHYs, we either use bus->phy_mask or do a manual
- * Device Tree scan to limit the search area.
- */
-static int bcmgenet_mii_bus_reset(struct mii_bus *bus)
+static struct device_node *bcmgenet_mii_of_find_mdio(struct bcmgenet_priv *priv)
 {
-       struct net_device *dev = bus->priv;
-       struct bcmgenet_priv *priv = netdev_priv(dev);
-       struct device_node *np = priv->mdio_dn;
-       struct device_node *child = NULL;
-       u32 read_mask = 0;
-       int addr = 0;
+       struct device_node *dn = priv->pdev->dev.of_node;
+       struct device *kdev = &priv->pdev->dev;
+       char *compat;
 
-       if (!np) {
-               read_mask = 1 << priv->phy_addr;
-       } else {
-               for_each_available_child_of_node(np, child) {
-                       addr = of_mdio_parse_addr(&dev->dev, child);
-                       if (addr < 0)
-                               continue;
+       compat = kasprintf(GFP_KERNEL, "brcm,genet-mdio-v%d", priv->version);
+       if (!compat)
+               return NULL;
 
-                       read_mask |= 1 << addr;
-               }
+       priv->mdio_dn = of_find_compatible_node(dn, NULL, compat);
+       kfree(compat);
+       if (!priv->mdio_dn) {
+               dev_err(kdev, "unable to find MDIO bus node\n");
+               return NULL;
        }
 
-       for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
-               if (read_mask & 1 << addr) {
-                       dev_dbg(&dev->dev, "Workaround for PHY @ %d\n", addr);
-                       mdiobus_read(bus, addr, MII_BMSR);
-               }
+       return priv->mdio_dn;
+}
+
+static void bcmgenet_mii_pdata_init(struct bcmgenet_priv *priv,
+                                   struct unimac_mdio_pdata *ppd)
+{
+       struct device *kdev = &priv->pdev->dev;
+       struct bcmgenet_platform_data *pd = kdev->platform_data;
+
+       if (pd->phy_interface != PHY_INTERFACE_MODE_MOCA && pd->mdio_enabled) {
+               /*
+                * Internal or external PHY with MDIO access
+                */
+               if (pd->phy_address >= 0 && pd->phy_address < PHY_MAX_ADDR)
+                       ppd->phy_mask = 1 << pd->phy_address;
+               else
+                       ppd->phy_mask = 0;
        }
+}
 
+static int bcmgenet_mii_wait(void *wait_func_data)
+{
+       struct bcmgenet_priv *priv = wait_func_data;
+
+       wait_event_timeout(priv->wq,
+                          !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD)
+                          & MDIO_START_BUSY),
+                          HZ / 100);
        return 0;
 }
 
-static int bcmgenet_mii_alloc(struct bcmgenet_priv *priv)
+static int bcmgenet_mii_register(struct bcmgenet_priv *priv)
 {
-       struct mii_bus *bus;
+       struct platform_device *pdev = priv->pdev;
+       struct bcmgenet_platform_data *pdata = pdev->dev.platform_data;
+       struct device_node *dn = pdev->dev.of_node;
+       struct unimac_mdio_pdata ppd;
+       struct platform_device *ppdev;
+       struct resource *pres, res;
+       int id, ret;
+
+       pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       memset(&res, 0, sizeof(res));
+       memset(&ppd, 0, sizeof(ppd));
+
+       ppd.wait_func = bcmgenet_mii_wait;
+       ppd.wait_func_data = priv;
+       ppd.bus_name = "bcmgenet MII bus";
+
+       /* Unimac MDIO bus controller starts at UniMAC offset + MDIO_CMD
+        * and is 2 * 32-bits word long, 8 bytes total.
+        */
+       res.start = pres->start + GENET_UMAC_OFF + UMAC_MDIO_CMD;
+       res.end = res.start + 8;
+       res.flags = IORESOURCE_MEM;
 
-       if (priv->mii_bus)
-               return 0;
+       if (dn)
+               id = of_alias_get_id(dn, "eth");
+       else
+               id = pdev->id;
 
-       priv->mii_bus = mdiobus_alloc();
-       if (!priv->mii_bus) {
-               pr_err("failed to allocate\n");
+       ppdev = platform_device_alloc(UNIMAC_MDIO_DRV_NAME, id);
+       if (!ppdev)
                return -ENOMEM;
-       }
 
-       bus = priv->mii_bus;
-       bus->priv = priv->dev;
-       bus->name = "bcmgenet MII bus";
-       bus->parent = &priv->pdev->dev;
-       bus->read = bcmgenet_mii_read;
-       bus->write = bcmgenet_mii_write;
-       bus->reset = bcmgenet_mii_bus_reset;
-       snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d",
-                priv->pdev->name, priv->pdev->id);
+       /* Retain this platform_device pointer for later cleanup */
+       priv->mii_pdev = ppdev;
+       ppdev->dev.parent = &pdev->dev;
+       ppdev->dev.of_node = bcmgenet_mii_of_find_mdio(priv);
+       if (pdata)
+               bcmgenet_mii_pdata_init(priv, &ppd);
+
+       ret = platform_device_add_resources(ppdev, &res, 1);
+       if (ret)
+               goto out;
+
+       ret = platform_device_add_data(ppdev, &ppd, sizeof(ppd));
+       if (ret)
+               goto out;
+
+       ret = platform_device_add(ppdev);
+       if (ret)
+               goto out;
 
        return 0;
+out:
+       platform_device_put(ppdev);
+       return ret;
 }
 
 static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv)
 {
        struct device_node *dn = priv->pdev->dev.of_node;
        struct device *kdev = &priv->pdev->dev;
-       struct phy_device *phydev = NULL;
-       char *compat;
+       struct phy_device *phydev;
        int phy_mode;
        int ret;
 
-       compat = kasprintf(GFP_KERNEL, "brcm,genet-mdio-v%d", priv->version);
-       if (!compat)
-               return -ENOMEM;
-
-       priv->mdio_dn = of_find_compatible_node(dn, NULL, compat);
-       kfree(compat);
-       if (!priv->mdio_dn) {
-               dev_err(kdev, "unable to find MDIO bus node\n");
-               return -ENODEV;
-       }
-
-       ret = of_mdiobus_register(priv->mii_bus, priv->mdio_dn);
-       if (ret) {
-               dev_err(kdev, "failed to register MDIO bus\n");
-               return ret;
-       }
-
        /* Fetch the PHY phandle */
        priv->phy_dn = of_parse_phandle(dn, "phy-handle", 0);
 
@@ -536,33 +502,23 @@ static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv)
 {
        struct device *kdev = &priv->pdev->dev;
        struct bcmgenet_platform_data *pd = kdev->platform_data;
-       struct mii_bus *mdio = priv->mii_bus;
+       char phy_name[MII_BUS_ID_SIZE + 3];
+       char mdio_bus_id[MII_BUS_ID_SIZE];
        struct phy_device *phydev;
-       int ret;
+
+       snprintf(mdio_bus_id, MII_BUS_ID_SIZE, "%s-%d",
+                UNIMAC_MDIO_DRV_NAME, priv->pdev->id);
 
        if (pd->phy_interface != PHY_INTERFACE_MODE_MOCA && pd->mdio_enabled) {
+               snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT,
+                        mdio_bus_id, pd->phy_address);
+
                /*
                 * Internal or external PHY with MDIO access
                 */
-               if (pd->phy_address >= 0 && pd->phy_address < PHY_MAX_ADDR)
-                       mdio->phy_mask = ~(1 << pd->phy_address);
-               else
-                       mdio->phy_mask = 0;
-
-               ret = mdiobus_register(mdio);
-               if (ret) {
-                       dev_err(kdev, "failed to register MDIO bus\n");
-                       return ret;
-               }
-
-               if (pd->phy_address >= 0 && pd->phy_address < PHY_MAX_ADDR)
-                       phydev = mdiobus_get_phy(mdio, pd->phy_address);
-               else
-                       phydev = phy_find_first(mdio);
-
+               phydev = phy_attach(priv->dev, phy_name, pd->phy_interface);
                if (!phydev) {
                        dev_err(kdev, "failed to register PHY device\n");
-                       mdiobus_unregister(mdio);
                        return -ENODEV;
                }
        } else {
@@ -608,10 +564,9 @@ static int bcmgenet_mii_bus_init(struct bcmgenet_priv *priv)
 int bcmgenet_mii_init(struct net_device *dev)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
-       struct device_node *dn = priv->pdev->dev.of_node;
        int ret;
 
-       ret = bcmgenet_mii_alloc(priv);
+       ret = bcmgenet_mii_register(priv);
        if (ret)
                return ret;
 
@@ -622,11 +577,7 @@ int bcmgenet_mii_init(struct net_device *dev)
        return 0;
 
 out:
-       if (of_phy_is_fixed_link(dn))
-               of_phy_deregister_fixed_link(dn);
-       of_node_put(priv->phy_dn);
-       mdiobus_unregister(priv->mii_bus);
-       mdiobus_free(priv->mii_bus);
+       bcmgenet_mii_exit(dev);
        return ret;
 }
 
@@ -638,6 +589,6 @@ void bcmgenet_mii_exit(struct net_device *dev)
        if (of_phy_is_fixed_link(dn))
                of_phy_deregister_fixed_link(dn);
        of_node_put(priv->phy_dn);
-       mdiobus_unregister(priv->mii_bus);
-       mdiobus_free(priv->mii_bus);
+       platform_device_unregister(priv->mii_pdev);
+       platform_device_put(priv->mii_pdev);
 }
index 976a50f..09e2875 100644 (file)
@@ -336,7 +336,7 @@ lio_ethtool_get_channels(struct net_device *dev,
 
 static int lio_get_eeprom_len(struct net_device *netdev)
 {
-       u8 buf[128];
+       u8 buf[192];
        struct lio *lio = GET_LIO(netdev);
        struct octeon_device *oct_dev = lio->oct_dev;
        struct octeon_board_info *board_info;
index 53aaf41..3b9e364 100644 (file)
@@ -27,8 +27,8 @@
 
 #define LIQUIDIO_PACKAGE ""
 #define LIQUIDIO_BASE_MAJOR_VERSION 1
-#define LIQUIDIO_BASE_MINOR_VERSION 5
-#define LIQUIDIO_BASE_MICRO_VERSION 1
+#define LIQUIDIO_BASE_MINOR_VERSION 6
+#define LIQUIDIO_BASE_MICRO_VERSION 0
 #define LIQUIDIO_BASE_VERSION   __stringify(LIQUIDIO_BASE_MAJOR_VERSION) "." \
                                __stringify(LIQUIDIO_BASE_MINOR_VERSION)
 #define LIQUIDIO_MICRO_VERSION  "." __stringify(LIQUIDIO_BASE_MICRO_VERSION)
@@ -768,6 +768,7 @@ struct nic_rx_stats {
        /* firmware stats */
        u64 fw_total_rcvd;
        u64 fw_total_fwd;
+       u64 fw_total_fwd_bytes;
        u64 fw_err_pko;
        u64 fw_err_link;
        u64 fw_err_drop;
index e08f760..15ad1ab 100644 (file)
@@ -42,9 +42,6 @@ module_param(console_bitmask, int, 0644);
 MODULE_PARM_DESC(console_bitmask,
                 "Bitmask indicating which consoles have debug output redirected to syslog.");
 
-#define MIN(a, b) min((a), (b))
-#define CAST_ULL(v) ((u64)(v))
-
 #define BOOTLOADER_PCI_READ_BUFFER_DATA_ADDR    0x0006c008
 #define BOOTLOADER_PCI_READ_BUFFER_LEN_ADDR     0x0006c004
 #define BOOTLOADER_PCI_READ_BUFFER_OWNER_ADDR   0x0006c000
@@ -234,7 +231,7 @@ static int __cvmx_bootmem_check_version(struct octeon_device *oct,
            (exact_match && major_version != exact_match)) {
                dev_err(&oct->pci_dev->dev, "bootmem ver mismatch %d.%d addr:0x%llx\n",
                        major_version, minor_version,
-                       CAST_ULL(oct->bootmem_desc_addr));
+                       (long long)oct->bootmem_desc_addr);
                return -1;
        } else {
                return 0;
@@ -704,7 +701,7 @@ static int octeon_console_read(struct octeon_device *oct, u32 console_num,
        if (bytes_to_read <= 0)
                return bytes_to_read;
 
-       bytes_to_read = MIN(bytes_to_read, (s32)buf_size);
+       bytes_to_read = min_t(s32, bytes_to_read, buf_size);
 
        /* Check to see if what we want to read is not contiguous, and limit
         * ourselves to the contiguous block
index c90ed48..ad46478 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef _OCTEON_DEVICE_H_
 #define  _OCTEON_DEVICE_H_
 
+#include <linux/interrupt.h>
+
 /** PCI VendorId Device Id */
 #define  OCTEON_CN68XX_PCIID          0x91177d
 #define  OCTEON_CN66XX_PCIID          0x92177d
index a0ca68c..5e5c4d7 100644 (file)
@@ -292,11 +292,30 @@ static void bgx_sgmii_change_link_state(struct lmac *lmac)
        u64 cmr_cfg;
        u64 port_cfg = 0;
        u64 misc_ctl = 0;
+       bool tx_en, rx_en;
 
        cmr_cfg = bgx_reg_read(bgx, lmac->lmacid, BGX_CMRX_CFG);
-       cmr_cfg &= ~CMR_EN;
+       tx_en = cmr_cfg & CMR_PKT_TX_EN;
+       rx_en = cmr_cfg & CMR_PKT_RX_EN;
+       cmr_cfg &= ~(CMR_PKT_RX_EN | CMR_PKT_TX_EN);
        bgx_reg_write(bgx, lmac->lmacid, BGX_CMRX_CFG, cmr_cfg);
 
+       /* Wait for BGX RX to be idle */
+       if (bgx_poll_reg(bgx, lmac->lmacid, BGX_GMP_GMI_PRTX_CFG,
+                        GMI_PORT_CFG_RX_IDLE, false)) {
+               dev_err(&bgx->pdev->dev, "BGX%d LMAC%d GMI RX not idle\n",
+                       bgx->bgx_id, lmac->lmacid);
+               return;
+       }
+
+       /* Wait for BGX TX to be idle */
+       if (bgx_poll_reg(bgx, lmac->lmacid, BGX_GMP_GMI_PRTX_CFG,
+                        GMI_PORT_CFG_TX_IDLE, false)) {
+               dev_err(&bgx->pdev->dev, "BGX%d LMAC%d GMI TX not idle\n",
+                       bgx->bgx_id, lmac->lmacid);
+               return;
+       }
+
        port_cfg = bgx_reg_read(bgx, lmac->lmacid, BGX_GMP_GMI_PRTX_CFG);
        misc_ctl = bgx_reg_read(bgx, lmac->lmacid, BGX_GMP_PCS_MISCX_CTL);
 
@@ -347,10 +366,8 @@ static void bgx_sgmii_change_link_state(struct lmac *lmac)
        bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_PCS_MISCX_CTL, misc_ctl);
        bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_PRTX_CFG, port_cfg);
 
-       port_cfg = bgx_reg_read(bgx, lmac->lmacid, BGX_GMP_GMI_PRTX_CFG);
-
-       /* Re-enable lmac */
-       cmr_cfg |= CMR_EN;
+       /* Restore CMR config settings */
+       cmr_cfg |= (rx_en ? CMR_PKT_RX_EN : 0) | (tx_en ? CMR_PKT_TX_EN : 0);
        bgx_reg_write(bgx, lmac->lmacid, BGX_CMRX_CFG, cmr_cfg);
 
        if (bgx->is_rgx && (cmr_cfg & (CMR_PKT_RX_EN | CMR_PKT_TX_EN)))
@@ -1008,7 +1025,7 @@ static void bgx_print_qlm_mode(struct bgx *bgx, u8 lmacid)
 {
        struct device *dev = &bgx->pdev->dev;
        struct lmac *lmac;
-       char str[20];
+       char str[27];
 
        if (!bgx->is_dlm && lmacid)
                return;
index 6b7fe6f..23acdc5 100644 (file)
 #define  GMI_PORT_CFG_DUPLEX                   BIT_ULL(2)
 #define  GMI_PORT_CFG_SLOT_TIME                        BIT_ULL(3)
 #define  GMI_PORT_CFG_SPEED_MSB                        BIT_ULL(8)
+#define  GMI_PORT_CFG_RX_IDLE                  BIT_ULL(12)
+#define  GMI_PORT_CFG_TX_IDLE                  BIT_ULL(13)
 #define BGX_GMP_GMI_RXX_JABBER         0x38038
 #define BGX_GMP_GMI_TXX_THRESH         0x38210
 #define BGX_GMP_GMI_TXX_APPEND         0x38218
index ef4be78..1978abb 100644 (file)
@@ -338,10 +338,12 @@ struct adapter_params {
        unsigned int sf_nsec;             /* # of flash sectors */
        unsigned int sf_fw_start;         /* start of FW image in flash */
 
-       unsigned int fw_vers;
-       unsigned int bs_vers;           /* bootstrap version */
-       unsigned int tp_vers;
-       unsigned int er_vers;           /* expansion ROM version */
+       unsigned int fw_vers;             /* firmware version */
+       unsigned int bs_vers;             /* bootstrap version */
+       unsigned int tp_vers;             /* TP microcode version */
+       unsigned int er_vers;             /* expansion ROM version */
+       unsigned int scfg_vers;           /* Serial Configuration version */
+       unsigned int vpd_vers;            /* VPD Version */
        u8 api_vers[7];
 
        unsigned short mtus[NMTUS];
@@ -1407,6 +1409,10 @@ int t4_get_fw_version(struct adapter *adapter, u32 *vers);
 int t4_get_bs_version(struct adapter *adapter, u32 *vers);
 int t4_get_tp_version(struct adapter *adapter, u32 *vers);
 int t4_get_exprom_version(struct adapter *adapter, u32 *vers);
+int t4_get_scfg_version(struct adapter *adapter, u32 *vers);
+int t4_get_vpd_version(struct adapter *adapter, u32 *vers);
+int t4_get_version_info(struct adapter *adapter);
+void t4_dump_version_info(struct adapter *adapter);
 int t4_prep_fw(struct adapter *adap, struct fw_info *fw_info,
               const u8 *fw_data, unsigned int fw_size,
               struct fw_hdr *card_fw, enum dev_state state, int *reset);
index 26eb00a..03f593e 100644 (file)
@@ -801,6 +801,104 @@ static int set_link_ksettings(struct net_device *dev,
        return ret;
 }
 
+/* Translate the Firmware FEC value into the ethtool value. */
+static inline unsigned int fwcap_to_eth_fec(unsigned int fw_fec)
+{
+       unsigned int eth_fec = 0;
+
+       if (fw_fec & FW_PORT_CAP_FEC_RS)
+               eth_fec |= ETHTOOL_FEC_RS;
+       if (fw_fec & FW_PORT_CAP_FEC_BASER_RS)
+               eth_fec |= ETHTOOL_FEC_BASER;
+
+       /* if nothing is set, then FEC is off */
+       if (!eth_fec)
+               eth_fec = ETHTOOL_FEC_OFF;
+
+       return eth_fec;
+}
+
+/* Translate Common Code FEC value into ethtool value. */
+static inline unsigned int cc_to_eth_fec(unsigned int cc_fec)
+{
+       unsigned int eth_fec = 0;
+
+       if (cc_fec & FEC_AUTO)
+               eth_fec |= ETHTOOL_FEC_AUTO;
+       if (cc_fec & FEC_RS)
+               eth_fec |= ETHTOOL_FEC_RS;
+       if (cc_fec & FEC_BASER_RS)
+               eth_fec |= ETHTOOL_FEC_BASER;
+
+       /* if nothing is set, then FEC is off */
+       if (!eth_fec)
+               eth_fec = ETHTOOL_FEC_OFF;
+
+       return eth_fec;
+}
+
+/* Translate ethtool FEC value into Common Code value. */
+static inline unsigned int eth_to_cc_fec(unsigned int eth_fec)
+{
+       unsigned int cc_fec = 0;
+
+       if (eth_fec & ETHTOOL_FEC_OFF)
+               return cc_fec;
+
+       if (eth_fec & ETHTOOL_FEC_AUTO)
+               cc_fec |= FEC_AUTO;
+       if (eth_fec & ETHTOOL_FEC_RS)
+               cc_fec |= FEC_RS;
+       if (eth_fec & ETHTOOL_FEC_BASER)
+               cc_fec |= FEC_BASER_RS;
+
+       return cc_fec;
+}
+
+static int get_fecparam(struct net_device *dev, struct ethtool_fecparam *fec)
+{
+       const struct port_info *pi = netdev_priv(dev);
+       const struct link_config *lc = &pi->link_cfg;
+
+       /* Translate the Firmware FEC Support into the ethtool value.  We
+        * always support IEEE 802.3 "automatic" selection of Link FEC type if
+        * any FEC is supported.
+        */
+       fec->fec = fwcap_to_eth_fec(lc->supported);
+       if (fec->fec != ETHTOOL_FEC_OFF)
+               fec->fec |= ETHTOOL_FEC_AUTO;
+
+       /* Translate the current internal FEC parameters into the
+        * ethtool values.
+        */
+       fec->active_fec = cc_to_eth_fec(lc->fec);
+
+       return 0;
+}
+
+static int set_fecparam(struct net_device *dev, struct ethtool_fecparam *fec)
+{
+       struct port_info *pi = netdev_priv(dev);
+       struct link_config *lc = &pi->link_cfg;
+       struct link_config old_lc;
+       int ret;
+
+       /* Save old Link Configuration in case the L1 Configure below
+        * fails.
+        */
+       old_lc = *lc;
+
+       /* Try to perform the L1 Configure and return the result of that
+        * effort.  If it fails, revert the attempted change.
+        */
+       lc->requested_fec = eth_to_cc_fec(fec->fec);
+       ret = t4_link_l1cfg(pi->adapter, pi->adapter->mbox,
+                           pi->tx_chan, lc);
+       if (ret)
+               *lc = old_lc;
+       return ret;
+}
+
 static void get_pauseparam(struct net_device *dev,
                           struct ethtool_pauseparam *epause)
 {
@@ -1255,6 +1353,8 @@ static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
 static const struct ethtool_ops cxgb_ethtool_ops = {
        .get_link_ksettings = get_link_ksettings,
        .set_link_ksettings = set_link_ksettings,
+       .get_fecparam      = get_fecparam,
+       .set_fecparam      = set_fecparam,
        .get_drvinfo       = get_drvinfo,
        .get_msglevel      = get_msglevel,
        .set_msglevel      = set_msglevel,
index e403fa1..fdf220a 100644 (file)
@@ -3610,11 +3610,8 @@ static int adap_init0(struct adapter *adap)
         * later reporting and B. to warn if the currently loaded firmware
         * is excessively mismatched relative to the driver.)
         */
-       t4_get_fw_version(adap, &adap->params.fw_vers);
-       t4_get_bs_version(adap, &adap->params.bs_vers);
-       t4_get_tp_version(adap, &adap->params.tp_vers);
-       t4_get_exprom_version(adap, &adap->params.er_vers);
 
+       t4_get_version_info(adap);
        ret = t4_check_fw_version(adap);
        /* If firmware is too old (not supported by driver) force an update. */
        if (ret)
@@ -4560,56 +4557,8 @@ static void cxgb4_check_pcie_caps(struct adapter *adap)
 /* Dump basic information about the adapter */
 static void print_adapter_info(struct adapter *adapter)
 {
-       /* Device information */
-       dev_info(adapter->pdev_dev, "Chelsio %s rev %d\n",
-                adapter->params.vpd.id,
-                CHELSIO_CHIP_RELEASE(adapter->params.chip));
-       dev_info(adapter->pdev_dev, "S/N: %s, P/N: %s\n",
-                adapter->params.vpd.sn, adapter->params.vpd.pn);
-
-       /* Firmware Version */
-       if (!adapter->params.fw_vers)
-               dev_warn(adapter->pdev_dev, "No firmware loaded\n");
-       else
-               dev_info(adapter->pdev_dev, "Firmware version: %u.%u.%u.%u\n",
-                        FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers),
-                        FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers),
-                        FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers),
-                        FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers));
-
-       /* Bootstrap Firmware Version. (Some adapters don't have Bootstrap
-        * Firmware, so dev_info() is more appropriate here.)
-        */
-       if (!adapter->params.bs_vers)
-               dev_info(adapter->pdev_dev, "No bootstrap loaded\n");
-       else
-               dev_info(adapter->pdev_dev, "Bootstrap version: %u.%u.%u.%u\n",
-                        FW_HDR_FW_VER_MAJOR_G(adapter->params.bs_vers),
-                        FW_HDR_FW_VER_MINOR_G(adapter->params.bs_vers),
-                        FW_HDR_FW_VER_MICRO_G(adapter->params.bs_vers),
-                        FW_HDR_FW_VER_BUILD_G(adapter->params.bs_vers));
-
-       /* TP Microcode Version */
-       if (!adapter->params.tp_vers)
-               dev_warn(adapter->pdev_dev, "No TP Microcode loaded\n");
-       else
-               dev_info(adapter->pdev_dev,
-                        "TP Microcode version: %u.%u.%u.%u\n",
-                        FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers),
-                        FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers),
-                        FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers),
-                        FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers));
-
-       /* Expansion ROM version */
-       if (!adapter->params.er_vers)
-               dev_info(adapter->pdev_dev, "No Expansion ROM loaded\n");
-       else
-               dev_info(adapter->pdev_dev,
-                        "Expansion ROM version: %u.%u.%u.%u\n",
-                        FW_HDR_FW_VER_MAJOR_G(adapter->params.er_vers),
-                        FW_HDR_FW_VER_MINOR_G(adapter->params.er_vers),
-                        FW_HDR_FW_VER_MICRO_G(adapter->params.er_vers),
-                        FW_HDR_FW_VER_BUILD_G(adapter->params.er_vers));
+       /* Hardware/Firmware/etc. Version/Revision IDs */
+       t4_dump_version_info(adapter);
 
        /* Software/Hardware configuration */
        dev_info(adapter->pdev_dev, "Configuration: %sNIC %s, %s capable\n",
index 50517cf..9f9d6ca 100644 (file)
@@ -441,7 +441,8 @@ void cxgb4_ptp_init(struct adapter *adapter)
 
        adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info,
                                                &adapter->pdev->dev);
-       if (!adapter->ptp_clock) {
+       if (IS_ERR_OR_NULL(adapter->ptp_clock)) {
+               adapter->ptp_clock = NULL;
                dev_err(adapter->pdev_dev,
                        "PTP %s Clock registration has failed\n", __func__);
                return;
index 570c095..24087c8 100644 (file)
@@ -3077,6 +3077,179 @@ int t4_get_exprom_version(struct adapter *adap, u32 *vers)
 }
 
 /**
+ *      t4_get_vpd_version - return the VPD version
+ *      @adapter: the adapter
+ *      @vers: where to place the version
+ *
+ *      Reads the VPD via the Firmware interface (thus this can only be called
+ *      once we're ready to issue Firmware commands).  The format of the
+ *      VPD version is adapter specific.  Returns 0 on success, an error on
+ *      failure.
+ *
+ *      Note that early versions of the Firmware didn't include the ability
+ *      to retrieve the VPD version, so we zero-out the return-value parameter
+ *      in that case to avoid leaving it with garbage in it.
+ *
+ *      Also note that the Firmware will return its cached copy of the VPD
+ *      Revision ID, not the actual Revision ID as written in the Serial
+ *      EEPROM.  This is only an issue if a new VPD has been written and the
+ *      Firmware/Chip haven't yet gone through a RESET sequence.  So it's best
+ *      to defer calling this routine till after a FW_RESET_CMD has been issued
+ *      if the Host Driver will be performing a full adapter initialization.
+ */
+int t4_get_vpd_version(struct adapter *adapter, u32 *vers)
+{
+       u32 vpdrev_param;
+       int ret;
+
+       vpdrev_param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+                       FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_VPDREV));
+       ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0,
+                             1, &vpdrev_param, vers);
+       if (ret)
+               *vers = 0;
+       return ret;
+}
+
+/**
+ *      t4_get_scfg_version - return the Serial Configuration version
+ *      @adapter: the adapter
+ *      @vers: where to place the version
+ *
+ *      Reads the Serial Configuration Version via the Firmware interface
+ *      (thus this can only be called once we're ready to issue Firmware
+ *      commands).  The format of the Serial Configuration version is
+ *      adapter specific.  Returns 0 on success, an error on failure.
+ *
+ *      Note that early versions of the Firmware didn't include the ability
+ *      to retrieve the Serial Configuration version, so we zero-out the
+ *      return-value parameter in that case to avoid leaving it with
+ *      garbage in it.
+ *
+ *      Also note that the Firmware will return its cached copy of the Serial
+ *      Initialization Revision ID, not the actual Revision ID as written in
+ *      the Serial EEPROM.  This is only an issue if a new VPD has been written
+ *      and the Firmware/Chip haven't yet gone through a RESET sequence.  So
+ *      it's best to defer calling this routine till after a FW_RESET_CMD has
+ *      been issued if the Host Driver will be performing a full adapter
+ *      initialization.
+ */
+int t4_get_scfg_version(struct adapter *adapter, u32 *vers)
+{
+       u32 scfgrev_param;
+       int ret;
+
+       scfgrev_param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+                        FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_SCFGREV));
+       ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0,
+                             1, &scfgrev_param, vers);
+       if (ret)
+               *vers = 0;
+       return ret;
+}
+
+/**
+ *      t4_get_version_info - extract various chip/firmware version information
+ *      @adapter: the adapter
+ *
+ *      Reads various chip/firmware version numbers and stores them into the
+ *      adapter Adapter Parameters structure.  If any of the efforts fails
+ *      the first failure will be returned, but all of the version numbers
+ *      will be read.
+ */
+int t4_get_version_info(struct adapter *adapter)
+{
+       int ret = 0;
+
+       #define FIRST_RET(__getvinfo) \
+       do { \
+               int __ret = __getvinfo; \
+               if (__ret && !ret) \
+                       ret = __ret; \
+       } while (0)
+
+       FIRST_RET(t4_get_fw_version(adapter, &adapter->params.fw_vers));
+       FIRST_RET(t4_get_bs_version(adapter, &adapter->params.bs_vers));
+       FIRST_RET(t4_get_tp_version(adapter, &adapter->params.tp_vers));
+       FIRST_RET(t4_get_exprom_version(adapter, &adapter->params.er_vers));
+       FIRST_RET(t4_get_scfg_version(adapter, &adapter->params.scfg_vers));
+       FIRST_RET(t4_get_vpd_version(adapter, &adapter->params.vpd_vers));
+
+       #undef FIRST_RET
+       return ret;
+}
+
+/**
+ *      t4_dump_version_info - dump all of the adapter configuration IDs
+ *      @adapter: the adapter
+ *
+ *      Dumps all of the various bits of adapter configuration version/revision
+ *      IDs information.  This is typically called at some point after
+ *      t4_get_version_info() has been called.
+ */
+void t4_dump_version_info(struct adapter *adapter)
+{
+       /* Device information */
+       dev_info(adapter->pdev_dev, "Chelsio %s rev %d\n",
+                adapter->params.vpd.id,
+                CHELSIO_CHIP_RELEASE(adapter->params.chip));
+       dev_info(adapter->pdev_dev, "S/N: %s, P/N: %s\n",
+                adapter->params.vpd.sn, adapter->params.vpd.pn);
+
+       /* Firmware Version */
+       if (!adapter->params.fw_vers)
+               dev_warn(adapter->pdev_dev, "No firmware loaded\n");
+       else
+               dev_info(adapter->pdev_dev, "Firmware version: %u.%u.%u.%u\n",
+                        FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers),
+                        FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers),
+                        FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers),
+                        FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers));
+
+       /* Bootstrap Firmware Version. (Some adapters don't have Bootstrap
+        * Firmware, so dev_info() is more appropriate here.)
+        */
+       if (!adapter->params.bs_vers)
+               dev_info(adapter->pdev_dev, "No bootstrap loaded\n");
+       else
+               dev_info(adapter->pdev_dev, "Bootstrap version: %u.%u.%u.%u\n",
+                        FW_HDR_FW_VER_MAJOR_G(adapter->params.bs_vers),
+                        FW_HDR_FW_VER_MINOR_G(adapter->params.bs_vers),
+                        FW_HDR_FW_VER_MICRO_G(adapter->params.bs_vers),
+                        FW_HDR_FW_VER_BUILD_G(adapter->params.bs_vers));
+
+       /* TP Microcode Version */
+       if (!adapter->params.tp_vers)
+               dev_warn(adapter->pdev_dev, "No TP Microcode loaded\n");
+       else
+               dev_info(adapter->pdev_dev,
+                        "TP Microcode version: %u.%u.%u.%u\n",
+                        FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers),
+                        FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers),
+                        FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers),
+                        FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers));
+
+       /* Expansion ROM version */
+       if (!adapter->params.er_vers)
+               dev_info(adapter->pdev_dev, "No Expansion ROM loaded\n");
+       else
+               dev_info(adapter->pdev_dev,
+                        "Expansion ROM version: %u.%u.%u.%u\n",
+                        FW_HDR_FW_VER_MAJOR_G(adapter->params.er_vers),
+                        FW_HDR_FW_VER_MINOR_G(adapter->params.er_vers),
+                        FW_HDR_FW_VER_MICRO_G(adapter->params.er_vers),
+                        FW_HDR_FW_VER_BUILD_G(adapter->params.er_vers));
+
+       /* Serial Configuration version */
+       dev_info(adapter->pdev_dev, "Serial Configuration version: %#x\n",
+                adapter->params.scfg_vers);
+
+       /* VPD Version */
+       dev_info(adapter->pdev_dev, "VPD version: %#x\n",
+                adapter->params.vpd_vers);
+}
+
+/**
  *     t4_check_fw_version - check if the FW is supported with this driver
  *     @adap: the adapter
  *
@@ -3667,11 +3840,64 @@ void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf)
                     FW_PORT_CAP_SPEED_40G | FW_PORT_CAP_SPEED_100G | \
                     FW_PORT_CAP_ANEG)
 
+/* Translate Firmware Port Capabilities Pause specification to Common Code */
+static inline unsigned int fwcap_to_cc_pause(unsigned int fw_pause)
+{
+       unsigned int cc_pause = 0;
+
+       if (fw_pause & FW_PORT_CAP_FC_RX)
+               cc_pause |= PAUSE_RX;
+       if (fw_pause & FW_PORT_CAP_FC_TX)
+               cc_pause |= PAUSE_TX;
+
+       return cc_pause;
+}
+
+/* Translate Common Code Pause specification into Firmware Port Capabilities */
+static inline unsigned int cc_to_fwcap_pause(unsigned int cc_pause)
+{
+       unsigned int fw_pause = 0;
+
+       if (cc_pause & PAUSE_RX)
+               fw_pause |= FW_PORT_CAP_FC_RX;
+       if (cc_pause & PAUSE_TX)
+               fw_pause |= FW_PORT_CAP_FC_TX;
+
+       return fw_pause;
+}
+
+/* Translate Firmware Forward Error Correction specification to Common Code */
+static inline unsigned int fwcap_to_cc_fec(unsigned int fw_fec)
+{
+       unsigned int cc_fec = 0;
+
+       if (fw_fec & FW_PORT_CAP_FEC_RS)
+               cc_fec |= FEC_RS;
+       if (fw_fec & FW_PORT_CAP_FEC_BASER_RS)
+               cc_fec |= FEC_BASER_RS;
+
+       return cc_fec;
+}
+
+/* Translate Common Code Forward Error Correction specification to Firmware */
+static inline unsigned int cc_to_fwcap_fec(unsigned int cc_fec)
+{
+       unsigned int fw_fec = 0;
+
+       if (cc_fec & FEC_RS)
+               fw_fec |= FW_PORT_CAP_FEC_RS;
+       if (cc_fec & FEC_BASER_RS)
+               fw_fec |= FW_PORT_CAP_FEC_BASER_RS;
+
+       return fw_fec;
+}
+
 /**
  *     t4_link_l1cfg - apply link configuration to MAC/PHY
- *     @phy: the PHY to setup
- *     @mac: the MAC to setup
- *     @lc: the requested link configuration
+ *     @adapter: the adapter
+ *     @mbox: the Firmware Mailbox to use
+ *     @port: the Port ID
+ *     @lc: the Port's Link Configuration
  *
  *     Set up a port's MAC and PHY according to a desired link configuration.
  *     - If the PHY can auto-negotiate first decide what to advertise, then
@@ -3684,22 +3910,46 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
                  struct link_config *lc)
 {
        struct fw_port_cmd c;
-       unsigned int mdi = FW_PORT_CAP_MDI_V(FW_PORT_CAP_MDI_AUTO);
-       unsigned int fc = 0, fec = 0, fw_fec = 0;
+       unsigned int fw_mdi = FW_PORT_CAP_MDI_V(FW_PORT_CAP_MDI_AUTO);
+       unsigned int fw_fc, cc_fec, fw_fec;
+       unsigned int rcap;
 
        lc->link_ok = 0;
-       if (lc->requested_fc & PAUSE_RX)
-               fc |= FW_PORT_CAP_FC_RX;
-       if (lc->requested_fc & PAUSE_TX)
-               fc |= FW_PORT_CAP_FC_TX;
 
-       fec = lc->requested_fec & FEC_AUTO ? lc->auto_fec : lc->requested_fec;
+       /* Convert driver coding of Pause Frame Flow Control settings into the
+        * Firmware's API.
+        */
+       fw_fc = cc_to_fwcap_pause(lc->requested_fc);
+
+       /* Convert Common Code Forward Error Control settings into the
+        * Firmware's API.  If the current Requested FEC has "Automatic"
+        * (IEEE 802.3) specified, then we use whatever the Firmware
+        * sent us as part of it's IEEE 802.3-based interpratation of
+        * the Transceiver Module EPROM FEC parameters.  Otherwise we
+        * use whatever is in the current Requested FEC settings.
+        */
+       if (lc->requested_fec & FEC_AUTO)
+               cc_fec = lc->auto_fec;
+       else
+               cc_fec = lc->requested_fec;
+       fw_fec = cc_to_fwcap_fec(cc_fec);
 
-       if (fec & FEC_RS)
-               fw_fec |= FW_PORT_CAP_FEC_RS;
-       if (fec & FEC_BASER_RS)
-               fw_fec |= FW_PORT_CAP_FEC_BASER_RS;
+       /* Figure out what our Requested Port Capabilities are going to be.
+        */
+       if (!(lc->supported & FW_PORT_CAP_ANEG)) {
+               rcap = (lc->supported & ADVERT_MASK) | fw_fc | fw_fec;
+               lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+               lc->fec = cc_fec;
+       } else if (lc->autoneg == AUTONEG_DISABLE) {
+               rcap = lc->requested_speed | fw_fc | fw_fec | fw_mdi;
+               lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+               lc->fec = cc_fec;
+       } else {
+               rcap = lc->advertising | fw_fc | fw_fec | fw_mdi;
+       }
 
+       /* And send that on to the Firmware ...
+        */
        memset(&c, 0, sizeof(c));
        c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
                                     FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
@@ -3707,19 +3957,7 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
        c.action_to_len16 =
                cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) |
                            FW_LEN16(c));
-
-       if (!(lc->supported & FW_PORT_CAP_ANEG)) {
-               c.u.l1cfg.rcap = cpu_to_be32((lc->supported & ADVERT_MASK) |
-                                            fc | fw_fec);
-               lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
-       } else if (lc->autoneg == AUTONEG_DISABLE) {
-               c.u.l1cfg.rcap = cpu_to_be32(lc->requested_speed | fc |
-                                            fw_fec | mdi);
-               lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
-       } else
-               c.u.l1cfg.rcap = cpu_to_be32(lc->advertising | fc |
-                                            fw_fec | mdi);
-
+       c.u.l1cfg.rcap = cpu_to_be32(rcap);
        return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
 }
 
@@ -7457,19 +7695,28 @@ static const char *t4_link_down_rc_str(unsigned char link_down_rc)
 void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
 {
        const struct fw_port_cmd *p = (const void *)rpl;
+       unsigned int acaps = be16_to_cpu(p->u.info.acap);
        struct adapter *adap = pi->adapter;
 
        /* link/module state change message */
-       int speed = 0, fc = 0;
+       int speed = 0, fc, fec;
        struct link_config *lc;
        u32 stat = be32_to_cpu(p->u.info.lstatus_to_modtype);
        int link_ok = (stat & FW_PORT_CMD_LSTATUS_F) != 0;
        u32 mod = FW_PORT_CMD_MODTYPE_G(stat);
 
+       /* Unfortunately the format of the Link Status returned by the
+        * Firmware isn't the same as the Firmware Port Capabilities bitfield
+        * used everywhere else ...
+        */
+       fc = 0;
        if (stat & FW_PORT_CMD_RXPAUSE_F)
                fc |= PAUSE_RX;
        if (stat & FW_PORT_CMD_TXPAUSE_F)
                fc |= PAUSE_TX;
+
+       fec = fwcap_to_cc_fec(acaps);
+
        if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
                speed = 100;
        else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
@@ -7486,11 +7733,20 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
        lc = &pi->link_cfg;
 
        if (mod != pi->mod_type) {
+               /* When a new Transceiver Module is inserted, the Firmware
+                * will examine any Forward Error Correction parameters
+                * present in the Transceiver Module i2c EPROM and determine
+                * the supported and recommended FEC settings from those
+                * based on IEEE 802.3 standards.  We always record the
+                * IEEE 802.3 recommended "automatic" settings.
+                */
+               lc->auto_fec = fec;
+
                pi->mod_type = mod;
                t4_os_portmod_changed(adap, pi->port_id);
        }
        if (link_ok != lc->link_ok || speed != lc->speed ||
-           fc != lc->fc) {     /* something changed */
+           fc != lc->fc || fec != lc->fec) {   /* something changed */
                if (!link_ok && lc->link_ok) {
                        unsigned char rc = FW_PORT_CMD_LINKDNRC_G(stat);
 
@@ -7502,6 +7758,8 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
                lc->link_ok = link_ok;
                lc->speed = speed;
                lc->fc = fc;
+               lc->fec = fec;
+
                lc->supported = be16_to_cpu(p->u.info.pcap);
                lc->lp_advertising = be16_to_cpu(p->u.info.lpacap);
 
@@ -7591,7 +7849,8 @@ static void get_pci_mode(struct adapter *adapter, struct pci_params *p)
 /**
  *     init_link_config - initialize a link's SW state
  *     @lc: structure holding the link state
- *     @caps: link capabilities
+ *     @pcaps: link Port Capabilities
+ *     @acaps: link current Advertised Port Capabilities
  *
  *     Initializes the SW state maintained for each link, including the link's
  *     capabilities and default speed/flow-control/autonegotiation settings.
@@ -7604,15 +7863,11 @@ static void init_link_config(struct link_config *lc, unsigned int pcaps,
        lc->requested_speed = 0;
        lc->speed = 0;
        lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
-       lc->auto_fec = 0;
 
        /* For Forward Error Control, we default to whatever the Firmware
         * tells us the Link is currently advertising.
         */
-       if (acaps & FW_PORT_CAP_FEC_RS)
-               lc->auto_fec |= FEC_RS;
-       if (acaps & FW_PORT_CAP_FEC_BASER_RS)
-               lc->auto_fec |= FEC_BASER_RS;
+       lc->auto_fec = fwcap_to_cc_fec(acaps);
        lc->requested_fec = FEC_AUTO;
        lc->fec = lc->auto_fec;
 
index 99987d8..aa28299 100644 (file)
@@ -174,6 +174,8 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN
        CH_PCI_ID_TABLE_FENTRY(0x50a0), /* Custom T540-CR */
        CH_PCI_ID_TABLE_FENTRY(0x50a1), /* Custom T540-CR */
        CH_PCI_ID_TABLE_FENTRY(0x50a2), /* Custom T540-KR4 */
+       CH_PCI_ID_TABLE_FENTRY(0x50a3), /* Custom T580-KR4 */
+       CH_PCI_ID_TABLE_FENTRY(0x50a4), /* Custom 2x T540-CR */
 
        /* T6 adapters:
         */
index 0ebed64..ad825fb 100644 (file)
@@ -1124,6 +1124,8 @@ enum fw_params_param_dev {
        FW_PARAMS_PARAM_DEV_MAXIRD_ADAPTER = 0x14, /* max supported adap IRD */
        FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17,
        FW_PARAMS_PARAM_DEV_FWCACHE = 0x18,
+       FW_PARAMS_PARAM_DEV_SCFGREV = 0x1A,
+       FW_PARAMS_PARAM_DEV_VPDREV = 0x1B,
        FW_PARAMS_PARAM_DEV_RI_FR_NSMR_TPTE_WR  = 0x1C,
        FW_PARAMS_PARAM_DEV_MPSBGMAP    = 0x1E,
 };
index 2b62841..05989aa 100644 (file)
@@ -139,10 +139,7 @@ int be_roce_register_driver(struct ocrdma_driver *drv)
        }
        ocrdma_drv = drv;
        list_for_each_entry(dev, &be_adapter_list, entry) {
-               struct net_device *netdev;
-
                _be_roce_dev_add(dev);
-               netdev = dev->netdev;
        }
        mutex_unlock(&be_adapter_list_lock);
        return 0;
index 95bf5e8..34dae51 100644 (file)
@@ -125,7 +125,7 @@ static int ftgmac100_reset_mac(struct ftgmac100 *priv, u32 maccr)
        iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
        iowrite32(maccr | FTGMAC100_MACCR_SW_RST,
                  priv->base + FTGMAC100_OFFSET_MACCR);
-       for (i = 0; i < 50; i++) {
+       for (i = 0; i < 200; i++) {
                unsigned int maccr;
 
                maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
@@ -392,7 +392,7 @@ static int ftgmac100_alloc_rx_buf(struct ftgmac100 *priv, unsigned int entry,
        struct net_device *netdev = priv->netdev;
        struct sk_buff *skb;
        dma_addr_t map;
-       int err;
+       int err = 0;
 
        skb = netdev_alloc_skb_ip_align(netdev, RX_BUF_SIZE);
        if (unlikely(!skb)) {
@@ -428,7 +428,7 @@ static int ftgmac100_alloc_rx_buf(struct ftgmac100 *priv, unsigned int entry,
        else
                rxdes->rxdes0 = 0;
 
-       return 0;
+       return err;
 }
 
 static unsigned int ftgmac100_next_rx_pointer(struct ftgmac100 *priv,
@@ -1682,6 +1682,7 @@ static int ftgmac100_setup_mdio(struct net_device *netdev)
        priv->mii_bus->name = "ftgmac100_mdio";
        snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%d",
                 pdev->name, pdev->id);
+       priv->mii_bus->parent = priv->dev;
        priv->mii_bus->priv = priv->netdev;
        priv->mii_bus->read = ftgmac100_mdiobus_read;
        priv->mii_bus->write = ftgmac100_mdiobus_write;
index 757b873..550ea1e 100644 (file)
@@ -398,8 +398,8 @@ static struct mac_device *dpaa_mac_dev_get(struct platform_device *pdev)
 
        of_dev = of_find_device_by_node(mac_node);
        if (!of_dev) {
-               dev_err(dpaa_dev, "of_find_device_by_node(%s) failed\n",
-                       mac_node->full_name);
+               dev_err(dpaa_dev, "of_find_device_by_node(%pOF) failed\n",
+                       mac_node);
                of_node_put(mac_node);
                return ERR_PTR(-EINVAL);
        }
index a6e323f..df09b25 100644 (file)
@@ -173,10 +173,12 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 #endif /* CONFIG_M5272 */
 
 /* The FEC stores dest/src/type/vlan, data, and checksum for receive packets.
+ *
+ * 2048 byte skbufs are allocated. However, alignment requirements
+ * varies between FEC variants. Worst case is 64, so round down by 64.
  */
-#define PKT_MAXBUF_SIZE                1522
+#define PKT_MAXBUF_SIZE                (round_down(2048 - 64, 64))
 #define PKT_MINBUF_SIZE                64
-#define PKT_MAXBLR_SIZE                1536
 
 /* FEC receive acceleration */
 #define FEC_RACC_IPDIS         (1 << 1)
@@ -851,7 +853,7 @@ static void fec_enet_enable_ring(struct net_device *ndev)
        for (i = 0; i < fep->num_rx_queues; i++) {
                rxq = fep->rx_queue[i];
                writel(rxq->bd.dma, fep->hwp + FEC_R_DES_START(i));
-               writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE(i));
+               writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_R_BUFF_SIZE(i));
 
                /* enable DMA1/2 */
                if (i)
@@ -1904,8 +1906,10 @@ static int fec_enet_mii_probe(struct net_device *ndev)
                phy_dev = of_phy_connect(ndev, fep->phy_node,
                                         &fec_enet_adjust_link, 0,
                                         fep->phy_interface);
-               if (!phy_dev)
+               if (!phy_dev) {
+                       netdev_err(ndev, "Unable to connect to phy\n");
                        return -ENODEV;
+               }
        } else {
                /* check for attached phy */
                for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) {
index aa8cf5d..6d7269d 100644 (file)
@@ -960,8 +960,8 @@ static int mpc52xx_fec_probe(struct platform_device *op)
 
        /* We're done ! */
        platform_set_drvdata(op, ndev);
-       netdev_info(ndev, "%s MAC %pM\n",
-                   op->dev.of_node->full_name, ndev->dev_addr);
+       netdev_info(ndev, "%pOF MAC %pM\n",
+                   op->dev.of_node, ndev->dev_addr);
 
        return 0;
 
index 4aefe24..e714b8f 100644 (file)
@@ -1925,8 +1925,8 @@ static int fman_reset(struct fman *fman)
 
                guts_regs = of_iomap(guts_node, 0);
                if (!guts_regs) {
-                       dev_err(fman->dev, "%s: Couldn't map %s regs\n",
-                               __func__, guts_node->full_name);
+                       dev_err(fman->dev, "%s: Couldn't map %pOF regs\n",
+                               __func__, guts_node);
                        goto guts_regs;
                }
 #define FMAN1_ALL_MACS_MASK    0xFCC00000
@@ -2780,8 +2780,8 @@ static struct fman *read_dts_node(struct platform_device *of_dev)
 
        err = of_property_read_u32(fm_node, "cell-index", &val);
        if (err) {
-               dev_err(&of_dev->dev, "%s: failed to read cell-index for %s\n",
-                       __func__, fm_node->full_name);
+               dev_err(&of_dev->dev, "%s: failed to read cell-index for %pOF\n",
+                       __func__, fm_node);
                goto fman_node_put;
        }
        fman->dts_params.id = (u8)val;
@@ -2834,8 +2834,8 @@ static struct fman *read_dts_node(struct platform_device *of_dev)
        err = of_property_read_u32_array(fm_node, "fsl,qman-channel-range",
                                         &range[0], 2);
        if (err) {
-               dev_err(&of_dev->dev, "%s: failed to read fsl,qman-channel-range for %s\n",
-                       __func__, fm_node->full_name);
+               dev_err(&of_dev->dev, "%s: failed to read fsl,qman-channel-range for %pOF\n",
+                       __func__, fm_node);
                goto fman_node_put;
        }
        fman->dts_params.qman_channel_base = range[0];
index 57bf44f..49bfa11 100644 (file)
@@ -1720,8 +1720,8 @@ static int fman_port_probe(struct platform_device *of_dev)
 
        err = of_property_read_u32(port_node, "cell-index", &val);
        if (err) {
-               dev_err(port->dev, "%s: reading cell-index for %s failed\n",
-                       __func__, port_node->full_name);
+               dev_err(port->dev, "%s: reading cell-index for %pOF failed\n",
+                       __func__, port_node);
                err = -EINVAL;
                goto return_err;
        }
index 6e67d22..14cd2c8 100644 (file)
@@ -698,8 +698,8 @@ static int mac_probe(struct platform_device *_of_dev)
                priv->internal_phy_node = of_parse_phandle(mac_node,
                                                          "pcsphy-handle", 0);
        } else {
-               dev_err(dev, "MAC node (%s) contains unsupported MAC\n",
-                       mac_node->full_name);
+               dev_err(dev, "MAC node (%pOF) contains unsupported MAC\n",
+                       mac_node);
                err = -EINVAL;
                goto _return;
        }
@@ -712,16 +712,15 @@ static int mac_probe(struct platform_device *_of_dev)
        /* Get the FM node */
        dev_node = of_get_parent(mac_node);
        if (!dev_node) {
-               dev_err(dev, "of_get_parent(%s) failed\n",
-                       mac_node->full_name);
+               dev_err(dev, "of_get_parent(%pOF) failed\n",
+                       mac_node);
                err = -EINVAL;
                goto _return_dev_set_drvdata;
        }
 
        of_dev = of_find_device_by_node(dev_node);
        if (!of_dev) {
-               dev_err(dev, "of_find_device_by_node(%s) failed\n",
-                       dev_node->full_name);
+               dev_err(dev, "of_find_device_by_node(%pOF) failed\n", dev_node);
                err = -EINVAL;
                goto _return_of_node_put;
        }
@@ -729,8 +728,7 @@ static int mac_probe(struct platform_device *_of_dev)
        /* Get the FMan cell-index */
        err = of_property_read_u32(dev_node, "cell-index", &val);
        if (err) {
-               dev_err(dev, "failed to read cell-index for %s\n",
-                       dev_node->full_name);
+               dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);
                err = -EINVAL;
                goto _return_of_node_put;
        }
@@ -739,7 +737,7 @@ static int mac_probe(struct platform_device *_of_dev)
 
        priv->fman = fman_bind(&of_dev->dev);
        if (!priv->fman) {
-               dev_err(dev, "fman_bind(%s) failed\n", dev_node->full_name);
+               dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
                err = -ENODEV;
                goto _return_of_node_put;
        }
@@ -749,8 +747,8 @@ static int mac_probe(struct platform_device *_of_dev)
        /* Get the address of the memory mapped registers */
        err = of_address_to_resource(mac_node, 0, &res);
        if (err < 0) {
-               dev_err(dev, "of_address_to_resource(%s) = %d\n",
-                       mac_node->full_name, err);
+               dev_err(dev, "of_address_to_resource(%pOF) = %d\n",
+                       mac_node, err);
                goto _return_dev_set_drvdata;
        }
 
@@ -784,8 +782,7 @@ static int mac_probe(struct platform_device *_of_dev)
        /* Get the cell-index */
        err = of_property_read_u32(mac_node, "cell-index", &val);
        if (err) {
-               dev_err(dev, "failed to read cell-index for %s\n",
-                       mac_node->full_name);
+               dev_err(dev, "failed to read cell-index for %pOF\n", mac_node);
                err = -EINVAL;
                goto _return_dev_set_drvdata;
        }
@@ -794,8 +791,7 @@ static int mac_probe(struct platform_device *_of_dev)
        /* Get the MAC address */
        mac_addr = of_get_mac_address(mac_node);
        if (!mac_addr) {
-               dev_err(dev, "of_get_mac_address(%s) failed\n",
-                       mac_node->full_name);
+               dev_err(dev, "of_get_mac_address(%pOF) failed\n", mac_node);
                err = -EINVAL;
                goto _return_dev_set_drvdata;
        }
@@ -804,15 +800,15 @@ static int mac_probe(struct platform_device *_of_dev)
        /* Get the port handles */
        nph = of_count_phandle_with_args(mac_node, "fsl,fman-ports", NULL);
        if (unlikely(nph < 0)) {
-               dev_err(dev, "of_count_phandle_with_args(%s, fsl,fman-ports) failed\n",
-                       mac_node->full_name);
+               dev_err(dev, "of_count_phandle_with_args(%pOF, fsl,fman-ports) failed\n",
+                       mac_node);
                err = nph;
                goto _return_dev_set_drvdata;
        }
 
        if (nph != ARRAY_SIZE(mac_dev->port)) {
-               dev_err(dev, "Not supported number of fman-ports handles of mac node %s from device tree\n",
-                       mac_node->full_name);
+               dev_err(dev, "Not supported number of fman-ports handles of mac node %pOF from device tree\n",
+                       mac_node);
                err = -EINVAL;
                goto _return_dev_set_drvdata;
        }
@@ -821,24 +817,24 @@ static int mac_probe(struct platform_device *_of_dev)
                /* Find the port node */
                dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
                if (!dev_node) {
-                       dev_err(dev, "of_parse_phandle(%s, fsl,fman-ports) failed\n",
-                               mac_node->full_name);
+                       dev_err(dev, "of_parse_phandle(%pOF, fsl,fman-ports) failed\n",
+                               mac_node);
                        err = -EINVAL;
                        goto _return_of_node_put;
                }
 
                of_dev = of_find_device_by_node(dev_node);
                if (!of_dev) {
-                       dev_err(dev, "of_find_device_by_node(%s) failed\n",
-                               dev_node->full_name);
+                       dev_err(dev, "of_find_device_by_node(%pOF) failed\n",
+                               dev_node);
                        err = -EINVAL;
                        goto _return_of_node_put;
                }
 
                mac_dev->port[i] = fman_port_bind(&of_dev->dev);
                if (!mac_dev->port[i]) {
-                       dev_err(dev, "dev_get_drvdata(%s) failed\n",
-                               dev_node->full_name);
+                       dev_err(dev, "dev_get_drvdata(%pOF) failed\n",
+                               dev_node);
                        err = -EINVAL;
                        goto _return_of_node_put;
                }
@@ -849,8 +845,8 @@ static int mac_probe(struct platform_device *_of_dev)
        phy_if = of_get_phy_mode(mac_node);
        if (phy_if < 0) {
                dev_warn(dev,
-                        "of_get_phy_mode() for %s failed. Defaulting to SGMII\n",
-                        mac_node->full_name);
+                        "of_get_phy_mode() for %pOF failed. Defaulting to SGMII\n",
+                        mac_node);
                phy_if = PHY_INTERFACE_MODE_SGMII;
        }
        priv->phy_if = phy_if;
index a10de1e..80ad16a 100644 (file)
@@ -267,8 +267,8 @@ static void ucc_configure(phys_addr_t start, phys_addr_t end)
 
                ret = of_address_to_resource(np, 0, &res);
                if (ret < 0) {
-                       pr_debug("fsl-pq-mdio: no address range in node %s\n",
-                                np->full_name);
+                       pr_debug("fsl-pq-mdio: no address range in node %pOF\n",
+                                np);
                        continue;
                }
 
@@ -280,8 +280,8 @@ static void ucc_configure(phys_addr_t start, phys_addr_t end)
                if (!iprop) {
                        iprop = of_get_property(np, "device-id", NULL);
                        if (!iprop) {
-                               pr_debug("fsl-pq-mdio: no UCC ID in node %s\n",
-                                        np->full_name);
+                               pr_debug("fsl-pq-mdio: no UCC ID in node %pOF\n",
+                                        np);
                                continue;
                        }
                }
@@ -293,8 +293,8 @@ static void ucc_configure(phys_addr_t start, phys_addr_t end)
                 * numbered from 1, not 0.
                 */
                if (ucc_set_qe_mux_mii_mng(id - 1) < 0) {
-                       pr_debug("fsl-pq-mdio: invalid UCC ID in node %s\n",
-                                np->full_name);
+                       pr_debug("fsl-pq-mdio: invalid UCC ID in node %pOF\n",
+                                np);
                        continue;
                }
 
@@ -442,8 +442,8 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev)
        if (data->get_tbipa) {
                for_each_child_of_node(np, tbi) {
                        if (strcmp(tbi->type, "tbi-phy") == 0) {
-                               dev_dbg(&pdev->dev, "found TBI PHY node %s\n",
-                                       strrchr(tbi->full_name, '/') + 1);
+                               dev_dbg(&pdev->dev, "found TBI PHY node %pOFP\n",
+                                       tbi);
                                break;
                        }
                }
@@ -454,8 +454,8 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev)
 
                        if (!prop) {
                                dev_err(&pdev->dev,
-                                       "missing 'reg' property in node %s\n",
-                                       tbi->full_name);
+                                       "missing 'reg' property in node %pOF\n",
+                                       tbi);
                                err = -EBUSY;
                                goto error;
                        }
index ff864a1..a37166e 100644 (file)
@@ -776,8 +776,9 @@ void hns_ae_update_led_status(struct hnae_handle *handle)
 
        assert(handle);
        mac_cb = hns_get_mac_cb(handle);
-       if (!mac_cb->cpld_ctrl)
+       if (mac_cb->media_type != HNAE_MEDIA_TYPE_FIBER)
                return;
+
        hns_set_led_opt(mac_cb);
 }
 
index 7a8addd..408b63f 100644 (file)
@@ -53,6 +53,34 @@ static u32 dsaf_read_sub(struct dsaf_device *dsaf_dev, u32 reg)
        return ret;
 }
 
+static void hns_dsaf_acpi_ledctrl_by_port(struct hns_mac_cb *mac_cb, u8 op_type,
+                                      u32 link, u32 port, u32 act)
+{
+       union acpi_object *obj;
+       union acpi_object obj_args[3], argv4;
+
+       obj_args[0].integer.type = ACPI_TYPE_INTEGER;
+       obj_args[0].integer.value = link;
+       obj_args[1].integer.type = ACPI_TYPE_INTEGER;
+       obj_args[1].integer.value = port;
+       obj_args[2].integer.type = ACPI_TYPE_INTEGER;
+       obj_args[2].integer.value = act;
+
+       argv4.type = ACPI_TYPE_PACKAGE;
+       argv4.package.count = 3;
+       argv4.package.elements = obj_args;
+
+       obj = acpi_evaluate_dsm(ACPI_HANDLE(mac_cb->dev),
+                               &hns_dsaf_acpi_dsm_guid, 0, op_type, &argv4);
+       if (!obj) {
+               dev_warn(mac_cb->dev, "ledctrl fail, link:%d port:%d act:%d!\n",
+                        link, port, act);
+               return;
+       }
+
+       ACPI_FREE(obj);
+}
+
 static void hns_cpld_set_led(struct hns_mac_cb *mac_cb, int link_status,
                             u16 speed, int data)
 {
@@ -93,6 +121,18 @@ static void hns_cpld_set_led(struct hns_mac_cb *mac_cb, int link_status,
        }
 }
 
+static void hns_cpld_set_led_acpi(struct hns_mac_cb *mac_cb, int link_status,
+                            u16 speed, int data)
+{
+       if (!mac_cb) {
+               pr_err("cpld_led_set mac_cb is null!\n");
+               return;
+       }
+
+       hns_dsaf_acpi_ledctrl_by_port(mac_cb, HNS_OP_LED_SET_FUNC,
+               link_status, mac_cb->mac_id, data);
+}
+
 static void cpld_led_reset(struct hns_mac_cb *mac_cb)
 {
        if (!mac_cb || !mac_cb->cpld_ctrl)
@@ -103,6 +143,20 @@ static void cpld_led_reset(struct hns_mac_cb *mac_cb)
        mac_cb->cpld_led_value = CPLD_LED_DEFAULT_VALUE;
 }
 
+static void cpld_led_reset_acpi(struct hns_mac_cb *mac_cb)
+{
+       if (!mac_cb) {
+               pr_err("cpld_led_reset mac_cb is null!\n");
+               return;
+       }
+
+       if (mac_cb->media_type != HNAE_MEDIA_TYPE_FIBER)
+                return;
+
+       hns_dsaf_acpi_ledctrl_by_port(mac_cb, HNS_OP_LED_SET_FUNC,
+               0, mac_cb->mac_id, 0);
+}
+
 static int cpld_set_led_id(struct hns_mac_cb *mac_cb,
                           enum hnae_led_state status)
 {
@@ -604,8 +658,8 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev)
 
                misc_op->cfg_serdes_loopback = hns_mac_config_sds_loopback;
        } else if (is_acpi_node(dsaf_dev->dev->fwnode)) {
-               misc_op->cpld_set_led = hns_cpld_set_led;
-               misc_op->cpld_reset_led = cpld_led_reset;
+               misc_op->cpld_set_led = hns_cpld_set_led_acpi;
+               misc_op->cpld_reset_led = cpld_led_reset_acpi;
                misc_op->cpld_set_led_id = cpld_set_led_id;
 
                misc_op->dsaf_reset = hns_dsaf_rst_acpi;
index b9d310f..4878b71 100644 (file)
@@ -3102,8 +3102,7 @@ static int ehea_setup_ports(struct ehea_adapter *adapter)
                dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
                                                 NULL);
                if (!dn_log_port_id) {
-                       pr_err("bad device node: eth_dn name=%s\n",
-                              eth_dn->full_name);
+                       pr_err("bad device node: eth_dn name=%pOF\n", eth_dn);
                        continue;
                }
 
@@ -3425,7 +3424,7 @@ static int ehea_probe_adapter(struct platform_device *dev)
 
        if (!adapter->handle) {
                dev_err(&dev->dev, "failed getting handle for adapter"
-                       " '%s'\n", dev->dev.of_node->full_name);
+                       " '%pOF'\n", dev->dev.of_node);
                ret = -ENODEV;
                goto out_free_ad;
        }
index 259e69a..95135d2 100644 (file)
@@ -133,8 +133,7 @@ static inline void emac_report_timeout_error(struct emac_instance *dev,
                                  EMAC_FTR_440EP_PHY_CLK_FIX))
                DBG(dev, "%s" NL, error);
        else if (net_ratelimit())
-               printk(KERN_ERR "%s: %s\n", dev->ofdev->dev.of_node->full_name,
-                       error);
+               printk(KERN_ERR "%pOF: %s\n", dev->ofdev->dev.of_node, error);
 }
 
 /* EMAC PHY clock workaround:
@@ -2258,8 +2257,8 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev,
 
        strlcpy(info->driver, "ibm_emac", sizeof(info->driver));
        strlcpy(info->version, DRV_VERSION, sizeof(info->version));
-       snprintf(info->bus_info, sizeof(info->bus_info), "PPC 4xx EMAC-%d %s",
-                dev->cell_index, dev->ofdev->dev.of_node->full_name);
+       snprintf(info->bus_info, sizeof(info->bus_info), "PPC 4xx EMAC-%d %pOF",
+                dev->cell_index, dev->ofdev->dev.of_node);
 }
 
 static const struct ethtool_ops emac_ethtool_ops = {
@@ -2431,8 +2430,8 @@ static int emac_read_uint_prop(struct device_node *np, const char *name,
        const u32 *prop = of_get_property(np, name, &len);
        if (prop == NULL || len < sizeof(u32)) {
                if (fatal)
-                       printk(KERN_ERR "%s: missing %s property\n",
-                              np->full_name, name);
+                       printk(KERN_ERR "%pOF: missing %s property\n",
+                              np, name);
                return -ENODEV;
        }
        *val = *prop;
@@ -2768,7 +2767,7 @@ static int emac_init_phy(struct emac_instance *dev)
 #endif
        mutex_unlock(&emac_phy_map_lock);
        if (i == 0x20) {
-               printk(KERN_WARNING "%s: can't find PHY!\n", np->full_name);
+               printk(KERN_WARNING "%pOF: can't find PHY!\n", np);
                return -ENXIO;
        }
 
@@ -2894,8 +2893,8 @@ static int emac_init_config(struct emac_instance *dev)
 #ifdef CONFIG_IBM_EMAC_NO_FLOW_CTRL
                        dev->features |= EMAC_FTR_NO_FLOW_CONTROL_40x;
 #else
-                       printk(KERN_ERR "%s: Flow control not disabled!\n",
-                                       np->full_name);
+                       printk(KERN_ERR "%pOF: Flow control not disabled!\n",
+                                       np);
                        return -ENXIO;
 #endif
                }
@@ -2918,8 +2917,7 @@ static int emac_init_config(struct emac_instance *dev)
 #ifdef CONFIG_IBM_EMAC_TAH
                dev->features |= EMAC_FTR_HAS_TAH;
 #else
-               printk(KERN_ERR "%s: TAH support not enabled !\n",
-                      np->full_name);
+               printk(KERN_ERR "%pOF: TAH support not enabled !\n", np);
                return -ENXIO;
 #endif
        }
@@ -2928,8 +2926,7 @@ static int emac_init_config(struct emac_instance *dev)
 #ifdef CONFIG_IBM_EMAC_ZMII
                dev->features |= EMAC_FTR_HAS_ZMII;
 #else
-               printk(KERN_ERR "%s: ZMII support not enabled !\n",
-                      np->full_name);
+               printk(KERN_ERR "%pOF: ZMII support not enabled !\n", np);
                return -ENXIO;
 #endif
        }
@@ -2938,8 +2935,7 @@ static int emac_init_config(struct emac_instance *dev)
 #ifdef CONFIG_IBM_EMAC_RGMII
                dev->features |= EMAC_FTR_HAS_RGMII;
 #else
-               printk(KERN_ERR "%s: RGMII support not enabled !\n",
-                      np->full_name);
+               printk(KERN_ERR "%pOF: RGMII support not enabled !\n", np);
                return -ENXIO;
 #endif
        }
@@ -2947,8 +2943,8 @@ static int emac_init_config(struct emac_instance *dev)
        /* Read MAC-address */
        p = of_get_property(np, "local-mac-address", NULL);
        if (p == NULL) {
-               printk(KERN_ERR "%s: Can't find local-mac-address property\n",
-                      np->full_name);
+               printk(KERN_ERR "%pOF: Can't find local-mac-address property\n",
+                      np);
                return -ENXIO;
        }
        memcpy(dev->ndev->dev_addr, p, ETH_ALEN);
@@ -3043,23 +3039,21 @@ static int emac_probe(struct platform_device *ofdev)
        dev->emac_irq = irq_of_parse_and_map(np, 0);
        dev->wol_irq = irq_of_parse_and_map(np, 1);
        if (!dev->emac_irq) {
-               printk(KERN_ERR "%s: Can't map main interrupt\n", np->full_name);
+               printk(KERN_ERR "%pOF: Can't map main interrupt\n", np);
                goto err_free;
        }
        ndev->irq = dev->emac_irq;
 
        /* Map EMAC regs */
        if (of_address_to_resource(np, 0, &dev->rsrc_regs)) {
-               printk(KERN_ERR "%s: Can't get registers address\n",
-                      np->full_name);
+               printk(KERN_ERR "%pOF: Can't get registers address\n", np);
                goto err_irq_unmap;
        }
        // TODO : request_mem_region
        dev->emacp = ioremap(dev->rsrc_regs.start,
                             resource_size(&dev->rsrc_regs));
        if (dev->emacp == NULL) {
-               printk(KERN_ERR "%s: Can't map device registers!\n",
-                      np->full_name);
+               printk(KERN_ERR "%pOF: Can't map device registers!\n", np);
                err = -ENOMEM;
                goto err_irq_unmap;
        }
@@ -3068,8 +3062,7 @@ static int emac_probe(struct platform_device *ofdev)
        err = emac_wait_deps(dev);
        if (err) {
                printk(KERN_ERR
-                      "%s: Timeout waiting for dependent devices\n",
-                      np->full_name);
+                      "%pOF: Timeout waiting for dependent devices\n", np);
                /*  display more info about what's missing ? */
                goto err_reg_unmap;
        }
@@ -3084,8 +3077,8 @@ static int emac_probe(struct platform_device *ofdev)
        dev->commac.rx_chan_mask = MAL_CHAN_MASK(dev->mal_rx_chan);
        err = mal_register_commac(dev->mal, &dev->commac);
        if (err) {
-               printk(KERN_ERR "%s: failed to register with mal %s!\n",
-                      np->full_name, dev->mal_dev->dev.of_node->full_name);
+               printk(KERN_ERR "%pOF: failed to register with mal %pOF!\n",
+                      np, dev->mal_dev->dev.of_node);
                goto err_rel_deps;
        }
        dev->rx_skb_size = emac_rx_skb_size(ndev->mtu);
@@ -3161,8 +3154,8 @@ static int emac_probe(struct platform_device *ofdev)
 
        err = register_netdev(ndev);
        if (err) {
-               printk(KERN_ERR "%s: failed to register net device (%d)!\n",
-                      np->full_name, err);
+               printk(KERN_ERR "%pOF: failed to register net device (%d)!\n",
+                      np, err);
                goto err_detach_tah;
        }
 
@@ -3176,8 +3169,8 @@ static int emac_probe(struct platform_device *ofdev)
        wake_up_all(&emac_probe_wait);
 
 
-       printk(KERN_INFO "%s: EMAC-%d %s, MAC %pM\n",
-              ndev->name, dev->cell_index, np->full_name, ndev->dev_addr);
+       printk(KERN_INFO "%s: EMAC-%d %pOF, MAC %pM\n",
+              ndev->name, dev->cell_index, np, ndev->dev_addr);
 
        if (dev->phy_mode == PHY_MODE_SGMII)
                printk(KERN_NOTICE "%s: in SGMII mode\n", ndev->name);
index 5bdfc17..9d06d3b 100644 (file)
@@ -31,7 +31,7 @@
 #endif
 
 #define EMAC_DBG(d, name, fmt, arg...) \
-       printk(KERN_DEBUG #name "%s: " fmt, d->ofdev->dev.of_node->full_name, ## arg)
+       printk(KERN_DEBUG #name "%pOF: " fmt, d->ofdev->dev.of_node, ## arg)
 
 #if DBG_LEVEL > 0
 #  define DBG(d,f,x...)                EMAC_DBG(d, emac, f, ##x)
index 91b1a55..2c74baa 100644 (file)
@@ -579,8 +579,8 @@ static int mal_probe(struct platform_device *ofdev)
                mal->features |= (MAL_FTR_CLEAR_ICINTSTAT |
                                MAL_FTR_COMMON_ERR_INT);
 #else
-               printk(KERN_ERR "%s: Support for 405EZ not enabled!\n",
-                               ofdev->dev.of_node->full_name);
+               printk(KERN_ERR "%pOF: Support for 405EZ not enabled!\n",
+                               ofdev->dev.of_node);
                err = -ENODEV;
                goto fail;
 #endif
@@ -687,8 +687,8 @@ static int mal_probe(struct platform_device *ofdev)
        mal_enable_eob_irq(mal);
 
        printk(KERN_INFO
-              "MAL v%d %s, %d TX channels, %d RX channels\n",
-              mal->version, ofdev->dev.of_node->full_name,
+              "MAL v%d %pOF, %d TX channels, %d RX channels\n",
+              mal->version, ofdev->dev.of_node,
               mal->num_tx_chans, mal->num_rx_chans);
 
        /* Advertise this instance to the rest of the world */
index 206ccbb..c4a1ac3 100644 (file)
@@ -104,8 +104,8 @@ int rgmii_attach(struct platform_device *ofdev, int input, int mode)
 
        /* Check if we need to attach to a RGMII */
        if (input < 0 || !rgmii_valid_mode(mode)) {
-               printk(KERN_ERR "%s: unsupported settings !\n",
-                      ofdev->dev.of_node->full_name);
+               printk(KERN_ERR "%pOF: unsupported settings !\n",
+                      ofdev->dev.of_node);
                return -ENODEV;
        }
 
@@ -114,8 +114,8 @@ int rgmii_attach(struct platform_device *ofdev, int input, int mode)
        /* Enable this input */
        out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input));
 
-       printk(KERN_NOTICE "%s: input %d in %s mode\n",
-              ofdev->dev.of_node->full_name, input, rgmii_mode_name(mode));
+       printk(KERN_NOTICE "%pOF: input %d in %s mode\n",
+              ofdev->dev.of_node, input, rgmii_mode_name(mode));
 
        ++dev->users;
 
@@ -249,8 +249,7 @@ static int rgmii_probe(struct platform_device *ofdev)
 
        rc = -ENXIO;
        if (of_address_to_resource(np, 0, &regs)) {
-               printk(KERN_ERR "%s: Can't get registers address\n",
-                      np->full_name);
+               printk(KERN_ERR "%pOF: Can't get registers address\n", np);
                goto err_free;
        }
 
@@ -258,8 +257,7 @@ static int rgmii_probe(struct platform_device *ofdev)
        dev->base = (struct rgmii_regs __iomem *)ioremap(regs.start,
                                                 sizeof(struct rgmii_regs));
        if (dev->base == NULL) {
-               printk(KERN_ERR "%s: Can't map device registers!\n",
-                      np->full_name);
+               printk(KERN_ERR "%pOF: Can't map device registers!\n", np);
                goto err_free;
        }
 
@@ -278,8 +276,8 @@ static int rgmii_probe(struct platform_device *ofdev)
        out_be32(&dev->base->fer, 0);
 
        printk(KERN_INFO
-              "RGMII %s initialized with%s MDIO support\n",
-              ofdev->dev.of_node->full_name,
+              "RGMII %pOF initialized with%s MDIO support\n",
+              ofdev->dev.of_node,
               (dev->flags & EMAC_RGMII_FLAG_HAS_MDIO) ? "" : "out");
 
        wmb();
index 32cb6c9..9912456 100644 (file)
@@ -58,8 +58,7 @@ void tah_reset(struct platform_device *ofdev)
                --n;
 
        if (unlikely(!n))
-               printk(KERN_ERR "%s: reset timeout\n",
-                       ofdev->dev.of_node->full_name);
+               printk(KERN_ERR "%pOF: reset timeout\n", ofdev->dev.of_node);
 
        /* 10KB TAH TX FIFO accommodates the max MTU of 9000 */
        out_be32(&p->mr,
@@ -105,8 +104,7 @@ static int tah_probe(struct platform_device *ofdev)
 
        rc = -ENXIO;
        if (of_address_to_resource(np, 0, &regs)) {
-               printk(KERN_ERR "%s: Can't get registers address\n",
-                      np->full_name);
+               printk(KERN_ERR "%pOF: Can't get registers address\n", np);
                goto err_free;
        }
 
@@ -114,8 +112,7 @@ static int tah_probe(struct platform_device *ofdev)
        dev->base = (struct tah_regs __iomem *)ioremap(regs.start,
                                               sizeof(struct tah_regs));
        if (dev->base == NULL) {
-               printk(KERN_ERR "%s: Can't map device registers!\n",
-                      np->full_name);
+               printk(KERN_ERR "%pOF: Can't map device registers!\n", np);
                goto err_free;
        }
 
@@ -124,8 +121,7 @@ static int tah_probe(struct platform_device *ofdev)
        /* Initialize TAH and enable IPv4 checksum verification, no TSO yet */
        tah_reset(ofdev);
 
-       printk(KERN_INFO
-              "TAH %s initialized\n", ofdev->dev.of_node->full_name);
+       printk(KERN_INFO "TAH %pOF initialized\n", ofdev->dev.of_node);
        wmb();
 
        return 0;
index 8727b86..89c42d3 100644 (file)
@@ -121,15 +121,15 @@ int zmii_attach(struct platform_device *ofdev, int input, int *mode)
                } else
                        dev->mode = *mode;
 
-               printk(KERN_NOTICE "%s: bridge in %s mode\n",
-                      ofdev->dev.of_node->full_name,
+               printk(KERN_NOTICE "%pOF: bridge in %s mode\n",
+                      ofdev->dev.of_node,
                       zmii_mode_name(dev->mode));
        } else {
                /* All inputs must use the same mode */
                if (*mode != PHY_MODE_NA && *mode != dev->mode) {
                        printk(KERN_ERR
-                              "%s: invalid mode %d specified for input %d\n",
-                              ofdev->dev.of_node->full_name, *mode, input);
+                              "%pOF: invalid mode %d specified for input %d\n",
+                              ofdev->dev.of_node, *mode, input);
                        mutex_unlock(&dev->lock);
                        return -EINVAL;
                }
@@ -250,8 +250,7 @@ static int zmii_probe(struct platform_device *ofdev)
 
        rc = -ENXIO;
        if (of_address_to_resource(np, 0, &regs)) {
-               printk(KERN_ERR "%s: Can't get registers address\n",
-                      np->full_name);
+               printk(KERN_ERR "%pOF: Can't get registers address\n", np);
                goto err_free;
        }
 
@@ -259,8 +258,7 @@ static int zmii_probe(struct platform_device *ofdev)
        dev->base = (struct zmii_regs __iomem *)ioremap(regs.start,
                                                sizeof(struct zmii_regs));
        if (dev->base == NULL) {
-               printk(KERN_ERR "%s: Can't map device registers!\n",
-                      np->full_name);
+               printk(KERN_ERR "%pOF: Can't map device registers!\n", np);
                goto err_free;
        }
 
@@ -270,8 +268,7 @@ static int zmii_probe(struct platform_device *ofdev)
        /* Disable all inputs by default */
        out_be32(&dev->base->fer, 0);
 
-       printk(KERN_INFO
-              "ZMII %s initialized\n", ofdev->dev.of_node->full_name);
+       printk(KERN_INFO "ZMII %pOF initialized\n", ofdev->dev.of_node);
        wmb();
        platform_set_drvdata(ofdev, dev);
 
index a3e6946..9d8af46 100644 (file)
@@ -3851,10 +3851,7 @@ static int ibmvnic_resume(struct device *dev)
        if (adapter->state != VNIC_OPEN)
                return 0;
 
-       /* kick the interrupt handlers just in case we lost an interrupt */
-       for (i = 0; i < adapter->req_rx_queues; i++)
-               ibmvnic_interrupt_rx(adapter->rx_scrq[i]->irq,
-                                    adapter->rx_scrq[i]);
+       tasklet_schedule(&adapter->tasklet);
 
        return 0;
 }
index 9692a52..1d29152 100644 (file)
@@ -1091,7 +1091,7 @@ static void i40e_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
        struct i40e_pf *pf = np->vsi->back;
        struct i40e_hw *hw = &pf->hw;
        u32 *reg_buf = p;
-       int i, j, ri;
+       unsigned int i, j, ri;
        u32 reg;
 
        /* Tell ethtool which driver-version-specific regs output we have.
@@ -1550,9 +1550,9 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
        struct i40e_ring *tx_ring, *rx_ring;
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
+       unsigned int j;
        int i = 0;
        char *p;
-       int j;
        struct rtnl_link_stats64 *net_stats = i40e_get_vsi_stats_struct(vsi);
        unsigned int start;
 
@@ -1637,7 +1637,7 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset,
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
        char *p = (char *)data;
-       int i;
+       unsigned int i;
 
        switch (stringset) {
        case ETH_SS_TEST:
index 2db93d3..4104944 100644 (file)
@@ -4773,7 +4773,7 @@ static void i40e_detect_recover_hung(struct i40e_pf *pf)
 {
        struct net_device *netdev;
        struct i40e_vsi *vsi;
-       int i;
+       unsigned int i;
 
        /* Only for LAN VSI */
        vsi = pf->vsi[pf->lan_vsi];
@@ -7520,6 +7520,18 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
        i40e_flush(hw);
 }
 
+static const char *i40e_tunnel_name(struct i40e_udp_port_config *port)
+{
+       switch (port->type) {
+       case UDP_TUNNEL_TYPE_VXLAN:
+               return "vxlan";
+       case UDP_TUNNEL_TYPE_GENEVE:
+               return "geneve";
+       default:
+               return "unknown";
+       }
+}
+
 /**
  * i40e_sync_udp_filters - Trigger a sync event for existing UDP filters
  * @pf: board private structure
@@ -7565,14 +7577,14 @@ static void i40e_sync_udp_filters_subtask(struct i40e_pf *pf)
                                ret = i40e_aq_del_udp_tunnel(hw, i, NULL);
 
                        if (ret) {
-                               dev_dbg(&pf->pdev->dev,
-                                       "%s %s port %d, index %d failed, err %s aq_err %s\n",
-                                       pf->udp_ports[i].type ? "vxlan" : "geneve",
-                                       port ? "add" : "delete",
-                                       port, i,
-                                       i40e_stat_str(&pf->hw, ret),
-                                       i40e_aq_str(&pf->hw,
-                                                   pf->hw.aq.asq_last_status));
+                               dev_info(&pf->pdev->dev,
+                                        "%s %s port %d, index %d failed, err %s aq_err %s\n",
+                                        i40e_tunnel_name(&pf->udp_ports[i]),
+                                        port ? "add" : "delete",
+                                        port, i,
+                                        i40e_stat_str(&pf->hw, ret),
+                                        i40e_aq_str(&pf->hw,
+                                                    pf->hw.aq.asq_last_status));
                                pf->udp_ports[i].port = 0;
                        }
                }
@@ -9589,6 +9601,7 @@ static int i40e_xdp(struct net_device *dev,
                return i40e_xdp_setup(vsi, xdp->prog);
        case XDP_QUERY_PROG:
                xdp->prog_attached = i40e_enabled_xdp_vsi(vsi);
+               xdp->prog_id = vsi->xdp_prog ? vsi->xdp_prog->aux->id : 0;
                return 0;
        default:
                return -EINVAL;
@@ -12089,7 +12102,10 @@ static int i40e_suspend(struct pci_dev *pdev, pm_message_t state)
        wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
 
        i40e_stop_misc_vector(pf);
-
+       if (pf->msix_entries) {
+               synchronize_irq(pf->msix_entries[0].vector);
+               free_irq(pf->msix_entries[0].vector, pf);
+       }
        retval = pci_save_state(pdev);
        if (retval)
                return retval;
@@ -12129,6 +12145,15 @@ static int i40e_resume(struct pci_dev *pdev)
        /* handling the reset will rebuild the device state */
        if (test_and_clear_bit(__I40E_SUSPENDED, pf->state)) {
                clear_bit(__I40E_DOWN, pf->state);
+               if (pf->msix_entries) {
+                       err = request_irq(pf->msix_entries[0].vector,
+                                         i40e_intr, 0, pf->int_name, pf);
+                       if (err) {
+                               dev_err(&pf->pdev->dev,
+                                       "request_irq for %s failed: %d\n",
+                                       pf->int_name, err);
+                       }
+               }
                i40e_reset_and_rebuild(pf, false, false);
        }
 
@@ -12168,12 +12193,14 @@ static int __init i40e_init_module(void)
                i40e_driver_string, i40e_driver_version_str);
        pr_info("%s: %s\n", i40e_driver_name, i40e_copyright);
 
-       /* we will see if single thread per module is enough for now,
-        * it can't be any worse than using the system workqueue which
-        * was already single threaded
+       /* There is no need to throttle the number of active tasks because
+        * each device limits its own task using a state bit for scheduling
+        * the service task, and the device tasks do not interfere with each
+        * other, so we don't set a max task limit. We must set WQ_MEM_RECLAIM
+        * since we need to be able to guarantee forward progress even under
+        * memory pressure.
         */
-       i40e_wq = alloc_workqueue("%s", WQ_UNBOUND | WQ_MEM_RECLAIM, 1,
-                                 i40e_driver_name);
+       i40e_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0, i40e_driver_name);
        if (!i40e_wq) {
                pr_err("%s: Failed to create workqueue\n", i40e_driver_name);
                return -ENOMEM;
index 800bd55..6fdecd7 100644 (file)
@@ -134,8 +134,25 @@ i40e_i40e_acquire_nvm_exit:
  **/
 void i40e_release_nvm(struct i40e_hw *hw)
 {
-       if (!hw->nvm.blank_nvm_mode)
-               i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
+       i40e_status ret_code = I40E_SUCCESS;
+       u32 total_delay = 0;
+
+       if (hw->nvm.blank_nvm_mode)
+               return;
+
+       ret_code = i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
+
+       /* there are some rare cases when trying to release the resource
+        * results in an admin Q timeout, so handle them correctly
+        */
+       while ((ret_code == I40E_ERR_ADMIN_QUEUE_TIMEOUT) &&
+              (total_delay < hw->aq.asq_cmd_timeout)) {
+               usleep_range(1000, 2000);
+               ret_code = i40e_aq_release_resource(hw,
+                                                   I40E_NVM_RESOURCE_ID,
+                                                   0, NULL);
+               total_delay++;
+       }
 }
 
 /**
index 1a0be83..0129ed3 100644 (file)
@@ -158,13 +158,12 @@ static int i40e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
 static int i40e_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
 {
        struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps);
-       struct timespec64 now, then;
+       struct timespec64 now;
 
-       then = ns_to_timespec64(delta);
        mutex_lock(&pf->tmreg_lock);
 
        i40e_ptp_read(pf, &now);
-       now = timespec64_add(now, then);
+       timespec64_add_ns(&now, delta);
        i40e_ptp_write(pf, (const struct timespec64 *)&now);
 
        mutex_unlock(&pf->tmreg_lock);
index b936feb..d464fce 100644 (file)
@@ -860,7 +860,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
        netdev_tx_completed_queue(txring_txq(tx_ring),
                                  total_packets, total_bytes);
 
-#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
+#define TX_WAKE_THRESHOLD ((s16)(DESC_NEEDED * 2))
        if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) &&
                     (I40E_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) {
                /* Make sure that anybody stopping the queue after this
@@ -2063,7 +2063,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
        u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
        bool failure = false, xdp_xmit = false;
 
-       while (likely(total_rx_packets < budget)) {
+       while (likely(total_rx_packets < (unsigned int)budget)) {
                struct i40e_rx_buffer *rx_buffer;
                union i40e_rx_desc *rx_desc;
                struct xdp_buff xdp;
@@ -2196,7 +2196,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
        rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
 
        /* guarantee a trip back through this routine if there was a failure */
-       return failure ? budget : total_rx_packets;
+       return failure ? budget : (int)total_rx_packets;
 }
 
 static u32 i40e_buildreg_itr(const int type, const u16 itr)
@@ -2451,9 +2451,15 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
                hlen = (hdr.network[0] & 0x0F) << 2;
                l4_proto = hdr.ipv4->protocol;
        } else {
-               hlen = hdr.network - skb->data;
-               l4_proto = ipv6_find_hdr(skb, &hlen, IPPROTO_TCP, NULL, NULL);
-               hlen -= hdr.network - skb->data;
+               /* find the start of the innermost ipv6 header */
+               unsigned int inner_hlen = hdr.network - skb->data;
+               unsigned int h_offset = inner_hlen;
+
+               /* this function updates h_offset to the end of the header */
+               l4_proto =
+                 ipv6_find_hdr(skb, &h_offset, IPPROTO_TCP, NULL, NULL);
+               /* hlen will contain our best estimate of the tcp header */
+               hlen = h_offset - inner_hlen;
        }
 
        if (l4_proto != IPPROTO_TCP)
index ecbe40e..979110d 100644 (file)
@@ -1567,7 +1567,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
                        dev_err(&pf->pdev->dev,
                                "VF %d requested polling mode: this feature is supported only when the device is running in single function per port (SFP) mode\n",
                                 vf->vf_id);
-                       ret = I40E_ERR_PARAM;
+                       aq_ret = I40E_ERR_PARAM;
                        goto err;
                }
                vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING;
@@ -1741,16 +1741,14 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf,
                                                            NULL);
        } else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
                hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
-                       aq_ret = 0;
-                       if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID) {
-                               aq_ret =
-                               i40e_aq_set_vsi_uc_promisc_on_vlan(hw,
-                                                                  vsi->seid,
-                                                                  alluni,
-                                                                  f->vlan,
-                                                                  NULL);
-                               aq_err = pf->hw.aq.asq_last_status;
-                       }
+                       if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
+                               continue;
+                       aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw,
+                                                                   vsi->seid,
+                                                                   alluni,
+                                                                   f->vlan,
+                                                                   NULL);
+                       aq_err = pf->hw.aq.asq_last_status;
                        if (aq_ret)
                                dev_err(&pf->pdev->dev,
                                        "Could not add VLAN %d to Unicast promiscuous domain err %s aq_err %s\n",
@@ -2764,7 +2762,6 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
 
        spin_unlock_bh(&vsi->mac_filter_hash_lock);
 
-       dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n", mac, vf_id);
        /* program mac filter */
        if (i40e_sync_vsi_filters(vsi)) {
                dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
@@ -2772,7 +2769,16 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
                goto error_param;
        }
        ether_addr_copy(vf->default_lan_addr.addr, mac);
-       vf->pf_set_mac = true;
+
+       if (is_zero_ether_addr(mac)) {
+               vf->pf_set_mac = false;
+               dev_info(&pf->pdev->dev, "Removing MAC on VF %d\n", vf_id);
+       } else {
+               vf->pf_set_mac = true;
+               dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n",
+                        mac, vf_id);
+       }
+
        /* 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");
index 5e314fd..a907377 100644 (file)
@@ -54,7 +54,7 @@ struct i40e_dma_mem {
        void *va;
        dma_addr_t pa;
        u32 size;
-} __packed;
+};
 
 #define i40e_allocate_dma_mem(h, m, unused, s, a) \
        i40evf_allocate_dma_mem_d(h, m, s, a)
@@ -63,7 +63,7 @@ struct i40e_dma_mem {
 struct i40e_virt_mem {
        void *va;
        u32 size;
-} __packed;
+};
 #define i40e_allocate_virt_mem(h, m, s) i40evf_allocate_virt_mem_d(h, m, s)
 #define i40e_free_virt_mem(h, m) i40evf_free_virt_mem_d(h, m)
 
index 12b02e5..d91676c 100644 (file)
@@ -275,7 +275,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
        netdev_tx_completed_queue(txring_txq(tx_ring),
                                  total_packets, total_bytes);
 
-#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
+#define TX_WAKE_THRESHOLD ((s16)(DESC_NEEDED * 2))
        if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) &&
                     (I40E_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) {
                /* Make sure that anybody stopping the queue after this
@@ -1299,7 +1299,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
        u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
        bool failure = false;
 
-       while (likely(total_rx_packets < budget)) {
+       while (likely(total_rx_packets < (unsigned int)budget)) {
                struct i40e_rx_buffer *rx_buffer;
                union i40e_rx_desc *rx_desc;
                unsigned int size;
@@ -1406,7 +1406,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
        rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
 
        /* guarantee a trip back through this routine if there was a failure */
-       return failure ? budget : total_rx_packets;
+       return failure ? budget : (int)total_rx_packets;
 }
 
 static u32 i40e_buildreg_itr(const int type, const u16 itr)
index 6cc9208..7901cc8 100644 (file)
 #include <linux/tcp.h>
 #include <linux/sctp.h>
 #include <linux/ipv6.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/gfp.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/socket.h>
+#include <linux/jiffies.h>
 #include <net/ip6_checksum.h>
 #include <net/udp.h>
 
index 9bb2cc7..76fd89c 100644 (file)
@@ -165,7 +165,7 @@ static void i40evf_get_ethtool_stats(struct net_device *netdev,
                                     struct ethtool_stats *stats, u64 *data)
 {
        struct i40evf_adapter *adapter = netdev_priv(netdev);
-       int i, j;
+       unsigned int i, j;
        char *p;
 
        for (i = 0; i < I40EVF_GLOBAL_STATS_LEN; i++) {
@@ -197,7 +197,7 @@ static void i40evf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
        int i;
 
        if (sset == ETH_SS_STATS) {
-               for (i = 0; i < I40EVF_GLOBAL_STATS_LEN; i++) {
+               for (i = 0; i < (int)I40EVF_GLOBAL_STATS_LEN; i++) {
                        memcpy(p, i40evf_gstrings_stats[i].stat_string,
                               ETH_GSTRING_LEN);
                        p += ETH_GSTRING_LEN;
index 7c213a3..93536b9 100644 (file)
@@ -1957,8 +1957,8 @@ static void i40evf_adminq_task(struct work_struct *work)
                container_of(work, struct i40evf_adapter, adminq_task);
        struct i40e_hw *hw = &adapter->hw;
        struct i40e_arq_event_info event;
-       struct virtchnl_msg *v_msg;
-       i40e_status ret;
+       enum virtchnl_ops v_op;
+       i40e_status ret, v_ret;
        u32 val, oldval;
        u16 pending;
 
@@ -1970,15 +1970,15 @@ static void i40evf_adminq_task(struct work_struct *work)
        if (!event.msg_buf)
                goto out;
 
-       v_msg = (struct virtchnl_msg *)&event.desc;
        do {
                ret = i40evf_clean_arq_element(hw, &event, &pending);
-               if (ret || !v_msg->v_opcode)
+               v_op = (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high);
+               v_ret = (i40e_status)le32_to_cpu(event.desc.cookie_low);
+
+               if (ret || !v_op)
                        break; /* No event to process or error cleaning ARQ */
 
-               i40evf_virtchnl_completion(adapter, v_msg->v_opcode,
-                                          (i40e_status)v_msg->v_retval,
-                                          event.msg_buf,
+               i40evf_virtchnl_completion(adapter, v_op, v_ret, event.msg_buf,
                                           event.msg_len);
                if (pending != 0)
                        memset(event.msg_buf, 0, I40EVF_MAX_AQ_BUF_SIZE);
index 4e35e70..2c19070 100644 (file)
@@ -79,16 +79,28 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
 
        switch (hw->phy.media_type) {
        case ixgbe_media_type_fiber:
-               hw->mac.ops.check_link(hw, &speed, &link_up, false);
-               /* if link is down, assume supported */
-               if (link_up)
-                       supported = speed == IXGBE_LINK_SPEED_1GB_FULL ?
+               /* flow control autoneg black list */
+               switch (hw->device_id) {
+               case IXGBE_DEV_ID_X550EM_A_SFP:
+               case IXGBE_DEV_ID_X550EM_A_SFP_N:
+                       supported = false;
+                       break;
+               default:
+                       hw->mac.ops.check_link(hw, &speed, &link_up, false);
+                       /* if link is down, assume supported */
+                       if (link_up)
+                               supported = speed == IXGBE_LINK_SPEED_1GB_FULL ?
                                true : false;
-               else
-                       supported = true;
+                       else
+                               supported = true;
+               }
+
                break;
        case ixgbe_media_type_backplane:
-               supported = true;
+               if (hw->device_id == IXGBE_DEV_ID_X550EM_X_XFI)
+                       supported = false;
+               else
+                       supported = true;
                break;
        case ixgbe_media_type_copper:
                /* only some copper devices support flow control autoneg */
@@ -111,6 +123,10 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
                break;
        }
 
+       if (!supported)
+               hw_dbg(hw, "Device %x does not support flow control autoneg\n",
+                      hw->device_id);
+
        return supported;
 }
 
index 0f867dc..96606e3 100644 (file)
@@ -386,7 +386,7 @@ u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
        if (ixgbe_removed(reg_addr))
                return IXGBE_FAILED_READ_REG;
        if (unlikely(hw->phy.nw_mng_if_sel &
-                    IXGBE_NW_MNG_IF_SEL_ENABLE_10_100M)) {
+                    IXGBE_NW_MNG_IF_SEL_SGMII_ENABLE)) {
                struct ixgbe_adapter *adapter;
                int i;
 
index 0760bd7..112d24c 100644 (file)
@@ -679,8 +679,9 @@ update_vlvfb:
 static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter,
                                int vf, int index, unsigned char *mac_addr)
 {
-       struct list_head *pos;
        struct vf_macvlans *entry;
+       struct list_head *pos;
+       int retval = 0;
 
        if (index <= 1) {
                list_for_each(pos, &adapter->vf_mvs.l) {
@@ -721,13 +722,15 @@ static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter,
        if (!entry || !entry->free)
                return -ENOSPC;
 
+       retval = ixgbe_add_mac_filter(adapter, mac_addr, vf);
+       if (retval < 0)
+               return retval;
+
        entry->free = false;
        entry->is_macvlan = true;
        entry->vf = vf;
        memcpy(entry->vf_macvlan, mac_addr, ETH_ALEN);
 
-       ixgbe_add_mac_filter(adapter, mac_addr, vf);
-
        return 0;
 }
 
index 9c2460c..ffa0ee5 100644 (file)
@@ -3778,8 +3778,8 @@ struct ixgbe_info {
 #define IXGBE_NW_MNG_IF_SEL_PHY_SPEED_1G       BIT(19)
 #define IXGBE_NW_MNG_IF_SEL_PHY_SPEED_2_5G     BIT(20)
 #define IXGBE_NW_MNG_IF_SEL_PHY_SPEED_10G      BIT(21)
-#define IXGBE_NW_MNG_IF_SEL_ENABLE_10_100M     BIT(23)
-#define IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE       BIT(24)
+#define IXGBE_NW_MNG_IF_SEL_SGMII_ENABLE       BIT(25)
+#define IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE       BIT(24) /* X552 only */
 #define IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT 3
 #define IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD       \
                                (0x1F << IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT)
index 72d84a0..19fbb2f 100644 (file)
@@ -1555,9 +1555,14 @@ static s32 ixgbe_restart_an_internal_phy_x550em(struct ixgbe_hw *hw)
  **/
 static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
 {
+       struct ixgbe_mac_info *mac = &hw->mac;
        s32 status;
        u32 reg_val;
 
+       /* iXFI is only supported with X552 */
+       if (mac->type != ixgbe_mac_X550EM_x)
+               return IXGBE_ERR_LINK_SETUP;
+
        /* Disable AN and force speed to 10G Serial. */
        status = ixgbe_read_iosf_sb_reg_x550(hw,
                                        IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
@@ -1874,8 +1879,10 @@ static s32 ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw,
        else
                force_speed = IXGBE_LINK_SPEED_1GB_FULL;
 
-       /* If internal link mode is XFI, then setup XFI internal link. */
-       if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
+       /* If X552 and internal link mode is XFI, then setup XFI internal link.
+        */
+       if (hw->mac.type == ixgbe_mac_X550EM_x &&
+           !(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
                status = ixgbe_setup_ixfi_x550em(hw, &force_speed);
 
                if (status)
@@ -2404,17 +2411,30 @@ static s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw)
        status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
 
        /* Enable link status change alarm */
-       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
-                                     MDIO_MMD_AN, &reg);
-       if (status)
-               return status;
 
-       reg |= IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN;
+       /* Enable the LASI interrupts on X552 devices to receive notifications
+        * of the link configurations of the external PHY and correspondingly
+        * support the configuration of the internal iXFI link, since iXFI does
+        * not support auto-negotiation. This is not required for X553 devices
+        * having KR support, which performs auto-negotiations and which is used
+        * as the internal link to the external PHY. Hence adding a check here
+        * to avoid enabling LASI interrupts for X553 devices.
+        */
+       if (hw->mac.type != ixgbe_mac_x550em_a) {
+               status = hw->phy.ops.read_reg(hw,
+                                           IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
+                                           MDIO_MMD_AN, &reg);
+               if (status)
+                       return status;
 
-       status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
-                                      MDIO_MMD_AN, reg);
-       if (status)
-               return status;
+               reg |= IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN;
+
+               status = hw->phy.ops.write_reg(hw,
+                                           IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
+                                           MDIO_MMD_AN, reg);
+               if (status)
+                       return status;
+       }
 
        /* Enable high temperature failure and global fault alarms */
        status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
@@ -2615,7 +2635,8 @@ static s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw)
        if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
                return IXGBE_ERR_CONFIG;
 
-       if (hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE) {
+       if (!(hw->mac.type == ixgbe_mac_X550EM_x &&
+             !(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE))) {
                speed = IXGBE_LINK_SPEED_10GB_FULL |
                        IXGBE_LINK_SPEED_1GB_FULL;
                return ixgbe_setup_kr_speed_x550em(hw, speed);
@@ -2822,7 +2843,7 @@ static s32 ixgbe_setup_fc_x550em(struct ixgbe_hw *hw)
 {
        bool pause, asm_dir;
        u32 reg_val;
-       s32 rc;
+       s32 rc = 0;
 
        /* Validate the requested mode */
        if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
@@ -2865,32 +2886,37 @@ static s32 ixgbe_setup_fc_x550em(struct ixgbe_hw *hw)
                return IXGBE_ERR_CONFIG;
        }
 
-       if (hw->device_id != IXGBE_DEV_ID_X550EM_X_KR &&
-           hw->device_id != IXGBE_DEV_ID_X550EM_A_KR &&
-           hw->device_id != IXGBE_DEV_ID_X550EM_A_KR_L)
-               return 0;
-
-       rc = hw->mac.ops.read_iosf_sb_reg(hw,
-                                         IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
-                                         IXGBE_SB_IOSF_TARGET_KR_PHY,
-                                         &reg_val);
-       if (rc)
-               return rc;
-
-       reg_val &= ~(IXGBE_KRM_AN_CNTL_1_SYM_PAUSE |
-                    IXGBE_KRM_AN_CNTL_1_ASM_PAUSE);
-       if (pause)
-               reg_val |= IXGBE_KRM_AN_CNTL_1_SYM_PAUSE;
-       if (asm_dir)
-               reg_val |= IXGBE_KRM_AN_CNTL_1_ASM_PAUSE;
-       rc = hw->mac.ops.write_iosf_sb_reg(hw,
-                                          IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
-                                          IXGBE_SB_IOSF_TARGET_KR_PHY,
-                                          reg_val);
-
-       /* This device does not fully support AN. */
-       hw->fc.disable_fc_autoneg = true;
+       switch (hw->device_id) {
+       case IXGBE_DEV_ID_X550EM_X_KR:
+       case IXGBE_DEV_ID_X550EM_A_KR:
+       case IXGBE_DEV_ID_X550EM_A_KR_L:
+               rc = hw->mac.ops.read_iosf_sb_reg(hw,
+                                           IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
+                                           IXGBE_SB_IOSF_TARGET_KR_PHY,
+                                           &reg_val);
+               if (rc)
+                       return rc;
 
+               reg_val &= ~(IXGBE_KRM_AN_CNTL_1_SYM_PAUSE |
+                            IXGBE_KRM_AN_CNTL_1_ASM_PAUSE);
+               if (pause)
+                       reg_val |= IXGBE_KRM_AN_CNTL_1_SYM_PAUSE;
+               if (asm_dir)
+                       reg_val |= IXGBE_KRM_AN_CNTL_1_ASM_PAUSE;
+               rc = hw->mac.ops.write_iosf_sb_reg(hw,
+                                           IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
+                                           IXGBE_SB_IOSF_TARGET_KR_PHY,
+                                           reg_val);
+
+               /* This device does not fully support AN. */
+               hw->fc.disable_fc_autoneg = true;
+               break;
+       case IXGBE_DEV_ID_X550EM_X_XFI:
+               hw->fc.disable_fc_autoneg = true;
+               break;
+       default:
+               break;
+       }
        return rc;
 }
 
index 5794d98..9c94ea9 100644 (file)
@@ -2734,7 +2734,7 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
        ppd.shared = pdev;
 
        memset(&res, 0, sizeof(res));
-       if (!of_irq_to_resource(pnp, 0, &res)) {
+       if (of_irq_to_resource(pnp, 0, &res) <= 0) {
                dev_err(&pdev->dev, "missing interrupt on %s\n", pnp->name);
                return -EINVAL;
        }
index 698bb89..f9149d2 100644 (file)
@@ -7,11 +7,11 @@ config NET_VENDOR_MEDIATEK
 if NET_VENDOR_MEDIATEK
 
 config NET_MEDIATEK_SOC
-       tristate "MediaTek MT7623 Gigabit ethernet support"
-       depends on NET_VENDOR_MEDIATEK && (MACH_MT7623 || MACH_MT2701)
+       tristate "MediaTek SoC Gigabit Ethernet support"
+       depends on NET_VENDOR_MEDIATEK
        select PHYLIB
        ---help---
          This driver supports the gigabit ethernet MACs in the
-         MediaTek MT2701/MT7623 chipset family.
+         MediaTek SoC family.
 
 endif #NET_VENDOR_MEDIATEK
index 7e95cf5..acf2b3b 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/if_vlan.h>
 #include <linux/reset.h>
 #include <linux/tcp.h>
+#include <linux/interrupt.h>
 
 #include "mtk_eth_soc.h"
 
@@ -52,7 +53,8 @@ static const struct mtk_ethtool_stats {
 };
 
 static const char * const mtk_clks_source_name[] = {
-       "ethif", "esw", "gp1", "gp2", "trgpll"
+       "ethif", "esw", "gp0", "gp1", "gp2", "trgpll", "sgmii_tx250m",
+       "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", "sgmii_ck", "eth2pll"
 };
 
 void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
@@ -162,6 +164,47 @@ static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth, int speed)
        mtk_w32(eth, val, TRGMII_TCK_CTRL);
 }
 
+static void mtk_gmac_sgmii_hw_setup(struct mtk_eth *eth, int mac_id)
+{
+       u32 val;
+
+       /* Setup the link timer and QPHY power up inside SGMIISYS */
+       regmap_write(eth->sgmiisys, SGMSYS_PCS_LINK_TIMER,
+                    SGMII_LINK_TIMER_DEFAULT);
+
+       regmap_read(eth->sgmiisys, SGMSYS_SGMII_MODE, &val);
+       val |= SGMII_REMOTE_FAULT_DIS;
+       regmap_write(eth->sgmiisys, SGMSYS_SGMII_MODE, val);
+
+       regmap_read(eth->sgmiisys, SGMSYS_PCS_CONTROL_1, &val);
+       val |= SGMII_AN_RESTART;
+       regmap_write(eth->sgmiisys, SGMSYS_PCS_CONTROL_1, val);
+
+       regmap_read(eth->sgmiisys, SGMSYS_QPHY_PWR_STATE_CTRL, &val);
+       val &= ~SGMII_PHYA_PWD;
+       regmap_write(eth->sgmiisys, SGMSYS_QPHY_PWR_STATE_CTRL, val);
+
+       /* Determine MUX for which GMAC uses the SGMII interface */
+       if (MTK_HAS_CAPS(eth->soc->caps, MTK_DUAL_GMAC_SHARED_SGMII)) {
+               regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
+               val &= ~SYSCFG0_SGMII_MASK;
+               val |= !mac_id ? SYSCFG0_SGMII_GMAC1 : SYSCFG0_SGMII_GMAC2;
+               regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
+
+               dev_info(eth->dev, "setup shared sgmii for gmac=%d\n",
+                        mac_id);
+       }
+
+       /* Setup the GMAC1 going through SGMII path when SoC also support
+        * ESW on GMAC1
+        */
+       if (MTK_HAS_CAPS(eth->soc->caps, MTK_GMAC1_ESW | MTK_GMAC1_SGMII) &&
+           !mac_id) {
+               mtk_w32(eth, 0, MTK_MAC_MISC);
+               dev_info(eth->dev, "setup gmac1 going through sgmii");
+       }
+}
+
 static void mtk_phy_link_adjust(struct net_device *dev)
 {
        struct mtk_mac *mac = netdev_priv(dev);
@@ -184,7 +227,8 @@ static void mtk_phy_link_adjust(struct net_device *dev)
                break;
        };
 
-       if (mac->id == 0 && !mac->trgmii)
+       if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII) &&
+           !mac->id && !mac->trgmii)
                mtk_gmac0_rgmii_adjust(mac->hw, dev->phydev->speed);
 
        if (dev->phydev->link)
@@ -268,6 +312,7 @@ static int mtk_phy_connect(struct net_device *dev)
        if (!np)
                return -ENODEV;
 
+       mac->ge_mode = 0;
        switch (of_get_phy_mode(np)) {
        case PHY_INTERFACE_MODE_TRGMII:
                mac->trgmii = true;
@@ -275,7 +320,10 @@ static int mtk_phy_connect(struct net_device *dev)
        case PHY_INTERFACE_MODE_RGMII_RXID:
        case PHY_INTERFACE_MODE_RGMII_ID:
        case PHY_INTERFACE_MODE_RGMII:
-               mac->ge_mode = 0;
+               break;
+       case PHY_INTERFACE_MODE_SGMII:
+               if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII))
+                       mtk_gmac_sgmii_hw_setup(eth, mac->id);
                break;
        case PHY_INTERFACE_MODE_MII:
                mac->ge_mode = 1;
@@ -947,6 +995,10 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
                      RX_DMA_FPORT_MASK;
                mac--;
 
+               if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT ||
+                            !eth->netdev[mac]))
+                       goto release_desc;
+
                netdev = eth->netdev[mac];
 
                if (unlikely(test_bit(MTK_RESETTING, &eth->state)))
@@ -1829,9 +1881,36 @@ static void ethsys_reset(struct mtk_eth *eth, u32 reset_bits)
        mdelay(10);
 }
 
+static void mtk_clk_disable(struct mtk_eth *eth)
+{
+       int clk;
+
+       for (clk = MTK_CLK_MAX - 1; clk >= 0; clk--)
+               clk_disable_unprepare(eth->clks[clk]);
+}
+
+static int mtk_clk_enable(struct mtk_eth *eth)
+{
+       int clk, ret;
+
+       for (clk = 0; clk < MTK_CLK_MAX ; clk++) {
+               ret = clk_prepare_enable(eth->clks[clk]);
+               if (ret)
+                       goto err_disable_clks;
+       }
+
+       return 0;
+
+err_disable_clks:
+       while (--clk >= 0)
+               clk_disable_unprepare(eth->clks[clk]);
+
+       return ret;
+}
+
 static int mtk_hw_init(struct mtk_eth *eth)
 {
-       int i, val;
+       int i, val, ret;
 
        if (test_and_set_bit(MTK_HW_INIT, &eth->state))
                return 0;
@@ -1839,10 +1918,10 @@ static int mtk_hw_init(struct mtk_eth *eth)
        pm_runtime_enable(eth->dev);
        pm_runtime_get_sync(eth->dev);
 
-       clk_prepare_enable(eth->clks[MTK_CLK_ETHIF]);
-       clk_prepare_enable(eth->clks[MTK_CLK_ESW]);
-       clk_prepare_enable(eth->clks[MTK_CLK_GP1]);
-       clk_prepare_enable(eth->clks[MTK_CLK_GP2]);
+       ret = mtk_clk_enable(eth);
+       if (ret)
+               goto err_disable_pm;
+
        ethsys_reset(eth, RSTCTRL_FE);
        ethsys_reset(eth, RSTCTRL_PPE);
 
@@ -1910,6 +1989,12 @@ static int mtk_hw_init(struct mtk_eth *eth)
        }
 
        return 0;
+
+err_disable_pm:
+       pm_runtime_put_sync(eth->dev);
+       pm_runtime_disable(eth->dev);
+
+       return ret;
 }
 
 static int mtk_hw_deinit(struct mtk_eth *eth)
@@ -1917,10 +2002,7 @@ static int mtk_hw_deinit(struct mtk_eth *eth)
        if (!test_and_clear_bit(MTK_HW_INIT, &eth->state))
                return 0;
 
-       clk_disable_unprepare(eth->clks[MTK_CLK_GP2]);
-       clk_disable_unprepare(eth->clks[MTK_CLK_GP1]);
-       clk_disable_unprepare(eth->clks[MTK_CLK_ESW]);
-       clk_disable_unprepare(eth->clks[MTK_CLK_ETHIF]);
+       mtk_clk_disable(eth);
 
        pm_runtime_put_sync(eth->dev);
        pm_runtime_disable(eth->dev);
@@ -2387,6 +2469,7 @@ static int mtk_get_chip_id(struct mtk_eth *eth, u32 *chip_id)
 static bool mtk_is_hwlro_supported(struct mtk_eth *eth)
 {
        switch (eth->chip_id) {
+       case MT7622_ETH:
        case MT7623_ETH:
                return true;
        }
@@ -2398,6 +2481,7 @@ static int mtk_probe(struct platform_device *pdev)
 {
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct device_node *mac_np;
+       const struct of_device_id *match;
        struct mtk_eth *eth;
        int err;
        int i;
@@ -2406,6 +2490,9 @@ static int mtk_probe(struct platform_device *pdev)
        if (!eth)
                return -ENOMEM;
 
+       match = of_match_device(of_mtk_match, &pdev->dev);
+       eth->soc = (struct mtk_soc_data *)match->data;
+
        eth->dev = &pdev->dev;
        eth->base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(eth->base))
@@ -2422,6 +2509,16 @@ static int mtk_probe(struct platform_device *pdev)
                return PTR_ERR(eth->ethsys);
        }
 
+       if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
+               eth->sgmiisys =
+               syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                               "mediatek,sgmiisys");
+               if (IS_ERR(eth->sgmiisys)) {
+                       dev_err(&pdev->dev, "no sgmiisys regmap found\n");
+                       return PTR_ERR(eth->sgmiisys);
+               }
+       }
+
        eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
                                                    "mediatek,pctl");
        if (IS_ERR(eth->pctl)) {
@@ -2442,7 +2539,12 @@ static int mtk_probe(struct platform_device *pdev)
                if (IS_ERR(eth->clks[i])) {
                        if (PTR_ERR(eth->clks[i]) == -EPROBE_DEFER)
                                return -EPROBE_DEFER;
-                       return -ENODEV;
+                       if (eth->soc->required_clks & BIT(i)) {
+                               dev_err(&pdev->dev, "clock %s not found\n",
+                                       mtk_clks_source_name[i]);
+                               return -EINVAL;
+                       }
+                       eth->clks[i] = NULL;
                }
        }
 
@@ -2545,8 +2647,25 @@ static int mtk_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct mtk_soc_data mt2701_data = {
+       .caps = MTK_GMAC1_TRGMII,
+       .required_clks = MT7623_CLKS_BITMAP
+};
+
+static const struct mtk_soc_data mt7622_data = {
+       .caps = MTK_DUAL_GMAC_SHARED_SGMII | MTK_GMAC1_ESW,
+       .required_clks = MT7622_CLKS_BITMAP
+};
+
+static const struct mtk_soc_data mt7623_data = {
+       .caps = MTK_GMAC1_TRGMII,
+       .required_clks = MT7623_CLKS_BITMAP
+};
+
 const struct of_device_id of_mtk_match[] = {
-       { .compatible = "mediatek,mt2701-eth" },
+       { .compatible = "mediatek,mt2701-eth", .data = &mt2701_data},
+       { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data},
+       { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data},
        {},
 };
 MODULE_DEVICE_TABLE(of, of_mtk_match);
index 5868a09..4594862 100644 (file)
 #define PHY_IAC_REG_SHIFT      25
 #define PHY_IAC_TIMEOUT                HZ
 
+#define MTK_MAC_MISC           0x1000c
+#define MTK_MUX_TO_ESW         BIT(0)
+
 /* Mac control registers */
 #define MTK_MAC_MCR(x)         (0x10100 + (x * 0x100))
 #define MAC_MCR_MAX_RX_1536    BIT(24)
 #define ETHSYS_CHIPID0_3       0x0
 #define ETHSYS_CHIPID4_7       0x4
 #define MT7623_ETH             7623
+#define MT7622_ETH             7622
 
 /* ethernet subsystem config register */
 #define ETHSYS_SYSCFG0         0x14
 #define SYSCFG0_GE_MASK                0x3
 #define SYSCFG0_GE_MODE(x, y)  (x << (12 + (y * 2)))
+#define SYSCFG0_SGMII_MASK     (3 << 8)
+#define SYSCFG0_SGMII_GMAC1    ((2 << 8) & GENMASK(9, 8))
+#define SYSCFG0_SGMII_GMAC2    ((3 << 8) & GENMASK(9, 8))
 
 /* ethernet subsystem clock register */
 #define ETHSYS_CLKCFG0         0x2c
 #define RSTCTRL_FE             BIT(6)
 #define RSTCTRL_PPE            BIT(31)
 
+/* SGMII subsystem config registers */
+/* Register to auto-negotiation restart */
+#define SGMSYS_PCS_CONTROL_1   0x0
+#define SGMII_AN_RESTART       BIT(9)
+
+/* Register to programmable link timer, the unit in 2 * 8ns */
+#define SGMSYS_PCS_LINK_TIMER  0x18
+#define SGMII_LINK_TIMER_DEFAULT       (0x186a0 & GENMASK(19, 0))
+
+/* Register to control remote fault */
+#define SGMSYS_SGMII_MODE      0x20
+#define SGMII_REMOTE_FAULT_DIS BIT(8)
+
+/* Register to power up QPHY */
+#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8
+#define        SGMII_PHYA_PWD          BIT(4)
+
 struct mtk_rx_dma {
        unsigned int rxd1;
        unsigned int rxd2;
@@ -437,12 +461,31 @@ enum mtk_tx_flags {
 enum mtk_clks_map {
        MTK_CLK_ETHIF,
        MTK_CLK_ESW,
+       MTK_CLK_GP0,
        MTK_CLK_GP1,
        MTK_CLK_GP2,
        MTK_CLK_TRGPLL,
+       MTK_CLK_SGMII_TX_250M,
+       MTK_CLK_SGMII_RX_250M,
+       MTK_CLK_SGMII_CDR_REF,
+       MTK_CLK_SGMII_CDR_FB,
+       MTK_CLK_SGMII_CK,
+       MTK_CLK_ETH2PLL,
        MTK_CLK_MAX
 };
 
+#define MT7623_CLKS_BITMAP     (BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) |  \
+                                BIT(MTK_CLK_GP1) | BIT(MTK_CLK_GP2) | \
+                                BIT(MTK_CLK_TRGPLL))
+#define MT7622_CLKS_BITMAP     (BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) |  \
+                                BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \
+                                BIT(MTK_CLK_GP2) | \
+                                BIT(MTK_CLK_SGMII_TX_250M) | \
+                                BIT(MTK_CLK_SGMII_RX_250M) | \
+                                BIT(MTK_CLK_SGMII_CDR_REF) | \
+                                BIT(MTK_CLK_SGMII_CDR_FB) | \
+                                BIT(MTK_CLK_SGMII_CK) | \
+                                BIT(MTK_CLK_ETH2PLL))
 enum mtk_dev_state {
        MTK_HW_INIT,
        MTK_RESETTING
@@ -511,6 +554,28 @@ struct mtk_rx_ring {
        u32 crx_idx_reg;
 };
 
+#define MTK_TRGMII                     BIT(0)
+#define MTK_GMAC1_TRGMII               (BIT(1) | MTK_TRGMII)
+#define MTK_ESW                                BIT(4)
+#define MTK_GMAC1_ESW                  (BIT(5) | MTK_ESW)
+#define MTK_SGMII                      BIT(8)
+#define MTK_GMAC1_SGMII                        (BIT(9) | MTK_SGMII)
+#define MTK_GMAC2_SGMII                        (BIT(10) | MTK_SGMII)
+#define MTK_DUAL_GMAC_SHARED_SGMII     (BIT(11) | MTK_GMAC1_SGMII | \
+                                        MTK_GMAC2_SGMII)
+#define MTK_HAS_CAPS(caps, _x)         (((caps) & (_x)) == (_x))
+
+/* struct mtk_eth_data -       This is the structure holding all differences
+ *                             among various plaforms
+ * @caps                       Flags shown the extra capability for the SoC
+ * @required_clks              Flags shown the bitmap for required clocks on
+ *                             the target SoC
+ */
+struct mtk_soc_data {
+       u32             caps;
+       u32             required_clks;
+};
+
 /* currently no SoC has more than 2 macs */
 #define MTK_MAX_DEVS                   2
 
@@ -529,6 +594,8 @@ struct mtk_rx_ring {
  * @msg_enable:                Ethtool msg level
  * @ethsys:            The register map pointing at the range used to setup
  *                     MII modes
+ * @sgmiisys:          The register map pointing at the range used to setup
+ *                     SGMII modes
  * @pctl:              The register map pointing at the range used to setup
  *                     GMAC port drive/slew values
  * @dma_refcnt:                track how many netdevs are using the DMA engine
@@ -542,7 +609,8 @@ struct mtk_rx_ring {
  * @clks:              clock array for all clocks required
  * @mii_bus:           If there is a bus we need to create an instance for it
  * @pending_work:      The workqueue used to reset the dma ring
- * @state               Initialization and runtime state of the device.
+ * @state:             Initialization and runtime state of the device
+ * @soc:               Holding specific data among vaious SoCs
  */
 
 struct mtk_eth {
@@ -558,6 +626,7 @@ struct mtk_eth {
        u32                             msg_enable;
        unsigned long                   sysclk;
        struct regmap                   *ethsys;
+       struct regmap                   *sgmiisys;
        struct regmap                   *pctl;
        u32                             chip_id;
        bool                            hwlro;
@@ -574,6 +643,8 @@ struct mtk_eth {
        struct mii_bus                  *mii_bus;
        struct work_struct              pending_work;
        unsigned long                   state;
+
+       const struct mtk_soc_data       *soc;
 };
 
 /* struct mtk_mac -    the structure that holds the info about the MACs of the
index 249a458..b651c12 100644 (file)
@@ -283,7 +283,7 @@ int mlx4_zone_add_one(struct mlx4_zone_allocator *zone_alloc,
 }
 
 /* Should be called under a lock */
-static int __mlx4_zone_remove_one_entry(struct mlx4_zone_entry *entry)
+static void __mlx4_zone_remove_one_entry(struct mlx4_zone_entry *entry)
 {
        struct mlx4_zone_allocator *zone_alloc = entry->allocator;
 
@@ -315,8 +315,6 @@ static int __mlx4_zone_remove_one_entry(struct mlx4_zone_entry *entry)
                }
                zone_alloc->mask = mask;
        }
-
-       return 0;
 }
 
 void mlx4_zone_allocator_destroy(struct mlx4_zone_allocator *zone_alloc)
@@ -457,7 +455,7 @@ struct mlx4_bitmap *mlx4_zone_get_bitmap(struct mlx4_zone_allocator *zones, u32
 int mlx4_zone_remove_one(struct mlx4_zone_allocator *zones, u32 uid)
 {
        struct mlx4_zone_entry *zone;
-       int res;
+       int res = 0;
 
        spin_lock(&zones->lock);
 
@@ -468,7 +466,7 @@ int mlx4_zone_remove_one(struct mlx4_zone_allocator *zones, u32 uid)
                goto out;
        }
 
-       res = __mlx4_zone_remove_one_entry(zone);
+       __mlx4_zone_remove_one_entry(zone);
 
 out:
        spin_unlock(&zones->lock);
@@ -578,7 +576,7 @@ out:
 }
 
 static int mlx4_buf_direct_alloc(struct mlx4_dev *dev, int size,
-                                struct mlx4_buf *buf, gfp_t gfp)
+                                struct mlx4_buf *buf)
 {
        dma_addr_t t;
 
@@ -587,7 +585,7 @@ static int mlx4_buf_direct_alloc(struct mlx4_dev *dev, int size,
        buf->page_shift   = get_order(size) + PAGE_SHIFT;
        buf->direct.buf   =
                dma_zalloc_coherent(&dev->persist->pdev->dev,
-                                   size, &t, gfp);
+                                   size, &t, GFP_KERNEL);
        if (!buf->direct.buf)
                return -ENOMEM;
 
@@ -607,10 +605,10 @@ static int mlx4_buf_direct_alloc(struct mlx4_dev *dev, int size,
  *  multiple pages, so we don't require too much contiguous memory.
  */
 int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
-                  struct mlx4_buf *buf, gfp_t gfp)
+                  struct mlx4_buf *buf)
 {
        if (size <= max_direct) {
-               return mlx4_buf_direct_alloc(dev, size, buf, gfp);
+               return mlx4_buf_direct_alloc(dev, size, buf);
        } else {
                dma_addr_t t;
                int i;
@@ -620,14 +618,14 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
                buf->npages     = buf->nbufs;
                buf->page_shift  = PAGE_SHIFT;
                buf->page_list   = kcalloc(buf->nbufs, sizeof(*buf->page_list),
-                                          gfp);
+                                          GFP_KERNEL);
                if (!buf->page_list)
                        return -ENOMEM;
 
                for (i = 0; i < buf->nbufs; ++i) {
                        buf->page_list[i].buf =
                                dma_zalloc_coherent(&dev->persist->pdev->dev,
-                                                   PAGE_SIZE, &t, gfp);
+                                                   PAGE_SIZE, &t, GFP_KERNEL);
                        if (!buf->page_list[i].buf)
                                goto err_free;
 
@@ -663,12 +661,11 @@ void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf)
 }
 EXPORT_SYMBOL_GPL(mlx4_buf_free);
 
-static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device,
-                                                gfp_t gfp)
+static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device)
 {
        struct mlx4_db_pgdir *pgdir;
 
-       pgdir = kzalloc(sizeof *pgdir, gfp);
+       pgdir = kzalloc(sizeof(*pgdir), GFP_KERNEL);
        if (!pgdir)
                return NULL;
 
@@ -676,7 +673,7 @@ static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device,
        pgdir->bits[0] = pgdir->order0;
        pgdir->bits[1] = pgdir->order1;
        pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE,
-                                           &pgdir->db_dma, gfp);
+                                           &pgdir->db_dma, GFP_KERNEL);
        if (!pgdir->db_page) {
                kfree(pgdir);
                return NULL;
@@ -716,7 +713,7 @@ found:
        return 0;
 }
 
-int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order, gfp_t gfp)
+int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct mlx4_db_pgdir *pgdir;
@@ -728,7 +725,7 @@ int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order, gfp_t gfp
                if (!mlx4_alloc_db_from_pgdir(pgdir, db, order))
                        goto out;
 
-       pgdir = mlx4_alloc_db_pgdir(&dev->persist->pdev->dev, gfp);
+       pgdir = mlx4_alloc_db_pgdir(&dev->persist->pdev->dev);
        if (!pgdir) {
                ret = -ENOMEM;
                goto out;
@@ -780,13 +777,13 @@ int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
 {
        int err;
 
-       err = mlx4_db_alloc(dev, &wqres->db, 1, GFP_KERNEL);
+       err = mlx4_db_alloc(dev, &wqres->db, 1);
        if (err)
                return err;
 
        *wqres->db.db = 0;
 
-       err = mlx4_buf_direct_alloc(dev, size, &wqres->buf, GFP_KERNEL);
+       err = mlx4_buf_direct_alloc(dev, size, &wqres->buf);
        if (err)
                goto err_db;
 
@@ -795,7 +792,7 @@ int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
        if (err)
                goto err_buf;
 
-       err = mlx4_buf_write_mtt(dev, &wqres->mtt, &wqres->buf, GFP_KERNEL);
+       err = mlx4_buf_write_mtt(dev, &wqres->mtt, &wqres->buf);
        if (err)
                goto err_mtt;
 
index fa6d235..c56a511 100644 (file)
@@ -224,11 +224,11 @@ int __mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn)
        if (*cqn == -1)
                return -ENOMEM;
 
-       err = mlx4_table_get(dev, &cq_table->table, *cqn, GFP_KERNEL);
+       err = mlx4_table_get(dev, &cq_table->table, *cqn);
        if (err)
                goto err_out;
 
-       err = mlx4_table_get(dev, &cq_table->cmpt_table, *cqn, GFP_KERNEL);
+       err = mlx4_table_get(dev, &cq_table->cmpt_table, *cqn);
        if (err)
                goto err_put;
        return 0;
index 85fe17e..87d1f4d 100644 (file)
@@ -208,12 +208,10 @@ int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
                              cq->moder_cnt, cq->moder_time);
 }
 
-int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
+void mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
 {
        mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map,
                    &priv->mdev->uar_lock);
-
-       return 0;
 }
 
 
index 2b0cbca..686e18d 100644 (file)
@@ -147,7 +147,7 @@ void mlx4_en_update_loopback_state(struct net_device *dev,
        mutex_unlock(&priv->mdev->state_lock);
 }
 
-static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
+static void mlx4_en_get_profile(struct mlx4_en_dev *mdev)
 {
        struct mlx4_en_profile *params = &mdev->profile;
        int i;
@@ -176,8 +176,6 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
                params->prof[i].rss_rings = 0;
                params->prof[i].inline_thold = inline_thold;
        }
-
-       return 0;
 }
 
 static void *mlx4_en_get_netdev(struct mlx4_dev *dev, void *ctx, u8 port)
@@ -309,10 +307,7 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
        }
 
        /* Build device profile according to supplied module parameters */
-       if (mlx4_en_get_profile(mdev)) {
-               mlx4_err(mdev, "Bad module parameters, aborting\n");
-               goto err_mr;
-       }
+       mlx4_en_get_profile(mdev);
 
        /* Configure which ports to start according to module parameters */
        mdev->port_cnt = 0;
index e5fb895..436f768 100644 (file)
@@ -1042,7 +1042,7 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn,
        if (!context)
                return -ENOMEM;
 
-       err = mlx4_qp_alloc(mdev->dev, qpn, qp, GFP_KERNEL);
+       err = mlx4_qp_alloc(mdev->dev, qpn, qp);
        if (err) {
                en_err(priv, "Failed to allocate qp #%x\n", qpn);
                goto out;
@@ -1086,7 +1086,7 @@ int mlx4_en_create_drop_qp(struct mlx4_en_priv *priv)
                en_err(priv, "Failed reserving drop qpn\n");
                return err;
        }
-       err = mlx4_qp_alloc(priv->mdev->dev, qpn, &priv->drop_qp, GFP_KERNEL);
+       err = mlx4_qp_alloc(priv->mdev->dev, qpn, &priv->drop_qp);
        if (err) {
                en_err(priv, "Failed allocating drop qp\n");
                mlx4_qp_release_range(priv->mdev->dev, qpn, 1);
@@ -1158,8 +1158,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
        }
 
        /* Configure RSS indirection qp */
-       err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, rss_map->indir_qp,
-                           GFP_KERNEL);
+       err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, rss_map->indir_qp);
        if (err) {
                en_err(priv, "Failed to allocate RSS indirection QP\n");
                goto rss_err;
index 4f3a9b2..73faa3d 100644 (file)
@@ -111,7 +111,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
                goto err_hwq_res;
        }
 
-       err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->sp_qp, GFP_KERNEL);
+       err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->sp_qp);
        if (err) {
                en_err(priv, "Failed allocating qp %d\n", ring->qpn);
                goto err_reserve;
index e1f9e7c..5a7816e 100644 (file)
@@ -251,8 +251,7 @@ int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev)
                        MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
 }
 
-int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj,
-                  gfp_t gfp)
+int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj)
 {
        u32 i = (obj & (table->num_obj - 1)) /
                        (MLX4_TABLE_CHUNK_SIZE / table->obj_size);
@@ -266,7 +265,7 @@ int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj,
        }
 
        table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
-                                      (table->lowmem ? gfp : GFP_HIGHUSER) |
+                                      (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
                                       __GFP_NOWARN, table->coherent);
        if (!table->icm[i]) {
                ret = -ENOMEM;
@@ -363,7 +362,7 @@ int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
        u32 i;
 
        for (i = start; i <= end; i += inc) {
-               err = mlx4_table_get(dev, table, i, GFP_KERNEL);
+               err = mlx4_table_get(dev, table, i);
                if (err)
                        goto fail;
        }
index 0c73645..dee67fa 100644 (file)
@@ -71,8 +71,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
                                gfp_t gfp_mask, int coherent);
 void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent);
 
-int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj,
-                  gfp_t gfp);
+int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj);
 void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj);
 int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
                         u32 start, u32 end);
index 30616cd..706d7f2 100644 (file)
@@ -969,7 +969,7 @@ void mlx4_cleanup_cq_table(struct mlx4_dev *dev);
 void mlx4_cleanup_qp_table(struct mlx4_dev *dev);
 void mlx4_cleanup_srq_table(struct mlx4_dev *dev);
 void mlx4_cleanup_mcg_table(struct mlx4_dev *dev);
-int __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn, gfp_t gfp);
+int __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn);
 void __mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn);
 int __mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn);
 void __mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn);
@@ -977,7 +977,7 @@ int __mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn);
 void __mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn);
 int __mlx4_mpt_reserve(struct mlx4_dev *dev);
 void __mlx4_mpt_release(struct mlx4_dev *dev, u32 index);
-int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index, gfp_t gfp);
+int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index);
 void __mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index);
 u32 __mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order);
 void __mlx4_free_mtt_range(struct mlx4_dev *dev, u32 first_seg, int order);
index d350b21..fdb3ad0 100644 (file)
@@ -685,7 +685,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
                        int cq_idx);
 void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
 int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
-int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
+void mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
 
 void mlx4_en_tx_irq(struct mlx4_cq *mcq);
 u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
index ce852ca..24282cd 100644 (file)
@@ -479,14 +479,14 @@ static void mlx4_mpt_release(struct mlx4_dev *dev, u32 index)
        __mlx4_mpt_release(dev, index);
 }
 
-int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index, gfp_t gfp)
+int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index)
 {
        struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
 
-       return mlx4_table_get(dev, &mr_table->dmpt_table, index, gfp);
+       return mlx4_table_get(dev, &mr_table->dmpt_table, index);
 }
 
-static int mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index, gfp_t gfp)
+static int mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index)
 {
        u64 param = 0;
 
@@ -497,7 +497,7 @@ static int mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index, gfp_t gfp)
                                                        MLX4_CMD_TIME_CLASS_A,
                                                        MLX4_CMD_WRAPPED);
        }
-       return __mlx4_mpt_alloc_icm(dev, index, gfp);
+       return __mlx4_mpt_alloc_icm(dev, index);
 }
 
 void __mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index)
@@ -629,7 +629,7 @@ int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr)
        struct mlx4_mpt_entry *mpt_entry;
        int err;
 
-       err = mlx4_mpt_alloc_icm(dev, key_to_hw_index(mr->key), GFP_KERNEL);
+       err = mlx4_mpt_alloc_icm(dev, key_to_hw_index(mr->key));
        if (err)
                return err;
 
@@ -787,14 +787,13 @@ int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
 EXPORT_SYMBOL_GPL(mlx4_write_mtt);
 
 int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
-                      struct mlx4_buf *buf, gfp_t gfp)
+                      struct mlx4_buf *buf)
 {
        u64 *page_list;
        int err;
        int i;
 
-       page_list = kmalloc(buf->npages * sizeof *page_list,
-                           gfp);
+       page_list = kcalloc(buf->npages, sizeof(*page_list), GFP_KERNEL);
        if (!page_list)
                return -ENOMEM;
 
@@ -841,7 +840,7 @@ int mlx4_mw_enable(struct mlx4_dev *dev, struct mlx4_mw *mw)
        struct mlx4_mpt_entry *mpt_entry;
        int err;
 
-       err = mlx4_mpt_alloc_icm(dev, key_to_hw_index(mw->key), GFP_KERNEL);
+       err = mlx4_mpt_alloc_icm(dev, key_to_hw_index(mw->key));
        if (err)
                return err;
 
index 5a310d3..2674721 100644 (file)
@@ -301,29 +301,29 @@ void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt)
 }
 EXPORT_SYMBOL_GPL(mlx4_qp_release_range);
 
-int __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn, gfp_t gfp)
+int __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct mlx4_qp_table *qp_table = &priv->qp_table;
        int err;
 
-       err = mlx4_table_get(dev, &qp_table->qp_table, qpn, gfp);
+       err = mlx4_table_get(dev, &qp_table->qp_table, qpn);
        if (err)
                goto err_out;
 
-       err = mlx4_table_get(dev, &qp_table->auxc_table, qpn, gfp);
+       err = mlx4_table_get(dev, &qp_table->auxc_table, qpn);
        if (err)
                goto err_put_qp;
 
-       err = mlx4_table_get(dev, &qp_table->altc_table, qpn, gfp);
+       err = mlx4_table_get(dev, &qp_table->altc_table, qpn);
        if (err)
                goto err_put_auxc;
 
-       err = mlx4_table_get(dev, &qp_table->rdmarc_table, qpn, gfp);
+       err = mlx4_table_get(dev, &qp_table->rdmarc_table, qpn);
        if (err)
                goto err_put_altc;
 
-       err = mlx4_table_get(dev, &qp_table->cmpt_table, qpn, gfp);
+       err = mlx4_table_get(dev, &qp_table->cmpt_table, qpn);
        if (err)
                goto err_put_rdmarc;
 
@@ -345,7 +345,7 @@ err_out:
        return err;
 }
 
-static int mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn, gfp_t gfp)
+static int mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn)
 {
        u64 param = 0;
 
@@ -355,7 +355,7 @@ static int mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn, gfp_t gfp)
                                    MLX4_CMD_ALLOC_RES, MLX4_CMD_TIME_CLASS_A,
                                    MLX4_CMD_WRAPPED);
        }
-       return __mlx4_qp_alloc_icm(dev, qpn, gfp);
+       return __mlx4_qp_alloc_icm(dev, qpn);
 }
 
 void __mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn)
@@ -397,7 +397,7 @@ struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn)
        return qp;
 }
 
-int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp, gfp_t gfp)
+int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct mlx4_qp_table *qp_table = &priv->qp_table;
@@ -408,7 +408,7 @@ int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp, gfp_t gfp)
 
        qp->qpn = qpn;
 
-       err = mlx4_qp_alloc_icm(dev, qpn, gfp);
+       err = mlx4_qp_alloc_icm(dev, qpn);
        if (err)
                return err;
 
index 8127838..215e21c 100644 (file)
@@ -1822,7 +1822,7 @@ static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
                        return err;
 
                if (!fw_reserved(dev, qpn)) {
-                       err = __mlx4_qp_alloc_icm(dev, qpn, GFP_KERNEL);
+                       err = __mlx4_qp_alloc_icm(dev, qpn);
                        if (err) {
                                res_abort_move(dev, slave, RES_QP, qpn);
                                return err;
@@ -1909,7 +1909,7 @@ static int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
                if (err)
                        return err;
 
-               err = __mlx4_mpt_alloc_icm(dev, mpt->key, GFP_KERNEL);
+               err = __mlx4_mpt_alloc_icm(dev, mpt->key);
                if (err) {
                        res_abort_move(dev, slave, RES_MPT, id);
                        return err;
index f44d089..bedf521 100644 (file)
@@ -100,11 +100,11 @@ int __mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn)
        if (*srqn == -1)
                return -ENOMEM;
 
-       err = mlx4_table_get(dev, &srq_table->table, *srqn, GFP_KERNEL);
+       err = mlx4_table_get(dev, &srq_table->table, *srqn);
        if (err)
                goto err_out;
 
-       err = mlx4_table_get(dev, &srq_table->cmpt_table, *srqn, GFP_KERNEL);
+       err = mlx4_table_get(dev, &srq_table->cmpt_table, *srqn);
        if (err)
                goto err_put;
        return 0;
index f5a2c60..31cbe5e 100644 (file)
@@ -786,6 +786,10 @@ static void cb_timeout_handler(struct work_struct *work)
        mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
 }
 
+static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg);
+static void mlx5_free_cmd_msg(struct mlx5_core_dev *dev,
+                             struct mlx5_cmd_msg *msg);
+
 static void cmd_work_handler(struct work_struct *work)
 {
        struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work);
@@ -796,17 +800,28 @@ static void cmd_work_handler(struct work_struct *work)
        struct semaphore *sem;
        unsigned long flags;
        bool poll_cmd = ent->polling;
+       int alloc_ret;
 
 
        sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
        down(sem);
        if (!ent->page_queue) {
-               ent->idx = alloc_ent(cmd);
-               if (ent->idx < 0) {
+               alloc_ret = alloc_ent(cmd);
+               if (alloc_ret < 0) {
                        mlx5_core_err(dev, "failed to allocate command entry\n");
+                       if (ent->callback) {
+                               ent->callback(-EAGAIN, ent->context);
+                               mlx5_free_cmd_msg(dev, ent->out);
+                               free_msg(dev, ent->in);
+                               free_cmd(ent);
+                       } else {
+                               ent->ret = -EAGAIN;
+                               complete(&ent->done);
+                       }
                        up(sem);
                        return;
                }
+               ent->idx = alloc_ret;
        } else {
                ent->idx = cmd->max_reg_cmds;
                spin_lock_irqsave(&cmd->alloc_lock, flags);
@@ -967,7 +982,7 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
 
        err = wait_func(dev, ent);
        if (err == -ETIMEDOUT)
-               goto out_free;
+               goto out;
 
        ds = ent->ts2 - ent->ts1;
        op = MLX5_GET(mbox_in, in->first.data, opcode);
@@ -1430,6 +1445,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced)
                                        mlx5_core_err(dev, "Command completion arrived after timeout (entry idx = %d).\n",
                                                      ent->idx);
                                        free_ent(cmd, ent->idx);
+                                       free_cmd(ent);
                                }
                                continue;
                        }
@@ -1488,7 +1504,8 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced)
                                free_msg(dev, ent->in);
 
                                err = err ? err : ent->status;
-                               free_cmd(ent);
+                               if (!forced)
+                                       free_cmd(ent);
                                callback(err, context);
                        } else {
                                complete(&ent->done);
index e1b7ddf..0039b47 100644 (file)
@@ -266,6 +266,14 @@ struct mlx5e_dcbx {
 };
 #endif
 
+#define MAX_PIN_NUM    8
+struct mlx5e_pps {
+       u8                         pin_caps[MAX_PIN_NUM];
+       struct work_struct         out_work;
+       u64                        start[MAX_PIN_NUM];
+       u8                         enabled;
+};
+
 struct mlx5e_tstamp {
        rwlock_t                   lock;
        struct cyclecounter        cycles;
@@ -277,7 +285,7 @@ struct mlx5e_tstamp {
        struct mlx5_core_dev      *mdev;
        struct ptp_clock          *ptp;
        struct ptp_clock_info      ptp_info;
-       u8                        *pps_pin_caps;
+       struct mlx5e_pps           pps_info;
 };
 
 enum {
index 66f4323..84dd63e 100644 (file)
@@ -53,6 +53,15 @@ enum {
        MLX5E_EVENT_MODE_ONCE_TILL_ARM  = 0x2,
 };
 
+enum {
+       MLX5E_MTPPS_FS_ENABLE                   = BIT(0x0),
+       MLX5E_MTPPS_FS_PATTERN                  = BIT(0x2),
+       MLX5E_MTPPS_FS_PIN_MODE                 = BIT(0x3),
+       MLX5E_MTPPS_FS_TIME_STAMP               = BIT(0x4),
+       MLX5E_MTPPS_FS_OUT_PULSE_DURATION       = BIT(0x5),
+       MLX5E_MTPPS_FS_ENH_OUT_PER_ADJ          = BIT(0x7),
+};
+
 void mlx5e_fill_hwstamp(struct mlx5e_tstamp *tstamp, u64 timestamp,
                        struct skb_shared_hwtstamps *hwts)
 {
@@ -73,17 +82,46 @@ static u64 mlx5e_read_internal_timer(const struct cyclecounter *cc)
        return mlx5_read_internal_timer(tstamp->mdev) & cc->mask;
 }
 
+static void mlx5e_pps_out(struct work_struct *work)
+{
+       struct mlx5e_pps *pps_info = container_of(work, struct mlx5e_pps,
+                                                 out_work);
+       struct mlx5e_tstamp *tstamp = container_of(pps_info, struct mlx5e_tstamp,
+                                                  pps_info);
+       u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
+       unsigned long flags;
+       int i;
+
+       for (i = 0; i < tstamp->ptp_info.n_pins; i++) {
+               u64 tstart;
+
+               write_lock_irqsave(&tstamp->lock, flags);
+               tstart = tstamp->pps_info.start[i];
+               tstamp->pps_info.start[i] = 0;
+               write_unlock_irqrestore(&tstamp->lock, flags);
+               if (!tstart)
+                       continue;
+
+               MLX5_SET(mtpps_reg, in, pin, i);
+               MLX5_SET64(mtpps_reg, in, time_stamp, tstart);
+               MLX5_SET(mtpps_reg, in, field_select, MLX5E_MTPPS_FS_TIME_STAMP);
+               mlx5_set_mtpps(tstamp->mdev, in, sizeof(in));
+       }
+}
+
 static void mlx5e_timestamp_overflow(struct work_struct *work)
 {
        struct delayed_work *dwork = to_delayed_work(work);
        struct mlx5e_tstamp *tstamp = container_of(dwork, struct mlx5e_tstamp,
                                                   overflow_work);
+       struct mlx5e_priv *priv = container_of(tstamp, struct mlx5e_priv, tstamp);
        unsigned long flags;
 
        write_lock_irqsave(&tstamp->lock, flags);
        timecounter_read(&tstamp->clock);
        write_unlock_irqrestore(&tstamp->lock, flags);
-       schedule_delayed_work(&tstamp->overflow_work, tstamp->overflow_period);
+       queue_delayed_work(priv->wq, &tstamp->overflow_work,
+                          msecs_to_jiffies(tstamp->overflow_period * 1000));
 }
 
 int mlx5e_hwstamp_set(struct mlx5e_priv *priv, struct ifreq *ifr)
@@ -213,18 +251,6 @@ static int mlx5e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
        int neg_adj = 0;
        struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
                                                  ptp_info);
-       struct mlx5e_priv *priv =
-               container_of(tstamp, struct mlx5e_priv, tstamp);
-
-       if (MLX5_CAP_GEN(priv->mdev, pps_modify)) {
-               u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
-
-               /* For future use need to add a loop for finding all 1PPS out pins */
-               MLX5_SET(mtpps_reg, in, pin_mode, MLX5E_PIN_MODE_OUT);
-               MLX5_SET(mtpps_reg, in, out_periodic_adjustment, delta & 0xFFFF);
-
-               mlx5_set_mtpps(priv->mdev, in, sizeof(in));
-       }
 
        if (delta < 0) {
                neg_adj = 1;
@@ -253,12 +279,13 @@ static int mlx5e_extts_configure(struct ptp_clock_info *ptp,
        struct mlx5e_priv *priv =
                container_of(tstamp, struct mlx5e_priv, tstamp);
        u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
+       u32 field_select = 0;
+       u8 pin_mode = 0;
        u8 pattern = 0;
        int pin = -1;
        int err = 0;
 
-       if (!MLX5_CAP_GEN(priv->mdev, pps) ||
-           !MLX5_CAP_GEN(priv->mdev, pps_modify))
+       if (!MLX5_PPS_CAP(priv->mdev))
                return -EOPNOTSUPP;
 
        if (rq->extts.index >= tstamp->ptp_info.n_pins)
@@ -268,15 +295,21 @@ static int mlx5e_extts_configure(struct ptp_clock_info *ptp,
                pin = ptp_find_pin(tstamp->ptp, PTP_PF_EXTTS, rq->extts.index);
                if (pin < 0)
                        return -EBUSY;
+               pin_mode = MLX5E_PIN_MODE_IN;
+               pattern = !!(rq->extts.flags & PTP_FALLING_EDGE);
+               field_select = MLX5E_MTPPS_FS_PIN_MODE |
+                              MLX5E_MTPPS_FS_PATTERN |
+                              MLX5E_MTPPS_FS_ENABLE;
+       } else {
+               pin = rq->extts.index;
+               field_select = MLX5E_MTPPS_FS_ENABLE;
        }
 
-       if (rq->extts.flags & PTP_FALLING_EDGE)
-               pattern = 1;
-
        MLX5_SET(mtpps_reg, in, pin, pin);
-       MLX5_SET(mtpps_reg, in, pin_mode, MLX5E_PIN_MODE_IN);
+       MLX5_SET(mtpps_reg, in, pin_mode, pin_mode);
        MLX5_SET(mtpps_reg, in, pattern, pattern);
        MLX5_SET(mtpps_reg, in, enable, on);
+       MLX5_SET(mtpps_reg, in, field_select, field_select);
 
        err = mlx5_set_mtpps(priv->mdev, in, sizeof(in));
        if (err)
@@ -295,14 +328,18 @@ static int mlx5e_perout_configure(struct ptp_clock_info *ptp,
        struct mlx5e_priv *priv =
                container_of(tstamp, struct mlx5e_priv, tstamp);
        u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
-       u64 nsec_now, nsec_delta, time_stamp;
+       u64 nsec_now, nsec_delta, time_stamp = 0;
        u64 cycles_now, cycles_delta;
        struct timespec64 ts;
        unsigned long flags;
+       u32 field_select = 0;
+       u8 pin_mode = 0;
+       u8 pattern = 0;
        int pin = -1;
+       int err = 0;
        s64 ns;
 
-       if (!MLX5_CAP_GEN(priv->mdev, pps_modify))
+       if (!MLX5_PPS_CAP(priv->mdev))
                return -EOPNOTSUPP;
 
        if (rq->perout.index >= tstamp->ptp_info.n_pins)
@@ -313,32 +350,60 @@ static int mlx5e_perout_configure(struct ptp_clock_info *ptp,
                                   rq->perout.index);
                if (pin < 0)
                        return -EBUSY;
-       }
 
-       ts.tv_sec = rq->perout.period.sec;
-       ts.tv_nsec = rq->perout.period.nsec;
-       ns = timespec64_to_ns(&ts);
-       if (on)
+               pin_mode = MLX5E_PIN_MODE_OUT;
+               pattern = MLX5E_OUT_PATTERN_PERIODIC;
+               ts.tv_sec = rq->perout.period.sec;
+               ts.tv_nsec = rq->perout.period.nsec;
+               ns = timespec64_to_ns(&ts);
+
                if ((ns >> 1) != 500000000LL)
                        return -EINVAL;
-       ts.tv_sec = rq->perout.start.sec;
-       ts.tv_nsec = rq->perout.start.nsec;
-       ns = timespec64_to_ns(&ts);
-       cycles_now = mlx5_read_internal_timer(tstamp->mdev);
-       write_lock_irqsave(&tstamp->lock, flags);
-       nsec_now = timecounter_cyc2time(&tstamp->clock, cycles_now);
-       nsec_delta = ns - nsec_now;
-       cycles_delta = div64_u64(nsec_delta << tstamp->cycles.shift,
-                                tstamp->cycles.mult);
-       write_unlock_irqrestore(&tstamp->lock, flags);
-       time_stamp = cycles_now + cycles_delta;
+
+               ts.tv_sec = rq->perout.start.sec;
+               ts.tv_nsec = rq->perout.start.nsec;
+               ns = timespec64_to_ns(&ts);
+               cycles_now = mlx5_read_internal_timer(tstamp->mdev);
+               write_lock_irqsave(&tstamp->lock, flags);
+               nsec_now = timecounter_cyc2time(&tstamp->clock, cycles_now);
+               nsec_delta = ns - nsec_now;
+               cycles_delta = div64_u64(nsec_delta << tstamp->cycles.shift,
+                                        tstamp->cycles.mult);
+               write_unlock_irqrestore(&tstamp->lock, flags);
+               time_stamp = cycles_now + cycles_delta;
+               field_select = MLX5E_MTPPS_FS_PIN_MODE |
+                              MLX5E_MTPPS_FS_PATTERN |
+                              MLX5E_MTPPS_FS_ENABLE |
+                              MLX5E_MTPPS_FS_TIME_STAMP;
+       } else {
+               pin = rq->perout.index;
+               field_select = MLX5E_MTPPS_FS_ENABLE;
+       }
+
        MLX5_SET(mtpps_reg, in, pin, pin);
-       MLX5_SET(mtpps_reg, in, pin_mode, MLX5E_PIN_MODE_OUT);
-       MLX5_SET(mtpps_reg, in, pattern, MLX5E_OUT_PATTERN_PERIODIC);
+       MLX5_SET(mtpps_reg, in, pin_mode, pin_mode);
+       MLX5_SET(mtpps_reg, in, pattern, pattern);
        MLX5_SET(mtpps_reg, in, enable, on);
        MLX5_SET64(mtpps_reg, in, time_stamp, time_stamp);
+       MLX5_SET(mtpps_reg, in, field_select, field_select);
+
+       err = mlx5_set_mtpps(priv->mdev, in, sizeof(in));
+       if (err)
+               return err;
 
-       return mlx5_set_mtpps(priv->mdev, in, sizeof(in));
+       return mlx5_set_mtppse(priv->mdev, pin, 0,
+                              MLX5E_EVENT_MODE_REPETETIVE & on);
+}
+
+static int mlx5e_pps_configure(struct ptp_clock_info *ptp,
+                              struct ptp_clock_request *rq,
+                              int on)
+{
+       struct mlx5e_tstamp *tstamp =
+               container_of(ptp, struct mlx5e_tstamp, ptp_info);
+
+       tstamp->pps_info.enabled = !!on;
+       return 0;
 }
 
 static int mlx5e_ptp_enable(struct ptp_clock_info *ptp,
@@ -350,6 +415,8 @@ static int mlx5e_ptp_enable(struct ptp_clock_info *ptp,
                return mlx5e_extts_configure(ptp, rq, on);
        case PTP_CLK_REQ_PEROUT:
                return mlx5e_perout_configure(ptp, rq, on);
+       case PTP_CLK_REQ_PPS:
+               return mlx5e_pps_configure(ptp, rq, on);
        default:
                return -EOPNOTSUPP;
        }
@@ -395,6 +462,7 @@ static int mlx5e_init_pin_config(struct mlx5e_tstamp *tstamp)
                return -ENOMEM;
        tstamp->ptp_info.enable = mlx5e_ptp_enable;
        tstamp->ptp_info.verify = mlx5e_ptp_verify;
+       tstamp->ptp_info.pps = 1;
 
        for (i = 0; i < tstamp->ptp_info.n_pins; i++) {
                snprintf(tstamp->ptp_info.pin_config[i].name,
@@ -422,22 +490,56 @@ static void mlx5e_get_pps_caps(struct mlx5e_priv *priv,
        tstamp->ptp_info.n_per_out = MLX5_GET(mtpps_reg, out,
                                              cap_max_num_of_pps_out_pins);
 
-       tstamp->pps_pin_caps[0] = MLX5_GET(mtpps_reg, out, cap_pin_0_mode);
-       tstamp->pps_pin_caps[1] = MLX5_GET(mtpps_reg, out, cap_pin_1_mode);
-       tstamp->pps_pin_caps[2] = MLX5_GET(mtpps_reg, out, cap_pin_2_mode);
-       tstamp->pps_pin_caps[3] = MLX5_GET(mtpps_reg, out, cap_pin_3_mode);
-       tstamp->pps_pin_caps[4] = MLX5_GET(mtpps_reg, out, cap_pin_4_mode);
-       tstamp->pps_pin_caps[5] = MLX5_GET(mtpps_reg, out, cap_pin_5_mode);
-       tstamp->pps_pin_caps[6] = MLX5_GET(mtpps_reg, out, cap_pin_6_mode);
-       tstamp->pps_pin_caps[7] = MLX5_GET(mtpps_reg, out, cap_pin_7_mode);
+       tstamp->pps_info.pin_caps[0] = MLX5_GET(mtpps_reg, out, cap_pin_0_mode);
+       tstamp->pps_info.pin_caps[1] = MLX5_GET(mtpps_reg, out, cap_pin_1_mode);
+       tstamp->pps_info.pin_caps[2] = MLX5_GET(mtpps_reg, out, cap_pin_2_mode);
+       tstamp->pps_info.pin_caps[3] = MLX5_GET(mtpps_reg, out, cap_pin_3_mode);
+       tstamp->pps_info.pin_caps[4] = MLX5_GET(mtpps_reg, out, cap_pin_4_mode);
+       tstamp->pps_info.pin_caps[5] = MLX5_GET(mtpps_reg, out, cap_pin_5_mode);
+       tstamp->pps_info.pin_caps[6] = MLX5_GET(mtpps_reg, out, cap_pin_6_mode);
+       tstamp->pps_info.pin_caps[7] = MLX5_GET(mtpps_reg, out, cap_pin_7_mode);
 }
 
 void mlx5e_pps_event_handler(struct mlx5e_priv *priv,
                             struct ptp_clock_event *event)
 {
+       struct net_device *netdev = priv->netdev;
        struct mlx5e_tstamp *tstamp = &priv->tstamp;
+       struct timespec64 ts;
+       u64 nsec_now, nsec_delta;
+       u64 cycles_now, cycles_delta;
+       int pin = event->index;
+       s64 ns;
+       unsigned long flags;
 
-       ptp_clock_event(tstamp->ptp, event);
+       switch (tstamp->ptp_info.pin_config[pin].func) {
+       case PTP_PF_EXTTS:
+               if (tstamp->pps_info.enabled) {
+                       event->type = PTP_CLOCK_PPSUSR;
+                       event->pps_times.ts_real = ns_to_timespec64(event->timestamp);
+               } else {
+                       event->type = PTP_CLOCK_EXTTS;
+               }
+               ptp_clock_event(tstamp->ptp, event);
+               break;
+       case PTP_PF_PEROUT:
+               mlx5e_ptp_gettime(&tstamp->ptp_info, &ts);
+               cycles_now = mlx5_read_internal_timer(tstamp->mdev);
+               ts.tv_sec += 1;
+               ts.tv_nsec = 0;
+               ns = timespec64_to_ns(&ts);
+               write_lock_irqsave(&tstamp->lock, flags);
+               nsec_now = timecounter_cyc2time(&tstamp->clock, cycles_now);
+               nsec_delta = ns - nsec_now;
+               cycles_delta = div64_u64(nsec_delta << tstamp->cycles.shift,
+                                        tstamp->cycles.mult);
+               tstamp->pps_info.start[pin] = cycles_now + cycles_delta;
+               queue_work(priv->wq, &tstamp->pps_info.out_work);
+               write_unlock_irqrestore(&tstamp->lock, flags);
+               break;
+       default:
+               netdev_err(netdev, "%s: Unhandled event\n", __func__);
+       }
 }
 
 void mlx5e_timestamp_init(struct mlx5e_priv *priv)
@@ -473,9 +575,10 @@ void mlx5e_timestamp_init(struct mlx5e_priv *priv)
        do_div(ns, NSEC_PER_SEC / 2 / HZ);
        tstamp->overflow_period = ns;
 
+       INIT_WORK(&tstamp->pps_info.out_work, mlx5e_pps_out);
        INIT_DELAYED_WORK(&tstamp->overflow_work, mlx5e_timestamp_overflow);
        if (tstamp->overflow_period)
-               schedule_delayed_work(&tstamp->overflow_work, 0);
+               queue_delayed_work(priv->wq, &tstamp->overflow_work, 0);
        else
                mlx5_core_warn(priv->mdev, "invalid overflow period, overflow_work is not scheduled\n");
 
@@ -484,16 +587,10 @@ void mlx5e_timestamp_init(struct mlx5e_priv *priv)
        snprintf(tstamp->ptp_info.name, 16, "mlx5 ptp");
 
        /* Initialize 1PPS data structures */
-#define MAX_PIN_NUM    8
-       tstamp->pps_pin_caps = kzalloc(sizeof(u8) * MAX_PIN_NUM, GFP_KERNEL);
-       if (tstamp->pps_pin_caps) {
-               if (MLX5_CAP_GEN(priv->mdev, pps))
-                       mlx5e_get_pps_caps(priv, tstamp);
-               if (tstamp->ptp_info.n_pins)
-                       mlx5e_init_pin_config(tstamp);
-       } else {
-               mlx5_core_warn(priv->mdev, "1PPS initialization failed\n");
-       }
+       if (MLX5_PPS_CAP(priv->mdev))
+               mlx5e_get_pps_caps(priv, tstamp);
+       if (tstamp->ptp_info.n_pins)
+               mlx5e_init_pin_config(tstamp);
 
        tstamp->ptp = ptp_clock_register(&tstamp->ptp_info,
                                         &priv->mdev->pdev->dev);
@@ -516,8 +613,7 @@ void mlx5e_timestamp_cleanup(struct mlx5e_priv *priv)
                priv->tstamp.ptp = NULL;
        }
 
-       kfree(tstamp->pps_pin_caps);
-       kfree(tstamp->ptp_info.pin_config);
-
+       cancel_work_sync(&tstamp->pps_info.out_work);
        cancel_delayed_work_sync(&tstamp->overflow_work);
+       kfree(tstamp->ptp_info.pin_config);
 }
index bdd82c9..eafc592 100644 (file)
@@ -276,7 +276,7 @@ static void add_rule_to_list(struct mlx5e_priv *priv,
 
 static bool outer_header_zero(u32 *match_criteria)
 {
-       int size = MLX5_ST_SZ_BYTES(fte_match_param);
+       int size = MLX5_FLD_SZ_BYTES(fte_match_param, outer_headers);
        char *outer_headers_c = MLX5_ADDR_OF(fte_match_param, match_criteria,
                                             outer_headers);
 
@@ -320,7 +320,7 @@ add_ethtool_flow_rule(struct mlx5e_priv *priv,
 
        spec->match_criteria_enable = (!outer_header_zero(spec->match_criteria));
        flow_act.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
-       rule = mlx5_add_flow_rules(ft, spec, &flow_act, dst, 1);
+       rule = mlx5_add_flow_rules(ft, spec, &flow_act, dst, dst ? 1 : 0);
        if (IS_ERR(rule)) {
                err = PTR_ERR(rule);
                netdev_err(priv->netdev, "%s: failed to add ethtool steering rule: %d\n",
index 1eac500..57f31fa 100644 (file)
@@ -377,7 +377,6 @@ static void mlx5e_async_event(struct mlx5_core_dev *mdev, void *vpriv,
                break;
        case MLX5_DEV_EVENT_PPS:
                eqe = (struct mlx5_eqe *)param;
-               ptp_event.type = PTP_CLOCK_EXTTS;
                ptp_event.index = eqe->data.pps.pin;
                ptp_event.timestamp =
                        timecounter_cyc2time(&priv->tstamp.clock,
index af51a5d..52b9a64 100644 (file)
@@ -698,7 +698,7 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev)
        else
                mlx5_core_dbg(dev, "port_module_event is not set\n");
 
-       if (MLX5_CAP_GEN(dev, pps))
+       if (MLX5_PPS_CAP(dev))
                async_event_mask |= (1ull << MLX5_EVENT_TYPE_PPS_EVENT);
 
        if (MLX5_CAP_GEN(dev, fpga))
index 89bfda4..8b18cc9 100644 (file)
@@ -1668,7 +1668,8 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
        int i;
 
        if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
-           MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
+           MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH ||
+           esw->mode == SRIOV_NONE)
                return;
 
        esw_info(esw->dev, "disable SRIOV: active vports(%d) mode(%d)\n",
index 1ee5bce..8529805 100644 (file)
@@ -178,8 +178,6 @@ out:
 
 static void mlx5i_destroy_underlay_qp(struct mlx5_core_dev *mdev, struct mlx5_core_qp *qp)
 {
-       mlx5_fs_remove_rx_underlay_qpn(mdev, qp->qpn);
-
        mlx5_core_destroy_qp(mdev, qp);
 }
 
@@ -194,8 +192,6 @@ static int mlx5i_init_tx(struct mlx5e_priv *priv)
                return err;
        }
 
-       mlx5_fs_add_rx_underlay_qpn(priv->mdev, ipriv->qp.qpn);
-
        err = mlx5e_create_tis(priv->mdev, 0 /* tc */, ipriv->qp.qpn, &priv->tisn[0]);
        if (err) {
                mlx5_core_warn(priv->mdev, "create tis failed, %d\n", err);
@@ -253,6 +249,7 @@ static void mlx5i_destroy_flow_steering(struct mlx5e_priv *priv)
 
 static int mlx5i_init_rx(struct mlx5e_priv *priv)
 {
+       struct mlx5i_priv *ipriv  = priv->ppriv;
        int err;
 
        err = mlx5e_create_indirect_rqt(priv);
@@ -271,12 +268,18 @@ static int mlx5i_init_rx(struct mlx5e_priv *priv)
        if (err)
                goto err_destroy_indirect_tirs;
 
-       err = mlx5i_create_flow_steering(priv);
+       err = mlx5_fs_add_rx_underlay_qpn(priv->mdev, ipriv->qp.qpn);
        if (err)
                goto err_destroy_direct_tirs;
 
+       err = mlx5i_create_flow_steering(priv);
+       if (err)
+               goto err_remove_rx_underlay_qpn;
+
        return 0;
 
+err_remove_rx_underlay_qpn:
+       mlx5_fs_remove_rx_underlay_qpn(priv->mdev, ipriv->qp.qpn);
 err_destroy_direct_tirs:
        mlx5e_destroy_direct_tirs(priv);
 err_destroy_indirect_tirs:
@@ -290,6 +293,9 @@ err_destroy_indirect_rqts:
 
 static void mlx5i_cleanup_rx(struct mlx5e_priv *priv)
 {
+       struct mlx5i_priv *ipriv  = priv->ppriv;
+
+       mlx5_fs_remove_rx_underlay_qpn(priv->mdev, ipriv->qp.qpn);
        mlx5i_destroy_flow_steering(priv);
        mlx5e_destroy_direct_tirs(priv);
        mlx5e_destroy_indirect_tirs(priv);
index a3a836b..f26f97f 100644 (file)
@@ -162,22 +162,17 @@ static bool mlx5_lag_is_bonded(struct mlx5_lag *ldev)
 static void mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker,
                                           u8 *port1, u8 *port2)
 {
-       if (tracker->tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP) {
-               if (tracker->netdev_state[0].tx_enabled) {
-                       *port1 = 1;
-                       *port2 = 1;
-               } else {
-                       *port1 = 2;
-                       *port2 = 2;
-               }
-       } else {
-               *port1 = 1;
-               *port2 = 2;
-               if (!tracker->netdev_state[0].link_up)
-                       *port1 = 2;
-               else if (!tracker->netdev_state[1].link_up)
-                       *port2 = 1;
+       *port1 = 1;
+       *port2 = 2;
+       if (!tracker->netdev_state[0].tx_enabled ||
+           !tracker->netdev_state[0].link_up) {
+               *port1 = 2;
+               return;
        }
+
+       if (!tracker->netdev_state[1].tx_enabled ||
+           !tracker->netdev_state[1].link_up)
+               *port2 = 1;
 }
 
 static void mlx5_activate_lag(struct mlx5_lag *ldev,
index 6a3d6be..6a263e8 100644 (file)
@@ -154,6 +154,11 @@ int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size);
 int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode);
 int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode);
 
+#define MLX5_PPS_CAP(mdev) (MLX5_CAP_GEN((mdev), pps) &&               \
+                           MLX5_CAP_GEN((mdev), pps_modify) &&         \
+                           MLX5_CAP_MCAM_FEATURE((mdev), mtpps_fs) &&  \
+                           MLX5_CAP_MCAM_FEATURE((mdev), mtpps_enh_out_per_adj))
+
 int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw);
 
 void mlx5e_init(void);
index bcdf777..bf99d40 100644 (file)
@@ -88,7 +88,11 @@ static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev)
        int vf;
 
        if (!sriov->enabled_vfs)
+#ifdef CONFIG_MLX5_CORE_EN
+               goto disable_sriov_resources;
+#else
                return;
+#endif
 
        for (vf = 0; vf < sriov->num_vfs; vf++) {
                if (!sriov->vfs_ctx[vf].enabled)
@@ -103,6 +107,7 @@ static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev)
        }
 
 #ifdef CONFIG_MLX5_CORE_EN
+disable_sriov_resources:
        mlx5_eswitch_disable_sriov(dev->priv.eswitch);
 #endif
 
index c6c5089..7e8ba54 100644 (file)
@@ -3992,16 +3992,16 @@ MLXSW_ITEM32(reg, ritr, ipv4, 0x00, 29, 1);
 MLXSW_ITEM32(reg, ritr, ipv6, 0x00, 28, 1);
 
 enum mlxsw_reg_ritr_if_type {
+       /* VLAN interface. */
        MLXSW_REG_RITR_VLAN_IF,
+       /* FID interface. */
        MLXSW_REG_RITR_FID_IF,
+       /* Sub-port interface. */
        MLXSW_REG_RITR_SP_IF,
 };
 
 /* reg_ritr_type
- * Router interface type.
- * 0 - VLAN interface.
- * 1 - FID interface.
- * 2 - Sub-port interface.
+ * Router interface type as per enum mlxsw_reg_ritr_if_type.
  * Access: RW
  */
 MLXSW_ITEM32(reg, ritr, type, 0x00, 23, 3);
@@ -4718,7 +4718,7 @@ MLXSW_ITEM32(reg, ralue, prefix_len, 0x08, 0, 8);
 /* reg_ralue_dip*
  * The prefix of the route or of the marker that the object of the LPM
  * is compared with. The most significant bits of the dip are the prefix.
- * The list significant bits must be '0' if the prefix_len is smaller
+ * The least significant bits must be '0' if the prefix_len is smaller
  * than 128 for IPv6 or smaller than 32 for IPv4.
  * IPv4 address uses bits dip[31:0] and bits dip[127:32] are reserved.
  * Access: Index
@@ -4813,7 +4813,7 @@ MLXSW_ITEM32(reg, ralue, ecmp_size, 0x28, 0, 13);
  */
 MLXSW_ITEM32(reg, ralue, local_erif, 0x24, 0, 16);
 
-/* reg_ralue_v
+/* reg_ralue_ip2me_v
  * Valid bit for the tunnel_ptr field.
  * If valid = 0 then trap to CPU as IP2ME trap ID.
  * If valid = 1 and the packet format allows NVE or IPinIP tunnel
@@ -4823,15 +4823,15 @@ MLXSW_ITEM32(reg, ralue, local_erif, 0x24, 0, 16);
  * Only relevant in case of IP2ME action.
  * Access: RW
  */
-MLXSW_ITEM32(reg, ralue, v, 0x24, 31, 1);
+MLXSW_ITEM32(reg, ralue, ip2me_v, 0x24, 31, 1);
 
-/* reg_ralue_tunnel_ptr
+/* reg_ralue_ip2me_tunnel_ptr
  * Tunnel Pointer for NVE or IPinIP tunnel decapsulation.
  * For Spectrum, pointer to KVD Linear.
  * Only relevant in case of IP2ME action.
  * Access: RW
  */
-MLXSW_ITEM32(reg, ralue, tunnel_ptr, 0x24, 0, 24);
+MLXSW_ITEM32(reg, ralue, ip2me_tunnel_ptr, 0x24, 0, 24);
 
 static inline void mlxsw_reg_ralue_pack(char *payload,
                                        enum mlxsw_reg_ralxx_protocol protocol,
index 01a1501..508b5fc 100644 (file)
@@ -369,7 +369,7 @@ int mlxsw_sp_acl_rulei_act_fwd(struct mlxsw_sp *mlxsw_sp,
                local_port = mlxsw_sp_port->local_port;
                in_port = false;
        } else {
-               /* If out_dev is NULL, the called wants to
+               /* If out_dev is NULL, the caller wants to
                 * set forward to ingress port.
                 */
                local_port = 0;
index e6d629f..add03fa 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/inetdevice.h>
 #include <linux/netdevice.h>
 #include <linux/if_bridge.h>
+#include <linux/socket.h>
 #include <net/netevent.h>
 #include <net/neighbour.h>
 #include <net/arp.h>
@@ -949,9 +950,13 @@ mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp *mlxsw_sp)
 {
        unsigned long interval;
 
+#if IS_ENABLED(CONFIG_IPV6)
        interval = min_t(unsigned long,
                         NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME),
                         NEIGH_VAR(&nd_tbl.parms, DELAY_PROBE_TIME));
+#else
+       interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME);
+#endif
        mlxsw_sp->router->neighs_update.interval = jiffies_to_msecs(interval);
 }
 
@@ -986,6 +991,7 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
        neigh_release(n);
 }
 
+#if IS_ENABLED(IPV6)
 static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
                                                   char *rauhtd_pl,
                                                   int rec_index)
@@ -1015,6 +1021,13 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
        neigh_event_send(n, NULL);
        neigh_release(n);
 }
+#else
+static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
+                                                  char *rauhtd_pl,
+                                                  int rec_index)
+{
+}
+#endif
 
 static void mlxsw_sp_router_neigh_rec_ipv4_process(struct mlxsw_sp *mlxsw_sp,
                                                   char *rauhtd_pl,
@@ -1260,10 +1273,10 @@ mlxsw_sp_neigh_entry_update(struct mlxsw_sp *mlxsw_sp,
        if (!adding && !neigh_entry->connected)
                return;
        neigh_entry->connected = adding;
-       if (neigh_entry->key.n->tbl == &arp_tbl) {
+       if (neigh_entry->key.n->tbl->family == AF_INET) {
                mlxsw_sp_router_neigh_entry_op4(mlxsw_sp, neigh_entry,
                                                mlxsw_sp_rauht_op(adding));
-       } else if (neigh_entry->key.n->tbl == &nd_tbl) {
+       } else if (neigh_entry->key.n->tbl->family == AF_INET6) {
                if (mlxsw_sp_neigh_ipv6_ignore(neigh_entry->key.n))
                        return;
                mlxsw_sp_router_neigh_entry_op6(mlxsw_sp, neigh_entry,
@@ -1339,7 +1352,8 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
                p = ptr;
 
                /* We don't care about changes in the default table. */
-               if (!p->dev || (p->tbl != &arp_tbl && p->tbl != &nd_tbl))
+               if (!p->dev || (p->tbl->family != AF_INET &&
+                               p->tbl->family != AF_INET6))
                        return NOTIFY_DONE;
 
                /* We are in atomic context and can't take RTNL mutex,
@@ -1358,7 +1372,7 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
        case NETEVENT_NEIGH_UPDATE:
                n = ptr;
 
-               if (n->tbl != &arp_tbl && n->tbl != &nd_tbl)
+               if (n->tbl->family != AF_INET && n->tbl->family != AF_INET6)
                        return NOTIFY_DONE;
 
                mlxsw_sp_port = mlxsw_sp_port_lower_dev_hold(n->dev);
@@ -1419,25 +1433,16 @@ static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)
        rhashtable_destroy(&mlxsw_sp->router->neigh_ht);
 }
 
-static int mlxsw_sp_neigh_rif_flush(struct mlxsw_sp *mlxsw_sp,
-                                   const struct mlxsw_sp_rif *rif)
-{
-       char rauht_pl[MLXSW_REG_RAUHT_LEN];
-
-       mlxsw_reg_rauht_pack(rauht_pl, MLXSW_REG_RAUHT_OP_WRITE_DELETE_ALL,
-                            rif->rif_index, rif->addr);
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
-}
-
 static void mlxsw_sp_neigh_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
                                         struct mlxsw_sp_rif *rif)
 {
        struct mlxsw_sp_neigh_entry *neigh_entry, *tmp;
 
-       mlxsw_sp_neigh_rif_flush(mlxsw_sp, rif);
        list_for_each_entry_safe(neigh_entry, tmp, &rif->neigh_list,
-                                rif_list_node)
+                                rif_list_node) {
+               mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, false);
                mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
+       }
 }
 
 struct mlxsw_sp_nexthop_key {
@@ -1626,6 +1631,10 @@ mlxsw_sp_nexthop_group_mac_update(struct mlxsw_sp *mlxsw_sp,
 static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
                                     struct mlxsw_sp_fib_entry *fib_entry);
 
+static bool
+mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node *fib_node,
+                                const struct mlxsw_sp_fib_entry *fib_entry);
+
 static int
 mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp *mlxsw_sp,
                                    struct mlxsw_sp_nexthop_group *nh_grp)
@@ -1634,6 +1643,9 @@ mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp *mlxsw_sp,
        int err;
 
        list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) {
+               if (!mlxsw_sp_fib_node_entry_is_first(fib_entry->fib_node,
+                                                     fib_entry))
+                       continue;
                err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
                if (err)
                        return err;
@@ -1663,7 +1675,7 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
        for (i = 0; i < nh_grp->count; i++) {
                nh = &nh_grp->nexthops[i];
 
-               if (nh->should_offload ^ nh->offloaded) {
+               if (nh->should_offload != nh->offloaded) {
                        offload_change = true;
                        if (nh->should_offload)
                                nh->update = 1;
@@ -1747,9 +1759,9 @@ set_trap:
 static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop *nh,
                                            bool removing)
 {
-       if (!removing && !nh->should_offload)
+       if (!removing)
                nh->should_offload = 1;
-       else if (removing && nh->offloaded)
+       else if (nh->offloaded)
                nh->should_offload = 0;
        nh->update = 1;
 }
@@ -1799,7 +1811,7 @@ static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp,
                return 0;
 
        /* Take a reference of neigh here ensuring that neigh would
-        * not be detructed before the nexthop entry is finished.
+        * not be destructed before the nexthop entry is finished.
         * The reference is taken either in neigh_lookup() or
         * in neigh_create() in case n is not found.
         */
@@ -3119,9 +3131,7 @@ mlxsw_sp_rif_should_config(struct mlxsw_sp_rif *rif, struct net_device *dev,
 
        switch (event) {
        case NETDEV_UP:
-               if (!rif)
-                       return true;
-               return false;
+               return rif == NULL;
        case NETDEV_DOWN:
                idev = __in_dev_get_rtnl(dev);
                if (idev && idev->ifa_list)
index c0d7d5e..2e4effa 100644 (file)
@@ -161,7 +161,7 @@ static void moxart_mac_setup_desc_ring(struct net_device *ndev)
 
        priv->rx_head = 0;
 
-       /* reset the MAC controller TX/RX desciptor base address */
+       /* reset the MAC controller TX/RX descriptor base address */
        writel(priv->tx_base, priv->base + REG_TXR_BASE_ADDRESS);
        writel(priv->rx_base, priv->base + REG_RXR_BASE_ADDRESS);
 }
@@ -269,9 +269,8 @@ rx_next:
                priv->rx_head = rx_head;
        }
 
-       if (rx < budget) {
+       if (rx < budget)
                napi_complete_done(napi, rx);
-       }
 
        priv->reg_imr |= RPKT_FINISH_M;
        writel(priv->reg_imr, priv->base + REG_INTERRUPT_MASK);
@@ -289,8 +288,8 @@ static int moxart_tx_queue_space(struct net_device *ndev)
 static void moxart_tx_finished(struct net_device *ndev)
 {
        struct moxart_mac_priv_t *priv = netdev_priv(ndev);
-       unsigned tx_head = priv->tx_head;
-       unsigned tx_tail = priv->tx_tail;
+       unsigned int tx_head = priv->tx_head;
+       unsigned int tx_tail = priv->tx_tail;
 
        while (tx_tail != tx_head) {
                dma_unmap_single(&ndev->dev, priv->tx_mapping[tx_tail],
@@ -312,7 +311,7 @@ static void moxart_tx_finished(struct net_device *ndev)
 
 static irqreturn_t moxart_mac_interrupt(int irq, void *dev_id)
 {
-       struct net_device *ndev = (struct net_device *) dev_id;
+       struct net_device *ndev = (struct net_device *)dev_id;
        struct moxart_mac_priv_t *priv = netdev_priv(ndev);
        unsigned int ists = readl(priv->base + REG_INTERRUPT_STATUS);
 
@@ -495,7 +494,7 @@ static int moxart_mac_probe(struct platform_device *pdev)
        priv->tx_desc_base = dma_alloc_coherent(NULL, TX_REG_DESC_SIZE *
                                                TX_DESC_NUM, &priv->tx_base,
                                                GFP_DMA | GFP_KERNEL);
-       if (priv->tx_desc_base == NULL) {
+       if (!priv->tx_desc_base) {
                ret = -ENOMEM;
                goto init_fail;
        }
@@ -503,7 +502,7 @@ static int moxart_mac_probe(struct platform_device *pdev)
        priv->rx_desc_base = dma_alloc_coherent(NULL, RX_REG_DESC_SIZE *
                                                RX_DESC_NUM, &priv->rx_base,
                                                GFP_DMA | GFP_KERNEL);
-       if (priv->rx_desc_base == NULL) {
+       if (!priv->rx_desc_base) {
                ret = -ENOMEM;
                goto init_fail;
        }
index 686b895..bee608b 100644 (file)
 #define RX_DESC2_ADDRESS_VIRT  4
 
 #define TX_DESC_NUM            64
-#define TX_DESC_NUM_MASK       (TX_DESC_NUM-1)
+#define TX_DESC_NUM_MASK       (TX_DESC_NUM - 1)
 #define TX_NEXT(N)             (((N) + 1) & (TX_DESC_NUM_MASK))
 #define TX_BUF_SIZE            1600
-#define TX_BUF_SIZE_MAX                (TX_DESC1_BUF_SIZE_MASK+1)
+#define TX_BUF_SIZE_MAX                (TX_DESC1_BUF_SIZE_MASK + 1)
 #define TX_WAKE_THRESHOLD      16
 
 #define RX_DESC_NUM            64
-#define RX_DESC_NUM_MASK       (RX_DESC_NUM-1)
+#define RX_DESC_NUM_MASK       (RX_DESC_NUM - 1)
 #define RX_NEXT(N)             (((N) + 1) & (RX_DESC_NUM_MASK))
 #define RX_BUF_SIZE            1600
-#define RX_BUF_SIZE_MAX                (RX_DESC1_BUF_SIZE_MASK+1)
+#define RX_BUF_SIZE_MAX                (RX_DESC1_BUF_SIZE_MASK + 1)
 
 #define REG_INTERRUPT_STATUS   0
 #define REG_INTERRUPT_MASK     4
index d67969d..dd769ec 100644 (file)
@@ -174,6 +174,21 @@ static int nfp_pcie_sriov_configure(struct pci_dev *pdev, int num_vfs)
                return nfp_pcie_sriov_enable(pdev, num_vfs);
 }
 
+static const struct firmware *
+nfp_net_fw_request(struct pci_dev *pdev, struct nfp_pf *pf, const char *name)
+{
+       const struct firmware *fw = NULL;
+       int err;
+
+       err = request_firmware_direct(&fw, name, &pdev->dev);
+       nfp_info(pf->cpp, "  %s: %s\n",
+                name, err ? "not found" : "found, loading...");
+       if (err)
+               return NULL;
+
+       return fw;
+}
+
 /**
  * nfp_net_fw_find() - Find the correct firmware image for netdev mode
  * @pdev:      PCI Device structure
@@ -184,13 +199,32 @@ static int nfp_pcie_sriov_configure(struct pci_dev *pdev, int num_vfs)
 static const struct firmware *
 nfp_net_fw_find(struct pci_dev *pdev, struct nfp_pf *pf)
 {
-       const struct firmware *fw = NULL;
        struct nfp_eth_table_port *port;
+       const struct firmware *fw;
        const char *fw_model;
        char fw_name[256];
-       int spc, err = 0;
-       int i, j;
+       const u8 *serial;
+       u16 interface;
+       int spc, i, j;
 
+       nfp_info(pf->cpp, "Looking for firmware file in order of priority:\n");
+
+       /* First try to find a firmware image specific for this device */
+       interface = nfp_cpp_interface(pf->cpp);
+       nfp_cpp_serial(pf->cpp, &serial);
+       sprintf(fw_name, "netronome/serial-%pMF-%02hhx-%02hhx.nffw",
+               serial, interface >> 8, interface & 0xff);
+       fw = nfp_net_fw_request(pdev, pf, fw_name);
+       if (fw)
+               return fw;
+
+       /* Then try the PCI name */
+       sprintf(fw_name, "netronome/pci-%s.nffw", pci_name(pdev));
+       fw = nfp_net_fw_request(pdev, pf, fw_name);
+       if (fw)
+               return fw;
+
+       /* Finally try the card type and media */
        if (!pf->eth_tbl) {
                dev_err(&pdev->dev, "Error: can't identify media config\n");
                return NULL;
@@ -223,13 +257,7 @@ nfp_net_fw_find(struct pci_dev *pdev, struct nfp_pf *pf)
        if (spc <= 0)
                return NULL;
 
-       err = request_firmware(&fw, fw_name, &pdev->dev);
-       if (err)
-               return NULL;
-
-       dev_info(&pdev->dev, "Loading FW image: %s\n", fw_name);
-
-       return fw;
+       return nfp_net_fw_request(pdev, pf, fw_name);
 }
 
 /**
index 18750ff..ea47160 100644 (file)
@@ -2658,6 +2658,7 @@ static int nfp_net_netdev_close(struct net_device *netdev)
        /* Step 2: Tell NFP
         */
        nfp_net_clear_config_and_disable(nn);
+       nfp_port_configure(netdev, false);
 
        /* Step 3: Free resources
         */
@@ -2775,16 +2776,21 @@ static int nfp_net_netdev_open(struct net_device *netdev)
                goto err_free_all;
 
        /* Step 2: Configure the NFP
+        * - Ifup the physical interface if it exists
         * - Enable rings from 0 to tx_rings/rx_rings - 1.
         * - Write MAC address (in case it changed)
         * - Set the MTU
         * - Set the Freelist buffer size
         * - Enable the FW
         */
-       err = nfp_net_set_config_and_enable(nn);
+       err = nfp_port_configure(netdev, true);
        if (err)
                goto err_free_all;
 
+       err = nfp_net_set_config_and_enable(nn);
+       if (err)
+               goto err_port_disable;
+
        /* Step 3: Enable for kernel
         * - put some freelist descriptors on each RX ring
         * - enable NAPI on each ring
@@ -2795,6 +2801,8 @@ static int nfp_net_netdev_open(struct net_device *netdev)
 
        return 0;
 
+err_port_disable:
+       nfp_port_configure(netdev, false);
 err_free_all:
        nfp_net_close_free_all(nn);
        return err;
index 5797dbf..d5e2361 100644 (file)
@@ -704,7 +704,7 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
        if (!pf->rtbl) {
                nfp_err(pf->cpp, "No %s, giving up.\n",
                        pf->fw_loaded ? "symbol table" : "firmware found");
-               return -EPROBE_DEFER;
+               return -EINVAL;
        }
 
        mutex_lock(&pf->lock);
index 8ec5474..47daad3 100644 (file)
@@ -239,15 +239,34 @@ static netdev_tx_t nfp_repr_xmit(struct sk_buff *skb, struct net_device *netdev)
 static int nfp_repr_stop(struct net_device *netdev)
 {
        struct nfp_repr *repr = netdev_priv(netdev);
+       int err;
+
+       err = nfp_app_repr_stop(repr->app, repr);
+       if (err)
+               return err;
 
-       return nfp_app_repr_stop(repr->app, repr);
+       nfp_port_configure(netdev, false);
+       return 0;
 }
 
 static int nfp_repr_open(struct net_device *netdev)
 {
        struct nfp_repr *repr = netdev_priv(netdev);
+       int err;
+
+       err = nfp_port_configure(netdev, true);
+       if (err)
+               return err;
+
+       err = nfp_app_repr_open(repr->app, repr);
+       if (err)
+               goto err_port_disable;
 
-       return nfp_app_repr_open(repr->app, repr);
+       return 0;
+
+err_port_disable:
+       nfp_port_configure(netdev, false);
+       return err;
 }
 
 const struct net_device_ops nfp_repr_netdev_ops = {
index e42644d..d16a7b7 100644 (file)
@@ -181,6 +181,33 @@ nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len)
        return 0;
 }
 
+/**
+ * nfp_port_configure() - helper to set the interface configured bit
+ * @netdev:    net_device instance
+ * @configed:  Desired state
+ *
+ * Helper to set the ifup/ifdown state on the PHY only if there is a physical
+ * interface associated with the netdev.
+ *
+ * Return:
+ * 0 - configuration successful (or no change);
+ * -ERRNO - configuration failed.
+ */
+int nfp_port_configure(struct net_device *netdev, bool configed)
+{
+       struct nfp_eth_table_port *eth_port;
+       struct nfp_port *port;
+       int err;
+
+       port = nfp_port_from_netdev(netdev);
+       eth_port = __nfp_port_get_eth_port(port);
+       if (!eth_port)
+               return 0;
+
+       err = nfp_eth_set_configured(port->app->cpp, eth_port->index, configed);
+       return err < 0 && err != -EOPNOTSUPP ? err : 0;
+}
+
 int nfp_port_init_phy_port(struct nfp_pf *pf, struct nfp_app *app,
                           struct nfp_port *port, unsigned int id)
 {
index a33d22e..56c7692 100644 (file)
@@ -120,6 +120,7 @@ struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port);
 
 int
 nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len);
+int nfp_port_configure(struct net_device *netdev, bool configed);
 
 struct nfp_port *
 nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type,
index c2bc36e..f6f7c08 100644 (file)
@@ -391,7 +391,10 @@ int nfp_eth_config_commit_end(struct nfp_nsp *nsp)
  * Enable or disable PHY module (this usually means setting the TX lanes
  * disable bits).
  *
- * Return: 0 or -ERRNO.
+ * Return:
+ * 0 - configuration successful;
+ * 1 - no changes were needed;
+ * -ERRNO - configuration failed.
  */
 int nfp_eth_set_mod_enable(struct nfp_cpp *cpp, unsigned int idx, bool enable)
 {
@@ -427,7 +430,10 @@ int nfp_eth_set_mod_enable(struct nfp_cpp *cpp, unsigned int idx, bool enable)
  *
  * Set the ifup/ifdown state on the PHY.
  *
- * Return: 0 or -ERRNO.
+ * Return:
+ * 0 - configuration successful;
+ * 1 - no changes were needed;
+ * -ERRNO - configuration failed.
  */
 int nfp_eth_set_configured(struct nfp_cpp *cpp, unsigned int idx, bool configed)
 {
@@ -439,6 +445,14 @@ int nfp_eth_set_configured(struct nfp_cpp *cpp, unsigned int idx, bool configed)
        if (IS_ERR(nsp))
                return PTR_ERR(nsp);
 
+       /* Older ABI versions did support this feature, however this has only
+        * been reliable since ABI 20.
+        */
+       if (nfp_nsp_get_abi_ver_minor(nsp) < 20) {
+               nfp_eth_config_cleanup_end(nsp);
+               return -EOPNOTSUPP;
+       }
+
        entries = nfp_nsp_config_entries(nsp);
 
        /* Check if we are already in requested state */
index 6c87bed..58a689f 100644 (file)
@@ -1684,6 +1684,8 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)
                           "Load request was sent. Load code: 0x%x\n",
                           load_code);
 
+               qed_mcp_set_capabilities(p_hwfn, p_hwfn->p_main_ptt);
+
                qed_reset_mb_shadow(p_hwfn, p_hwfn->p_main_ptt);
 
                p_hwfn->first_on_engine = (load_code ==
@@ -2472,6 +2474,7 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
 {
        u32 port_cfg_addr, link_temp, nvm_cfg_addr, device_capabilities;
        u32 nvm_cfg1_offset, mf_mode, addr, generic_cont0, core_cfg;
+       struct qed_mcp_link_capabilities *p_caps;
        struct qed_mcp_link_params *link;
 
        /* Read global nvm_cfg address */
@@ -2534,6 +2537,7 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
 
        /* Read default link configuration */
        link = &p_hwfn->mcp_info->link_input;
+       p_caps = &p_hwfn->mcp_info->link_capabilities;
        port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
                        offsetof(struct nvm_cfg1, port[MFW_PORT(p_hwfn)]);
        link_temp = qed_rd(p_hwfn, p_ptt,
@@ -2588,10 +2592,45 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
                                   NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX);
        link->loopback_mode = 0;
 
-       DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
-                  "Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x\n",
-                  link->speed.forced_speed, link->speed.advertised_speeds,
-                  link->speed.autoneg, link->pause.autoneg);
+       if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) {
+               link_temp = qed_rd(p_hwfn, p_ptt, port_cfg_addr +
+                                  offsetof(struct nvm_cfg1_port, ext_phy));
+               link_temp &= NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_MASK;
+               link_temp >>= NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_OFFSET;
+               p_caps->default_eee = QED_MCP_EEE_ENABLED;
+               link->eee.enable = true;
+               switch (link_temp) {
+               case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_DISABLED:
+                       p_caps->default_eee = QED_MCP_EEE_DISABLED;
+                       link->eee.enable = false;
+                       break;
+               case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_BALANCED:
+                       p_caps->eee_lpi_timer = EEE_TX_TIMER_USEC_BALANCED_TIME;
+                       break;
+               case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_AGGRESSIVE:
+                       p_caps->eee_lpi_timer =
+                           EEE_TX_TIMER_USEC_AGGRESSIVE_TIME;
+                       break;
+               case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_LOW_LATENCY:
+                       p_caps->eee_lpi_timer = EEE_TX_TIMER_USEC_LATENCY_TIME;
+                       break;
+               }
+
+               link->eee.tx_lpi_timer = p_caps->eee_lpi_timer;
+               link->eee.tx_lpi_enable = link->eee.enable;
+               link->eee.adv_caps = QED_EEE_1G_ADV | QED_EEE_10G_ADV;
+       } else {
+               p_caps->default_eee = QED_MCP_EEE_UNSUPPORTED;
+       }
+
+       DP_VERBOSE(p_hwfn,
+                  NETIF_MSG_LINK,
+                  "Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x EEE: %02x [%08x usec]\n",
+                  link->speed.forced_speed,
+                  link->speed.advertised_speeds,
+                  link->speed.autoneg,
+                  link->pause.autoneg,
+                  p_caps->default_eee, p_caps->eee_lpi_timer);
 
        /* Read Multi-function information from shmem */
        addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
@@ -2751,6 +2790,27 @@ static void qed_hw_info_port_num(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
                qed_hw_info_port_num_ah(p_hwfn, p_ptt);
 }
 
+static void qed_get_eee_caps(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
+{
+       struct qed_mcp_link_capabilities *p_caps;
+       u32 eee_status;
+
+       p_caps = &p_hwfn->mcp_info->link_capabilities;
+       if (p_caps->default_eee == QED_MCP_EEE_UNSUPPORTED)
+               return;
+
+       p_caps->eee_speed_caps = 0;
+       eee_status = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr +
+                           offsetof(struct public_port, eee_status));
+       eee_status = (eee_status & EEE_SUPPORTED_SPEED_MASK) >>
+                       EEE_SUPPORTED_SPEED_OFFSET;
+
+       if (eee_status & EEE_1G_SUPPORTED)
+               p_caps->eee_speed_caps |= QED_EEE_1G_ADV;
+       if (eee_status & EEE_10G_ADV)
+               p_caps->eee_speed_caps |= QED_EEE_10G_ADV;
+}
+
 static int
 qed_get_hw_info(struct qed_hwfn *p_hwfn,
                struct qed_ptt *p_ptt,
@@ -2767,6 +2827,8 @@ qed_get_hw_info(struct qed_hwfn *p_hwfn,
 
        qed_hw_info_port_num(p_hwfn, p_ptt);
 
+       qed_mcp_get_capabilities(p_hwfn, p_ptt);
+
        qed_hw_get_nvm_info(p_hwfn, p_ptt);
 
        rc = qed_int_igu_read_cam(p_hwfn, p_ptt);
@@ -2785,6 +2847,8 @@ qed_get_hw_info(struct qed_hwfn *p_hwfn,
                                p_hwfn->mcp_info->func_info.ovlan;
 
                qed_mcp_cmd_port_init(p_hwfn, p_ptt);
+
+               qed_get_eee_caps(p_hwfn, p_ptt);
        }
 
        if (qed_mcp_is_init(p_hwfn)) {
@@ -3630,7 +3694,7 @@ static int qed_set_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
        }
 
        p_coal_timeset = p_eth_qzone;
-       memset(p_coal_timeset, 0, eth_qzone_size);
+       memset(p_eth_qzone, 0, eth_qzone_size);
        SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_TIMESET, timeset);
        SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_VALID, 1);
        qed_memcpy_to(p_hwfn, p_ptt, hw_addr, p_eth_qzone, eth_qzone_size);
@@ -3638,12 +3702,46 @@ static int qed_set_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
        return 0;
 }
 
-int qed_set_rxq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
-                        u16 coalesce, u16 qid, u16 sb_id)
+int qed_set_queue_coalesce(u16 rx_coal, u16 tx_coal, void *p_handle)
+{
+       struct qed_queue_cid *p_cid = p_handle;
+       struct qed_hwfn *p_hwfn;
+       struct qed_ptt *p_ptt;
+       int rc = 0;
+
+       p_hwfn = p_cid->p_owner;
+
+       if (IS_VF(p_hwfn->cdev))
+               return qed_vf_pf_set_coalesce(p_hwfn, rx_coal, tx_coal, p_cid);
+
+       p_ptt = qed_ptt_acquire(p_hwfn);
+       if (!p_ptt)
+               return -EAGAIN;
+
+       if (rx_coal) {
+               rc = qed_set_rxq_coalesce(p_hwfn, p_ptt, rx_coal, p_cid);
+               if (rc)
+                       goto out;
+               p_hwfn->cdev->rx_coalesce_usecs = rx_coal;
+       }
+
+       if (tx_coal) {
+               rc = qed_set_txq_coalesce(p_hwfn, p_ptt, tx_coal, p_cid);
+               if (rc)
+                       goto out;
+               p_hwfn->cdev->tx_coalesce_usecs = tx_coal;
+       }
+out:
+       qed_ptt_release(p_hwfn, p_ptt);
+       return rc;
+}
+
+int qed_set_rxq_coalesce(struct qed_hwfn *p_hwfn,
+                        struct qed_ptt *p_ptt,
+                        u16 coalesce, struct qed_queue_cid *p_cid)
 {
        struct ustorm_eth_queue_zone eth_qzone;
        u8 timeset, timer_res;
-       u16 fw_qid = 0;
        u32 address;
        int rc;
 
@@ -3660,32 +3758,29 @@ int qed_set_rxq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
        }
        timeset = (u8)(coalesce >> timer_res);
 
-       rc = qed_fw_l2_queue(p_hwfn, qid, &fw_qid);
-       if (rc)
-               return rc;
-
-       rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res, sb_id, false);
+       rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res,
+                                  p_cid->sb_igu_id, false);
        if (rc)
                goto out;
 
-       address = BAR0_MAP_REG_USDM_RAM + USTORM_ETH_QUEUE_ZONE_OFFSET(fw_qid);
+       address = BAR0_MAP_REG_USDM_RAM +
+                 USTORM_ETH_QUEUE_ZONE_OFFSET(p_cid->abs.queue_id);
 
        rc = qed_set_coalesce(p_hwfn, p_ptt, address, &eth_qzone,
                              sizeof(struct ustorm_eth_queue_zone), timeset);
        if (rc)
                goto out;
 
-       p_hwfn->cdev->rx_coalesce_usecs = coalesce;
 out:
        return rc;
 }
 
-int qed_set_txq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
-                        u16 coalesce, u16 qid, u16 sb_id)
+int qed_set_txq_coalesce(struct qed_hwfn *p_hwfn,
+                        struct qed_ptt *p_ptt,
+                        u16 coalesce, struct qed_queue_cid *p_cid)
 {
        struct xstorm_eth_queue_zone eth_qzone;
        u8 timeset, timer_res;
-       u16 fw_qid = 0;
        u32 address;
        int rc;
 
@@ -3702,22 +3797,16 @@ int qed_set_txq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
        }
        timeset = (u8)(coalesce >> timer_res);
 
-       rc = qed_fw_l2_queue(p_hwfn, qid, &fw_qid);
-       if (rc)
-               return rc;
-
-       rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res, sb_id, true);
+       rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res,
+                                  p_cid->sb_igu_id, true);
        if (rc)
                goto out;
 
-       address = BAR0_MAP_REG_XSDM_RAM + XSTORM_ETH_QUEUE_ZONE_OFFSET(fw_qid);
+       address = BAR0_MAP_REG_XSDM_RAM +
+                 XSTORM_ETH_QUEUE_ZONE_OFFSET(p_cid->abs.queue_id);
 
        rc = qed_set_coalesce(p_hwfn, p_ptt, address, &eth_qzone,
                              sizeof(struct xstorm_eth_queue_zone), timeset);
-       if (rc)
-               goto out;
-
-       p_hwfn->cdev->tx_coalesce_usecs = coalesce;
 out:
        return rc;
 }
index 1f1df1b..defdda1 100644 (file)
@@ -443,38 +443,35 @@ int qed_final_cleanup(struct qed_hwfn *p_hwfn,
                      struct qed_ptt *p_ptt, u16 id, bool is_vf);
 
 /**
- * @brief qed_set_rxq_coalesce - Configure coalesce parameters for an Rx queue
- * The fact that we can configure coalescing to up to 511, but on varying
- * accuracy [the bigger the value the less accurate] up to a mistake of 3usec
- * for the highest values.
+ * @brief qed_get_queue_coalesce - Retrieve coalesce value for a given queue.
  *
  * @param p_hwfn
- * @param p_ptt
- * @param coalesce - Coalesce value in micro seconds.
- * @param qid - Queue index.
- * @param qid - SB Id
+ * @param p_coal - store coalesce value read from the hardware.
+ * @param p_handle
  *
  * @return int
- */
-int qed_set_rxq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
-                        u16 coalesce, u16 qid, u16 sb_id);
+ **/
+int qed_get_queue_coalesce(struct qed_hwfn *p_hwfn, u16 *coal, void *handle);
 
 /**
- * @brief qed_set_txq_coalesce - Configure coalesce parameters for a Tx queue
- * While the API allows setting coalescing per-qid, all tx queues sharing a
- * SB should be in same range [i.e., either 0-0x7f, 0x80-0xff or 0x100-0x1ff]
- * otherwise configuration would break.
+ * @brief qed_set_queue_coalesce - Configure coalesce parameters for Rx and
+ *    Tx queue. The fact that we can configure coalescing to up to 511, but on
+ *    varying accuracy [the bigger the value the less accurate] up to a mistake
+ *    of 3usec for the highest values.
+ *    While the API allows setting coalescing per-qid, all queues sharing a SB
+ *    should be in same range [i.e., either 0-0x7f, 0x80-0xff or 0x100-0x1ff]
+ *    otherwise configuration would break.
  *
- * @param p_hwfn
- * @param p_ptt
- * @param coalesce - Coalesce value in micro seconds.
- * @param qid - Queue index.
- * @param qid - SB Id
+ *
+ * @param rx_coal - Rx Coalesce value in micro seconds.
+ * @param tx_coal - TX Coalesce value in micro seconds.
+ * @param p_handle
  *
  * @return int
- */
-int qed_set_txq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
-                        u16 coalesce, u16 qid, u16 sb_id);
+ **/
+int
+qed_set_queue_coalesce(u16 rx_coal, u16 tx_coal, void *p_handle);
+
 
 const char *qed_hw_get_resc_name(enum qed_resources res_id);
 #endif
index 31fb0bf..3427fe7 100644 (file)
@@ -10825,6 +10825,17 @@ struct eth_phy_cfg {
 #define ETH_LOOPBACK_EXT               (3)
 #define ETH_LOOPBACK_MAC               (4)
 
+       u32 eee_cfg;
+#define EEE_CFG_EEE_ENABLED                    BIT(0)
+#define EEE_CFG_TX_LPI                         BIT(1)
+#define EEE_CFG_ADV_SPEED_1G                   BIT(2)
+#define EEE_CFG_ADV_SPEED_10G                  BIT(3)
+#define EEE_TX_TIMER_USEC_MASK                 (0xfffffff0)
+#define EEE_TX_TIMER_USEC_OFFSET               4
+#define EEE_TX_TIMER_USEC_BALANCED_TIME                (0xa00)
+#define EEE_TX_TIMER_USEC_AGGRESSIVE_TIME      (0x100)
+#define EEE_TX_TIMER_USEC_LATENCY_TIME         (0x6000)
+
        u32 feature_config_flags;
 #define ETH_EEE_MODE_ADV_LPI           (1 << 0)
 };
@@ -11242,6 +11253,25 @@ struct public_port {
        u32 wol_pkt_len;
        u32 wol_pkt_details;
        struct dcb_dscp_map dcb_dscp_map;
+
+       u32 eee_status;
+#define EEE_ACTIVE_BIT                 BIT(0)
+#define EEE_LD_ADV_STATUS_MASK         0x000000f0
+#define EEE_LD_ADV_STATUS_OFFSET       4
+#define EEE_1G_ADV                     BIT(1)
+#define EEE_10G_ADV                    BIT(2)
+#define EEE_LP_ADV_STATUS_MASK         0x00000f00
+#define EEE_LP_ADV_STATUS_OFFSET       8
+#define EEE_SUPPORTED_SPEED_MASK       0x0000f000
+#define EEE_SUPPORTED_SPEED_OFFSET     12
+#define EEE_1G_SUPPORTED               BIT(1)
+#define EEE_10G_SUPPORTED              BIT(2)
+
+       u32 eee_remote;
+#define EEE_REMOTE_TW_TX_MASK   0x0000ffff
+#define EEE_REMOTE_TW_TX_OFFSET 0
+#define EEE_REMOTE_TW_RX_MASK   0xffff0000
+#define EEE_REMOTE_TW_RX_OFFSET 16
 };
 
 struct public_func {
@@ -11570,6 +11600,9 @@ struct public_drv_mb {
 #define DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL      0x002b0000
 #define DRV_MSG_CODE_OS_WOL                    0x002e0000
 
+#define DRV_MSG_CODE_FEATURE_SUPPORT           0x00300000
+#define DRV_MSG_CODE_GET_MFW_FEATURE_SUPPORT   0x00310000
+
 #define DRV_MSG_SEQ_NUMBER_MASK                        0x0000ffff
 
        u32 drv_mb_param;
@@ -11653,6 +11686,10 @@ struct public_drv_mb {
 #define DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_SHIFT       8
 #define DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_MASK                0x0000FF00
 
+#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_MASK         0x0000FFFF
+#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_OFFSET       0
+#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE          0x00000002
+
        u32 fw_mb_header;
 #define FW_MSG_CODE_MASK                       0xffff0000
 #define FW_MSG_CODE_UNSUPPORTED                 0x00000000
@@ -11696,6 +11733,9 @@ struct public_drv_mb {
 #define FW_MB_PARAM_GET_PF_RDMA_IWARP          0x2
 #define FW_MB_PARAM_GET_PF_RDMA_BOTH           0x3
 
+/* get MFW feature support response */
+#define FW_MB_PARAM_FEATURE_SUPPORT_EEE                0x00000002
+
 #define FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR  (1 << 0)
 
        u32 drv_pulse_mb;
@@ -11891,7 +11931,16 @@ struct nvm_cfg1_port {
 #define NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX                      0x4
        u32 phy_cfg;
        u32 mgmt_traffic;
+
        u32 ext_phy;
+       /* EEE power saving mode */
+#define NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_MASK               0x00FF0000
+#define NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_OFFSET             16
+#define NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_DISABLED           0x0
+#define NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_BALANCED           0x1
+#define NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_AGGRESSIVE         0x2
+#define NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_LOW_LATENCY                0x3
+
        u32 mba_cfg1;
        u32 mba_cfg2;
        u32 vf_cfg;
index 0ba5ec8..9a16458 100644 (file)
@@ -2047,6 +2047,106 @@ qed_configure_rfs_ntuple_filter(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
        return qed_spq_post(p_hwfn, p_ent, NULL);
 }
 
+int qed_get_rxq_coalesce(struct qed_hwfn *p_hwfn,
+                        struct qed_ptt *p_ptt,
+                        struct qed_queue_cid *p_cid, u16 *p_rx_coal)
+{
+       u32 coalesce, address, is_valid;
+       struct cau_sb_entry sb_entry;
+       u8 timer_res;
+       int rc;
+
+       rc = qed_dmae_grc2host(p_hwfn, p_ptt, CAU_REG_SB_VAR_MEMORY +
+                              p_cid->sb_igu_id * sizeof(u64),
+                              (u64)(uintptr_t)&sb_entry, 2, 0);
+       if (rc) {
+               DP_ERR(p_hwfn, "dmae_grc2host failed %d\n", rc);
+               return rc;
+       }
+
+       timer_res = GET_FIELD(sb_entry.params, CAU_SB_ENTRY_TIMER_RES0);
+
+       address = BAR0_MAP_REG_USDM_RAM +
+                 USTORM_ETH_QUEUE_ZONE_OFFSET(p_cid->abs.queue_id);
+       coalesce = qed_rd(p_hwfn, p_ptt, address);
+
+       is_valid = GET_FIELD(coalesce, COALESCING_TIMESET_VALID);
+       if (!is_valid)
+               return -EINVAL;
+
+       coalesce = GET_FIELD(coalesce, COALESCING_TIMESET_TIMESET);
+       *p_rx_coal = (u16)(coalesce << timer_res);
+
+       return 0;
+}
+
+int qed_get_txq_coalesce(struct qed_hwfn *p_hwfn,
+                        struct qed_ptt *p_ptt,
+                        struct qed_queue_cid *p_cid, u16 *p_tx_coal)
+{
+       u32 coalesce, address, is_valid;
+       struct cau_sb_entry sb_entry;
+       u8 timer_res;
+       int rc;
+
+       rc = qed_dmae_grc2host(p_hwfn, p_ptt, CAU_REG_SB_VAR_MEMORY +
+                              p_cid->sb_igu_id * sizeof(u64),
+                              (u64)(uintptr_t)&sb_entry, 2, 0);
+       if (rc) {
+               DP_ERR(p_hwfn, "dmae_grc2host failed %d\n", rc);
+               return rc;
+       }
+
+       timer_res = GET_FIELD(sb_entry.params, CAU_SB_ENTRY_TIMER_RES1);
+
+       address = BAR0_MAP_REG_XSDM_RAM +
+                 XSTORM_ETH_QUEUE_ZONE_OFFSET(p_cid->abs.queue_id);
+       coalesce = qed_rd(p_hwfn, p_ptt, address);
+
+       is_valid = GET_FIELD(coalesce, COALESCING_TIMESET_VALID);
+       if (!is_valid)
+               return -EINVAL;
+
+       coalesce = GET_FIELD(coalesce, COALESCING_TIMESET_TIMESET);
+       *p_tx_coal = (u16)(coalesce << timer_res);
+
+       return 0;
+}
+
+int qed_get_queue_coalesce(struct qed_hwfn *p_hwfn, u16 *p_coal, void *handle)
+{
+       struct qed_queue_cid *p_cid = handle;
+       struct qed_ptt *p_ptt;
+       int rc = 0;
+
+       if (IS_VF(p_hwfn->cdev)) {
+               rc = qed_vf_pf_get_coalesce(p_hwfn, p_coal, p_cid);
+               if (rc)
+                       DP_NOTICE(p_hwfn, "Unable to read queue coalescing\n");
+
+               return rc;
+       }
+
+       p_ptt = qed_ptt_acquire(p_hwfn);
+       if (!p_ptt)
+               return -EAGAIN;
+
+       if (p_cid->b_is_rx) {
+               rc = qed_get_rxq_coalesce(p_hwfn, p_ptt, p_cid, p_coal);
+               if (rc)
+                       goto out;
+       } else {
+               rc = qed_get_txq_coalesce(p_hwfn, p_ptt, p_cid, p_coal);
+               if (rc)
+                       goto out;
+       }
+
+out:
+       qed_ptt_release(p_hwfn, p_ptt);
+
+       return rc;
+}
+
 static int qed_fill_eth_dev_info(struct qed_dev *cdev,
                                 struct qed_dev_eth_info *info)
 {
@@ -2696,6 +2796,20 @@ static int qed_ntuple_arfs_filter_config(struct qed_dev *cdev, void *cookie,
        return rc;
 }
 
+static int qed_get_coalesce(struct qed_dev *cdev, u16 *coal, void *handle)
+{
+       struct qed_queue_cid *p_cid = handle;
+       struct qed_hwfn *p_hwfn;
+       int rc;
+
+       p_hwfn = p_cid->p_owner;
+       rc = qed_get_queue_coalesce(p_hwfn, coal, handle);
+       if (rc)
+               DP_NOTICE(p_hwfn, "Unable to read queue calescing\n");
+
+       return rc;
+}
+
 static int qed_fp_cqe_completion(struct qed_dev *dev,
                                 u8 rss_id, struct eth_slow_path_rx_cqe *cqe)
 {
@@ -2739,6 +2853,7 @@ static const struct qed_eth_ops qed_eth_ops_pass = {
        .tunn_config = &qed_tunn_configure,
        .ntuple_filter_config = &qed_ntuple_arfs_filter_config,
        .configure_arfs_searcher = &qed_configure_arfs_searcher,
+       .get_coalesce = &qed_get_coalesce,
 };
 
 const struct qed_eth_ops *qed_get_eth_ops(void)
index f8f09aa..cc1f248 100644 (file)
@@ -400,4 +400,20 @@ qed_eth_txq_start_ramrod(struct qed_hwfn *p_hwfn,
 
 u8 qed_mcast_bin_from_mac(u8 *mac);
 
-#endif /* _QED_L2_H */
+int qed_set_rxq_coalesce(struct qed_hwfn *p_hwfn,
+                        struct qed_ptt *p_ptt,
+                        u16 coalesce, struct qed_queue_cid *p_cid);
+
+int qed_set_txq_coalesce(struct qed_hwfn *p_hwfn,
+                        struct qed_ptt *p_ptt,
+                        u16 coalesce, struct qed_queue_cid *p_cid);
+
+int qed_get_rxq_coalesce(struct qed_hwfn *p_hwfn,
+                        struct qed_ptt *p_ptt,
+                        struct qed_queue_cid *p_cid, u16 *p_hw_coal);
+
+int qed_get_txq_coalesce(struct qed_hwfn *p_hwfn,
+                        struct qed_ptt *p_ptt,
+                        struct qed_queue_cid *p_cid, u16 *p_hw_coal);
+
+#endif
index b113996..2783288 100644 (file)
@@ -954,9 +954,7 @@ static int qed_slowpath_start(struct qed_dev *cdev,
        struct qed_tunnel_info tunn_info;
        const u8 *data = NULL;
        struct qed_hwfn *hwfn;
-#ifdef CONFIG_RFS_ACCEL
        struct qed_ptt *p_ptt;
-#endif
        int rc = -EINVAL;
 
        if (qed_iov_wq_start(cdev))
@@ -972,7 +970,6 @@ static int qed_slowpath_start(struct qed_dev *cdev,
                        goto err;
                }
 
-#ifdef CONFIG_RFS_ACCEL
                if (cdev->num_hwfns == 1) {
                        p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev));
                        if (p_ptt) {
@@ -983,7 +980,6 @@ static int qed_slowpath_start(struct qed_dev *cdev,
                                goto err;
                        }
                }
-#endif
        }
 
        cdev->rx_coalesce_usecs = QED_DEFAULT_RX_USECS;
@@ -1091,12 +1087,10 @@ err:
        if (IS_PF(cdev))
                release_firmware(cdev->firmware);
 
-#ifdef CONFIG_RFS_ACCEL
        if (IS_PF(cdev) && (cdev->num_hwfns == 1) &&
            QED_LEADING_HWFN(cdev)->p_arfs_ptt)
                qed_ptt_release(QED_LEADING_HWFN(cdev),
                                QED_LEADING_HWFN(cdev)->p_arfs_ptt);
-#endif
 
        qed_iov_wq_stop(cdev, false);
 
@@ -1111,11 +1105,9 @@ static int qed_slowpath_stop(struct qed_dev *cdev)
        qed_ll2_dealloc_if(cdev);
 
        if (IS_PF(cdev)) {
-#ifdef CONFIG_RFS_ACCEL
                if (cdev->num_hwfns == 1)
                        qed_ptt_release(QED_LEADING_HWFN(cdev),
                                        QED_LEADING_HWFN(cdev)->p_arfs_ptt);
-#endif
                qed_free_stream_mem(cdev);
                if (IS_QED_ETH_IF(cdev))
                        qed_sriov_disable(cdev, true);
@@ -1305,6 +1297,10 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params)
                }
        }
 
+       if (params->override_flags & QED_LINK_OVERRIDE_EEE_CONFIG)
+               memcpy(&link_params->eee, &params->eee,
+                      sizeof(link_params->eee));
+
        rc = qed_mcp_set_link(hwfn, ptt, params->link_up);
 
        qed_ptt_release(hwfn, ptt);
@@ -1491,6 +1487,21 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
        if (link.partner_adv_pause == QED_LINK_PARTNER_ASYMMETRIC_PAUSE ||
            link.partner_adv_pause == QED_LINK_PARTNER_BOTH_PAUSE)
                if_link->lp_caps |= QED_LM_Asym_Pause_BIT;
+
+       if (link_caps.default_eee == QED_MCP_EEE_UNSUPPORTED) {
+               if_link->eee_supported = false;
+       } else {
+               if_link->eee_supported = true;
+               if_link->eee_active = link.eee_active;
+               if_link->sup_caps = link_caps.eee_speed_caps;
+               /* MFW clears adv_caps on eee disable; use configured value */
+               if_link->eee.adv_caps = link.eee_adv_caps ? link.eee_adv_caps :
+                                       params.eee.adv_caps;
+               if_link->eee.lp_adv_caps = link.eee_lp_adv_caps;
+               if_link->eee.enable = params.eee.enable;
+               if_link->eee.tx_lpi_enable = params.eee.tx_lpi_enable;
+               if_link->eee.tx_lpi_timer = params.eee.tx_lpi_timer;
+       }
 }
 
 static void qed_get_current_link(struct qed_dev *cdev,
@@ -1557,36 +1568,10 @@ static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type,
        return rc;
 }
 
-static void qed_get_coalesce(struct qed_dev *cdev, u16 *rx_coal, u16 *tx_coal)
-{
-       *rx_coal = cdev->rx_coalesce_usecs;
-       *tx_coal = cdev->tx_coalesce_usecs;
-}
-
 static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal,
-                           u16 qid, u16 sb_id)
+                           void *handle)
 {
-       struct qed_hwfn *hwfn;
-       struct qed_ptt *ptt;
-       int hwfn_index;
-       int status = 0;
-
-       hwfn_index = qid % cdev->num_hwfns;
-       hwfn = &cdev->hwfns[hwfn_index];
-       ptt = qed_ptt_acquire(hwfn);
-       if (!ptt)
-               return -EAGAIN;
-
-       status = qed_set_rxq_coalesce(hwfn, ptt, rx_coal,
-                                     qid / cdev->num_hwfns, sb_id);
-       if (status)
-               goto out;
-       status = qed_set_txq_coalesce(hwfn, ptt, tx_coal,
-                                     qid / cdev->num_hwfns, sb_id);
-out:
-       qed_ptt_release(hwfn, ptt);
-
-       return status;
+               return qed_set_queue_coalesce(rx_coal, tx_coal, handle);
 }
 
 static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode)
@@ -1735,7 +1720,6 @@ const struct qed_common_ops qed_common_ops_pass = {
        .chain_alloc = &qed_chain_alloc,
        .chain_free = &qed_chain_free,
        .nvm_get_image = &qed_nvm_get_image,
-       .get_coalesce = &qed_get_coalesce,
        .set_coalesce = &qed_set_coalesce,
        .set_led = &qed_set_led,
        .update_drv_state = &qed_update_drv_state,
index 9da9104..c1ecce6 100644 (file)
@@ -1097,6 +1097,31 @@ static void qed_mcp_handle_transceiver_change(struct qed_hwfn *p_hwfn,
                DP_NOTICE(p_hwfn, "Transceiver is unplugged.\n");
 }
 
+static void qed_mcp_read_eee_config(struct qed_hwfn *p_hwfn,
+                                   struct qed_ptt *p_ptt,
+                                   struct qed_mcp_link_state *p_link)
+{
+       u32 eee_status, val;
+
+       p_link->eee_adv_caps = 0;
+       p_link->eee_lp_adv_caps = 0;
+       eee_status = qed_rd(p_hwfn,
+                           p_ptt,
+                           p_hwfn->mcp_info->port_addr +
+                           offsetof(struct public_port, eee_status));
+       p_link->eee_active = !!(eee_status & EEE_ACTIVE_BIT);
+       val = (eee_status & EEE_LD_ADV_STATUS_MASK) >> EEE_LD_ADV_STATUS_OFFSET;
+       if (val & EEE_1G_ADV)
+               p_link->eee_adv_caps |= QED_EEE_1G_ADV;
+       if (val & EEE_10G_ADV)
+               p_link->eee_adv_caps |= QED_EEE_10G_ADV;
+       val = (eee_status & EEE_LP_ADV_STATUS_MASK) >> EEE_LP_ADV_STATUS_OFFSET;
+       if (val & EEE_1G_ADV)
+               p_link->eee_lp_adv_caps |= QED_EEE_1G_ADV;
+       if (val & EEE_10G_ADV)
+               p_link->eee_lp_adv_caps |= QED_EEE_10G_ADV;
+}
+
 static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn,
                                       struct qed_ptt *p_ptt, bool b_reset)
 {
@@ -1228,6 +1253,9 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn,
 
        p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT);
 
+       if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE)
+               qed_mcp_read_eee_config(p_hwfn, p_ptt, p_link);
+
        qed_link_update(p_hwfn);
 out:
        spin_unlock_bh(&p_hwfn->mcp_info->link_lock);
@@ -1251,6 +1279,19 @@ int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up)
        phy_cfg.pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0;
        phy_cfg.adv_speed = params->speed.advertised_speeds;
        phy_cfg.loopback_mode = params->loopback_mode;
+       if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) {
+               if (params->eee.enable)
+                       phy_cfg.eee_cfg |= EEE_CFG_EEE_ENABLED;
+               if (params->eee.tx_lpi_enable)
+                       phy_cfg.eee_cfg |= EEE_CFG_TX_LPI;
+               if (params->eee.adv_caps & QED_EEE_1G_ADV)
+                       phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_1G;
+               if (params->eee.adv_caps & QED_EEE_10G_ADV)
+                       phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_10G;
+               phy_cfg.eee_cfg |= (params->eee.tx_lpi_timer <<
+                                   EEE_TX_TIMER_USEC_OFFSET) &
+                                  EEE_TX_TIMER_USEC_MASK;
+       }
 
        p_hwfn->b_drv_link_init = b_up;
 
@@ -2822,3 +2863,28 @@ void qed_mcp_resc_lock_default_init(struct qed_resc_lock_params *p_lock,
                p_unlock->resource = resource;
        }
 }
+
+int qed_mcp_get_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
+{
+       u32 mcp_resp;
+       int rc;
+
+       rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GET_MFW_FEATURE_SUPPORT,
+                        0, &mcp_resp, &p_hwfn->mcp_info->capabilities);
+       if (!rc)
+               DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_PROBE),
+                          "MFW supported features: %08x\n",
+                          p_hwfn->mcp_info->capabilities);
+
+       return rc;
+}
+
+int qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
+{
+       u32 mcp_resp, mcp_param, features;
+
+       features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE;
+
+       return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT,
+                          features, &mcp_resp, &mcp_param);
+}
index af03b36..c7ec239 100644 (file)
@@ -53,15 +53,25 @@ struct qed_mcp_link_pause_params {
        bool    forced_tx;
 };
 
+enum qed_mcp_eee_mode {
+       QED_MCP_EEE_DISABLED,
+       QED_MCP_EEE_ENABLED,
+       QED_MCP_EEE_UNSUPPORTED
+};
+
 struct qed_mcp_link_params {
-       struct qed_mcp_link_speed_params        speed;
-       struct qed_mcp_link_pause_params        pause;
-       u32                                  loopback_mode;
+       struct qed_mcp_link_speed_params speed;
+       struct qed_mcp_link_pause_params pause;
+       u32 loopback_mode;
+       struct qed_link_eee_params eee;
 };
 
 struct qed_mcp_link_capabilities {
        u32 speed_capabilities;
        bool default_speed_autoneg;
+       enum qed_mcp_eee_mode default_eee;
+       u32 eee_lpi_timer;
+       u8 eee_speed_caps;
 };
 
 struct qed_mcp_link_state {
@@ -102,6 +112,9 @@ struct qed_mcp_link_state {
        u8      partner_adv_pause;
 
        bool    sfp_tx_fault;
+       bool    eee_active;
+       u8      eee_adv_caps;
+       u8      eee_lp_adv_caps;
 };
 
 struct qed_mcp_function_info {
@@ -546,6 +559,9 @@ struct qed_mcp_info {
        u8                                      *mfw_mb_shadow;
        u16                                     mfw_mb_length;
        u32                                     mcp_hist;
+
+       /* Capabilties negotiated with the MFW */
+       u32                                     capabilities;
 };
 
 struct qed_mcp_mb_params {
@@ -925,5 +941,20 @@ void qed_mcp_resc_lock_default_init(struct qed_resc_lock_params *p_lock,
                                    struct qed_resc_unlock_params *p_unlock,
                                    enum qed_resc_lock
                                    resource, bool b_is_permanent);
+/**
+ * @brief Learn of supported MFW features; To be done during early init
+ *
+ * @param p_hwfn
+ * @param p_ptt
+ */
+int qed_mcp_get_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
 
+/**
+ * @brief Inform MFW of set of features supported by driver. Should be done
+ * inside the content of the LOAD_REQ.
+ *
+ * @param p_hwfn
+ * @param p_ptt
+ */
+int qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
 #endif
index 2cfd3bd..3f40b1d 100644 (file)
@@ -3400,6 +3400,157 @@ static void qed_iov_vf_mbx_release(struct qed_hwfn *p_hwfn,
                             length, status);
 }
 
+static void qed_iov_vf_pf_get_coalesce(struct qed_hwfn *p_hwfn,
+                                      struct qed_ptt *p_ptt,
+                                      struct qed_vf_info *p_vf)
+{
+       struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx;
+       struct pfvf_read_coal_resp_tlv *p_resp;
+       struct vfpf_read_coal_req_tlv *req;
+       u8 status = PFVF_STATUS_FAILURE;
+       struct qed_vf_queue *p_queue;
+       struct qed_queue_cid *p_cid;
+       u16 coal = 0, qid, i;
+       bool b_is_rx;
+       int rc = 0;
+
+       mbx->offset = (u8 *)mbx->reply_virt;
+       req = &mbx->req_virt->read_coal_req;
+
+       qid = req->qid;
+       b_is_rx = req->is_rx ? true : false;
+
+       if (b_is_rx) {
+               if (!qed_iov_validate_rxq(p_hwfn, p_vf, qid,
+                                         QED_IOV_VALIDATE_Q_ENABLE)) {
+                       DP_VERBOSE(p_hwfn, QED_MSG_IOV,
+                                  "VF[%d]: Invalid Rx queue_id = %d\n",
+                                  p_vf->abs_vf_id, qid);
+                       goto send_resp;
+               }
+
+               p_cid = qed_iov_get_vf_rx_queue_cid(&p_vf->vf_queues[qid]);
+               rc = qed_get_rxq_coalesce(p_hwfn, p_ptt, p_cid, &coal);
+               if (rc)
+                       goto send_resp;
+       } else {
+               if (!qed_iov_validate_txq(p_hwfn, p_vf, qid,
+                                         QED_IOV_VALIDATE_Q_ENABLE)) {
+                       DP_VERBOSE(p_hwfn, QED_MSG_IOV,
+                                  "VF[%d]: Invalid Tx queue_id = %d\n",
+                                  p_vf->abs_vf_id, qid);
+                       goto send_resp;
+               }
+               for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) {
+                       p_queue = &p_vf->vf_queues[qid];
+                       if ((!p_queue->cids[i].p_cid) ||
+                           (!p_queue->cids[i].b_is_tx))
+                               continue;
+
+                       p_cid = p_queue->cids[i].p_cid;
+
+                       rc = qed_get_txq_coalesce(p_hwfn, p_ptt, p_cid, &coal);
+                       if (rc)
+                               goto send_resp;
+                       break;
+               }
+       }
+
+       status = PFVF_STATUS_SUCCESS;
+
+send_resp:
+       p_resp = qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_COALESCE_READ,
+                            sizeof(*p_resp));
+       p_resp->coal = coal;
+
+       qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_LIST_END,
+                   sizeof(struct channel_list_end_tlv));
+
+       qed_iov_send_response(p_hwfn, p_ptt, p_vf, sizeof(*p_resp), status);
+}
+
+static void qed_iov_vf_pf_set_coalesce(struct qed_hwfn *p_hwfn,
+                                      struct qed_ptt *p_ptt,
+                                      struct qed_vf_info *vf)
+{
+       struct qed_iov_vf_mbx *mbx = &vf->vf_mbx;
+       struct vfpf_update_coalesce *req;
+       u8 status = PFVF_STATUS_FAILURE;
+       struct qed_queue_cid *p_cid;
+       u16 rx_coal, tx_coal;
+       int rc = 0, i;
+       u16 qid;
+
+       req = &mbx->req_virt->update_coalesce;
+
+       rx_coal = req->rx_coal;
+       tx_coal = req->tx_coal;
+       qid = req->qid;
+
+       if (!qed_iov_validate_rxq(p_hwfn, vf, qid,
+                                 QED_IOV_VALIDATE_Q_ENABLE) && rx_coal) {
+               DP_VERBOSE(p_hwfn, QED_MSG_IOV,
+                          "VF[%d]: Invalid Rx queue_id = %d\n",
+                          vf->abs_vf_id, qid);
+               goto out;
+       }
+
+       if (!qed_iov_validate_txq(p_hwfn, vf, qid,
+                                 QED_IOV_VALIDATE_Q_ENABLE) && tx_coal) {
+               DP_VERBOSE(p_hwfn, QED_MSG_IOV,
+                          "VF[%d]: Invalid Tx queue_id = %d\n",
+                          vf->abs_vf_id, qid);
+               goto out;
+       }
+
+       DP_VERBOSE(p_hwfn,
+                  QED_MSG_IOV,
+                  "VF[%d]: Setting coalesce for VF rx_coal = %d, tx_coal = %d at queue = %d\n",
+                  vf->abs_vf_id, rx_coal, tx_coal, qid);
+
+       if (rx_coal) {
+               p_cid = qed_iov_get_vf_rx_queue_cid(&vf->vf_queues[qid]);
+
+               rc = qed_set_rxq_coalesce(p_hwfn, p_ptt, rx_coal, p_cid);
+               if (rc) {
+                       DP_VERBOSE(p_hwfn,
+                                  QED_MSG_IOV,
+                                  "VF[%d]: Unable to set rx queue = %d coalesce\n",
+                                  vf->abs_vf_id, vf->vf_queues[qid].fw_rx_qid);
+                       goto out;
+               }
+               vf->rx_coal = rx_coal;
+       }
+
+       if (tx_coal) {
+               struct qed_vf_queue *p_queue = &vf->vf_queues[qid];
+
+               for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) {
+                       if (!p_queue->cids[i].p_cid)
+                               continue;
+
+                       if (!p_queue->cids[i].b_is_tx)
+                               continue;
+
+                       rc = qed_set_txq_coalesce(p_hwfn, p_ptt, tx_coal,
+                                                 p_queue->cids[i].p_cid);
+
+                       if (rc) {
+                               DP_VERBOSE(p_hwfn,
+                                          QED_MSG_IOV,
+                                          "VF[%d]: Unable to set tx queue coalesce\n",
+                                          vf->abs_vf_id);
+                               goto out;
+                       }
+               }
+               vf->tx_coal = tx_coal;
+       }
+
+       status = PFVF_STATUS_SUCCESS;
+out:
+       qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_COALESCE_UPDATE,
+                            sizeof(struct pfvf_def_resp_tlv), status);
+}
 static int
 qed_iov_vf_flr_poll_dorq(struct qed_hwfn *p_hwfn,
                         struct qed_vf_info *p_vf, struct qed_ptt *p_ptt)
@@ -3725,6 +3876,12 @@ static void qed_iov_process_mbx_req(struct qed_hwfn *p_hwfn,
                case CHANNEL_TLV_UPDATE_TUNN_PARAM:
                        qed_iov_vf_mbx_update_tunn_param(p_hwfn, p_ptt, p_vf);
                        break;
+               case CHANNEL_TLV_COALESCE_UPDATE:
+                       qed_iov_vf_pf_set_coalesce(p_hwfn, p_ptt, p_vf);
+                       break;
+               case CHANNEL_TLV_COALESCE_READ:
+                       qed_iov_vf_pf_get_coalesce(p_hwfn, p_ptt, p_vf);
+                       break;
                }
        } else if (qed_iov_tlv_supported(mbx->first_tlv.tl.type)) {
                DP_VERBOSE(p_hwfn, QED_MSG_IOV,
index c2e44bc..3955929 100644 (file)
@@ -217,6 +217,9 @@ struct qed_vf_info {
        u8 num_rxqs;
        u8 num_txqs;
 
+       u16 rx_coal;
+       u16 tx_coal;
+
        u8 num_sbs;
 
        u8 num_mac_filters;
index 1926d1e..91b5e9f 100644 (file)
@@ -1343,6 +1343,81 @@ exit:
        return rc;
 }
 
+int qed_vf_pf_get_coalesce(struct qed_hwfn *p_hwfn,
+                          u16 *p_coal, struct qed_queue_cid *p_cid)
+{
+       struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
+       struct pfvf_read_coal_resp_tlv *resp;
+       struct vfpf_read_coal_req_tlv *req;
+       int rc;
+
+       /* clear mailbox and prep header tlv */
+       req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_COALESCE_READ, sizeof(*req));
+       req->qid = p_cid->rel.queue_id;
+       req->is_rx = p_cid->b_is_rx ? 1 : 0;
+
+       qed_add_tlv(p_hwfn, &p_iov->offset, CHANNEL_TLV_LIST_END,
+                   sizeof(struct channel_list_end_tlv));
+       resp = &p_iov->pf2vf_reply->read_coal_resp;
+
+       rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+       if (rc)
+               goto exit;
+
+       if (resp->hdr.status != PFVF_STATUS_SUCCESS)
+               goto exit;
+
+       *p_coal = resp->coal;
+exit:
+       qed_vf_pf_req_end(p_hwfn, rc);
+
+       return rc;
+}
+
+int
+qed_vf_pf_set_coalesce(struct qed_hwfn *p_hwfn,
+                      u16 rx_coal, u16 tx_coal, struct qed_queue_cid *p_cid)
+{
+       struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
+       struct vfpf_update_coalesce *req;
+       struct pfvf_def_resp_tlv *resp;
+       int rc;
+
+       /* clear mailbox and prep header tlv */
+       req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_COALESCE_UPDATE, sizeof(*req));
+
+       req->rx_coal = rx_coal;
+       req->tx_coal = tx_coal;
+       req->qid = p_cid->rel.queue_id;
+
+       DP_VERBOSE(p_hwfn,
+                  QED_MSG_IOV,
+                  "Setting coalesce rx_coal = %d, tx_coal = %d at queue = %d\n",
+                  rx_coal, tx_coal, req->qid);
+
+       /* add list termination tlv */
+       qed_add_tlv(p_hwfn, &p_iov->offset, CHANNEL_TLV_LIST_END,
+                   sizeof(struct channel_list_end_tlv));
+
+       resp = &p_iov->pf2vf_reply->default_resp;
+       rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+       if (rc)
+               goto exit;
+
+       if (resp->hdr.status != PFVF_STATUS_SUCCESS)
+               goto exit;
+
+       if (rx_coal)
+               p_hwfn->cdev->rx_coalesce_usecs = rx_coal;
+
+       if (tx_coal)
+               p_hwfn->cdev->tx_coalesce_usecs = tx_coal;
+
+exit:
+       qed_vf_pf_req_end(p_hwfn, rc);
+       return rc;
+}
+
 u16 qed_vf_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id)
 {
        struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
index 34d9b88..97d44df 100644 (file)
@@ -497,6 +497,27 @@ struct tlv_buffer_size {
        u8 tlv_buffer[TLV_BUFFER_SIZE];
 };
 
+struct vfpf_update_coalesce {
+       struct vfpf_first_tlv first_tlv;
+       u16 rx_coal;
+       u16 tx_coal;
+       u16 qid;
+       u8 padding[2];
+};
+
+struct vfpf_read_coal_req_tlv {
+       struct vfpf_first_tlv first_tlv;
+       u16 qid;
+       u8 is_rx;
+       u8 padding[5];
+};
+
+struct pfvf_read_coal_resp_tlv {
+       struct pfvf_tlv hdr;
+       u16 coal;
+       u8 padding[6];
+};
+
 union vfpf_tlvs {
        struct vfpf_first_tlv first_tlv;
        struct vfpf_acquire_tlv acquire;
@@ -509,7 +530,8 @@ union vfpf_tlvs {
        struct vfpf_vport_update_tlv vport_update;
        struct vfpf_ucast_filter_tlv ucast_filter;
        struct vfpf_update_tunn_param_tlv tunn_param_update;
-       struct channel_list_end_tlv list_end;
+       struct vfpf_update_coalesce update_coalesce;
+       struct vfpf_read_coal_req_tlv read_coal_req;
        struct tlv_buffer_size tlv_buf_size;
 };
 
@@ -519,6 +541,7 @@ union pfvf_tlvs {
        struct tlv_buffer_size tlv_buf_size;
        struct pfvf_start_queue_resp_tlv queue_start;
        struct pfvf_update_tunn_param_tlv tunn_param_resp;
+       struct pfvf_read_coal_resp_tlv read_coal_resp;
 };
 
 enum qed_bulletin_bit {
@@ -624,8 +647,9 @@ enum {
        CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN,
        CHANNEL_TLV_VPORT_UPDATE_SGE_TPA,
        CHANNEL_TLV_UPDATE_TUNN_PARAM,
-       CHANNEL_TLV_RESERVED,
+       CHANNEL_TLV_COALESCE_UPDATE,
        CHANNEL_TLV_QID,
+       CHANNEL_TLV_COALESCE_READ,
        CHANNEL_TLV_MAX,
 
        /* Required for iterating over vport-update tlvs.
@@ -677,6 +701,31 @@ struct qed_vf_iov {
        bool b_doorbell_bar;
 };
 
+/**
+ * @brief VF - Set Rx/Tx coalesce per VF's relative queue.
+ *             Coalesce value '0' will omit the configuration.
+ *
+ * @param p_hwfn
+ * @param rx_coal - coalesce value in micro second for rx queue
+ * @param tx_coal - coalesce value in micro second for tx queue
+ * @param p_cid   - queue cid
+ *
+ **/
+int qed_vf_pf_set_coalesce(struct qed_hwfn *p_hwfn,
+                          u16 rx_coal,
+                          u16 tx_coal, struct qed_queue_cid *p_cid);
+
+/**
+ * @brief VF - Get coalesce per VF's relative queue.
+ *
+ * @param p_hwfn
+ * @param p_coal - coalesce value in micro second for VF queues.
+ * @param p_cid  - queue cid
+ *
+ **/
+int qed_vf_pf_get_coalesce(struct qed_hwfn *p_hwfn,
+                          u16 *p_coal, struct qed_queue_cid *p_cid);
+
 #ifdef CONFIG_QED_SRIOV
 /**
  * @brief Read the VF bulletin and act on it if needed
index 4dfb238..adb7005 100644 (file)
@@ -160,6 +160,8 @@ struct qede_rdma_dev {
 
 struct qede_ptp;
 
+#define QEDE_RFS_MAX_FLTR      256
+
 struct qede_dev {
        struct qed_dev                  *cdev;
        struct net_device               *ndev;
@@ -241,9 +243,7 @@ struct qede_dev {
        u16                             vxlan_dst_port;
        u16                             geneve_dst_port;
 
-#ifdef CONFIG_RFS_ACCEL
        struct qede_arfs                *arfs;
-#endif
        bool                            wol_enabled;
 
        struct qede_rdma_dev            rdma_info;
@@ -447,16 +447,21 @@ struct qede_fastpath {
 #ifdef CONFIG_RFS_ACCEL
 int qede_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
                       u16 rxq_index, u32 flow_id);
+#define QEDE_SP_ARFS_CONFIG    4
+#define QEDE_SP_TASK_POLL_DELAY        (5 * HZ)
+#endif
+
 void qede_process_arfs_filters(struct qede_dev *edev, bool free_fltr);
 void qede_poll_for_freeing_arfs_filters(struct qede_dev *edev);
 void qede_arfs_filter_op(void *dev, void *filter, u8 fw_rc);
 void qede_free_arfs(struct qede_dev *edev);
 int qede_alloc_arfs(struct qede_dev *edev);
-
-#define QEDE_SP_ARFS_CONFIG    4
-#define QEDE_SP_TASK_POLL_DELAY        (5 * HZ)
-#define QEDE_RFS_MAX_FLTR      256
-#endif
+int qede_add_cls_rule(struct qede_dev *edev, struct ethtool_rxnfc *info);
+int qede_del_cls_rule(struct qede_dev *edev, struct ethtool_rxnfc *info);
+int qede_get_cls_rule_entry(struct qede_dev *edev, struct ethtool_rxnfc *cmd);
+int qede_get_cls_rule_all(struct qede_dev *edev, struct ethtool_rxnfc *info,
+                         u32 *rule_locs);
+int qede_get_arfs_filter_count(struct qede_dev *edev);
 
 struct qede_reload_args {
        void (*func)(struct qede_dev *edev, struct qede_reload_args *args);
index 6a03d3e..dae7412 100644 (file)
@@ -702,24 +702,62 @@ static u32 qede_get_link(struct net_device *dev)
 static int qede_get_coalesce(struct net_device *dev,
                             struct ethtool_coalesce *coal)
 {
+       void *rx_handle = NULL, *tx_handle = NULL;
        struct qede_dev *edev = netdev_priv(dev);
-       u16 rxc, txc;
+       u16 rx_coal, tx_coal, i, rc = 0;
+       struct qede_fastpath *fp;
+
+       rx_coal = QED_DEFAULT_RX_USECS;
+       tx_coal = QED_DEFAULT_TX_USECS;
 
        memset(coal, 0, sizeof(struct ethtool_coalesce));
-       edev->ops->common->get_coalesce(edev->cdev, &rxc, &txc);
 
-       coal->rx_coalesce_usecs = rxc;
-       coal->tx_coalesce_usecs = txc;
+       __qede_lock(edev);
+       if (edev->state == QEDE_STATE_OPEN) {
+               for_each_queue(i) {
+                       fp = &edev->fp_array[i];
 
-       return 0;
+                       if (fp->type & QEDE_FASTPATH_RX) {
+                               rx_handle = fp->rxq->handle;
+                               break;
+                       }
+               }
+
+               rc = edev->ops->get_coalesce(edev->cdev, &rx_coal, rx_handle);
+               if (rc) {
+                       DP_INFO(edev, "Read Rx coalesce error\n");
+                       goto out;
+               }
+
+               for_each_queue(i) {
+                       fp = &edev->fp_array[i];
+                       if (fp->type & QEDE_FASTPATH_TX) {
+                               tx_handle = fp->txq->handle;
+                               break;
+                       }
+               }
+
+               rc = edev->ops->get_coalesce(edev->cdev, &tx_coal, tx_handle);
+               if (rc)
+                       DP_INFO(edev, "Read Tx coalesce error\n");
+       }
+
+out:
+       __qede_unlock(edev);
+
+       coal->rx_coalesce_usecs = rx_coal;
+       coal->tx_coalesce_usecs = tx_coal;
+
+       return rc;
 }
 
 static int qede_set_coalesce(struct net_device *dev,
                             struct ethtool_coalesce *coal)
 {
        struct qede_dev *edev = netdev_priv(dev);
+       struct qede_fastpath *fp;
        int i, rc = 0;
-       u16 rxc, txc, sb_id;
+       u16 rxc, txc;
 
        if (!netif_running(dev)) {
                DP_INFO(edev, "Interface is down\n");
@@ -730,21 +768,36 @@ static int qede_set_coalesce(struct net_device *dev,
            coal->tx_coalesce_usecs > QED_COALESCE_MAX) {
                DP_INFO(edev,
                        "Can't support requested %s coalesce value [max supported value %d]\n",
-                       coal->rx_coalesce_usecs > QED_COALESCE_MAX ? "rx"
-                                                                  : "tx",
-                       QED_COALESCE_MAX);
+                       coal->rx_coalesce_usecs > QED_COALESCE_MAX ? "rx" :
+                       "tx", QED_COALESCE_MAX);
                return -EINVAL;
        }
 
        rxc = (u16)coal->rx_coalesce_usecs;
        txc = (u16)coal->tx_coalesce_usecs;
        for_each_queue(i) {
-               sb_id = edev->fp_array[i].sb_info->igu_sb_id;
-               rc = edev->ops->common->set_coalesce(edev->cdev, rxc, txc,
-                                                    (u16)i, sb_id);
-               if (rc) {
-                       DP_INFO(edev, "Set coalesce error, rc = %d\n", rc);
-                       return rc;
+               fp = &edev->fp_array[i];
+
+               if (edev->fp_array[i].type & QEDE_FASTPATH_RX) {
+                       rc = edev->ops->common->set_coalesce(edev->cdev,
+                                                            rxc, 0,
+                                                            fp->rxq->handle);
+                       if (rc) {
+                               DP_INFO(edev,
+                                       "Set RX coalesce error, rc = %d\n", rc);
+                               return rc;
+                       }
+               }
+
+               if (edev->fp_array[i].type & QEDE_FASTPATH_TX) {
+                       rc = edev->ops->common->set_coalesce(edev->cdev,
+                                                            0, txc,
+                                                            fp->txq->handle);
+                       if (rc) {
+                               DP_INFO(edev,
+                                       "Set TX coalesce error, rc = %d\n", rc);
+                               return rc;
+                       }
                }
        }
 
@@ -1045,20 +1098,34 @@ static int qede_get_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
 }
 
 static int qede_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
-                         u32 *rules __always_unused)
+                         u32 *rule_locs)
 {
        struct qede_dev *edev = netdev_priv(dev);
+       int rc = 0;
 
        switch (info->cmd) {
        case ETHTOOL_GRXRINGS:
                info->data = QEDE_RSS_COUNT(edev);
-               return 0;
+               break;
        case ETHTOOL_GRXFH:
-               return qede_get_rss_flags(edev, info);
+               rc = qede_get_rss_flags(edev, info);
+               break;
+       case ETHTOOL_GRXCLSRLCNT:
+               info->rule_cnt = qede_get_arfs_filter_count(edev);
+               info->data = QEDE_RFS_MAX_FLTR;
+               break;
+       case ETHTOOL_GRXCLSRULE:
+               rc = qede_get_cls_rule_entry(edev, info);
+               break;
+       case ETHTOOL_GRXCLSRLALL:
+               rc = qede_get_cls_rule_all(edev, info, rule_locs);
+               break;
        default:
                DP_ERR(edev, "Command parameters not supported\n");
-               return -EOPNOTSUPP;
+               rc = -EOPNOTSUPP;
        }
+
+       return rc;
 }
 
 static int qede_set_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
@@ -1168,14 +1235,24 @@ static int qede_set_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
 static int qede_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
 {
        struct qede_dev *edev = netdev_priv(dev);
+       int rc;
 
        switch (info->cmd) {
        case ETHTOOL_SRXFH:
-               return qede_set_rss_flags(edev, info);
+               rc = qede_set_rss_flags(edev, info);
+               break;
+       case ETHTOOL_SRXCLSRLINS:
+               rc = qede_add_cls_rule(edev, info);
+               break;
+       case ETHTOOL_SRXCLSRLDEL:
+               rc = qede_del_cls_rule(edev, info);
+               break;
        default:
                DP_INFO(edev, "Command parameters not supported\n");
-               return -EOPNOTSUPP;
+               rc = -EOPNOTSUPP;
        }
+
+       return rc;
 }
 
 static u32 qede_get_rxfh_indir_size(struct net_device *dev)
@@ -1607,6 +1684,87 @@ static int qede_get_tunable(struct net_device *dev,
        return 0;
 }
 
+static int qede_get_eee(struct net_device *dev, struct ethtool_eee *edata)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+       struct qed_link_output current_link;
+
+       memset(&current_link, 0, sizeof(current_link));
+       edev->ops->common->get_link(edev->cdev, &current_link);
+
+       if (!current_link.eee_supported) {
+               DP_INFO(edev, "EEE is not supported\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (current_link.eee.adv_caps & QED_EEE_1G_ADV)
+               edata->advertised = ADVERTISED_1000baseT_Full;
+       if (current_link.eee.adv_caps & QED_EEE_10G_ADV)
+               edata->advertised |= ADVERTISED_10000baseT_Full;
+       if (current_link.sup_caps & QED_EEE_1G_ADV)
+               edata->supported = ADVERTISED_1000baseT_Full;
+       if (current_link.sup_caps & QED_EEE_10G_ADV)
+               edata->supported |= ADVERTISED_10000baseT_Full;
+       if (current_link.eee.lp_adv_caps & QED_EEE_1G_ADV)
+               edata->lp_advertised = ADVERTISED_1000baseT_Full;
+       if (current_link.eee.lp_adv_caps & QED_EEE_10G_ADV)
+               edata->lp_advertised |= ADVERTISED_10000baseT_Full;
+
+       edata->tx_lpi_timer = current_link.eee.tx_lpi_timer;
+       edata->eee_enabled = current_link.eee.enable;
+       edata->tx_lpi_enabled = current_link.eee.tx_lpi_enable;
+       edata->eee_active = current_link.eee_active;
+
+       return 0;
+}
+
+static int qede_set_eee(struct net_device *dev, struct ethtool_eee *edata)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+       struct qed_link_output current_link;
+       struct qed_link_params params;
+
+       if (!edev->ops->common->can_link_change(edev->cdev)) {
+               DP_INFO(edev, "Link settings are not allowed to be changed\n");
+               return -EOPNOTSUPP;
+       }
+
+       memset(&current_link, 0, sizeof(current_link));
+       edev->ops->common->get_link(edev->cdev, &current_link);
+
+       if (!current_link.eee_supported) {
+               DP_INFO(edev, "EEE is not supported\n");
+               return -EOPNOTSUPP;
+       }
+
+       memset(&params, 0, sizeof(params));
+       params.override_flags |= QED_LINK_OVERRIDE_EEE_CONFIG;
+
+       if (!(edata->advertised & (ADVERTISED_1000baseT_Full |
+                                  ADVERTISED_10000baseT_Full)) ||
+           ((edata->advertised & (ADVERTISED_1000baseT_Full |
+                                  ADVERTISED_10000baseT_Full)) !=
+            edata->advertised)) {
+               DP_VERBOSE(edev, QED_MSG_DEBUG,
+                          "Invalid advertised capabilities %d\n",
+                          edata->advertised);
+               return -EINVAL;
+       }
+
+       if (edata->advertised & ADVERTISED_1000baseT_Full)
+               params.eee.adv_caps = QED_EEE_1G_ADV;
+       if (edata->advertised & ADVERTISED_10000baseT_Full)
+               params.eee.adv_caps |= QED_EEE_10G_ADV;
+       params.eee.enable = edata->eee_enabled;
+       params.eee.tx_lpi_enable = edata->tx_lpi_enabled;
+       params.eee.tx_lpi_timer = edata->tx_lpi_timer;
+
+       params.link_up = true;
+       edev->ops->common->set_link(edev->cdev, &params);
+
+       return 0;
+}
+
 static const struct ethtool_ops qede_ethtool_ops = {
        .get_link_ksettings = qede_get_link_ksettings,
        .set_link_ksettings = qede_set_link_ksettings,
@@ -1640,6 +1798,9 @@ static const struct ethtool_ops qede_ethtool_ops = {
        .get_channels = qede_get_channels,
        .set_channels = qede_set_channels,
        .self_test = qede_self_test,
+       .get_eee = qede_get_eee,
+       .set_eee = qede_set_eee,
+
        .get_tunable = qede_get_tunable,
        .set_tunable = qede_set_tunable,
 };
@@ -1650,6 +1811,8 @@ static const struct ethtool_ops qede_vf_ethtool_ops = {
        .get_msglevel = qede_get_msglevel,
        .set_msglevel = qede_set_msglevel,
        .get_link = qede_get_link,
+       .get_coalesce = qede_get_coalesce,
+       .set_coalesce = qede_set_coalesce,
        .get_ringparam = qede_get_ringparam,
        .set_ringparam = qede_set_ringparam,
        .get_strings = qede_get_strings,
index f939db5..f79e36e 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/qed/qed_if.h>
 #include "qede.h"
 
-#ifdef CONFIG_RFS_ACCEL
 struct qede_arfs_tuple {
        union {
                __be32 src_ipv4;
@@ -76,10 +75,12 @@ struct qede_arfs_fltr_node {
        u16 next_rxq_id;
        bool filter_op;
        bool used;
+       u8 fw_rc;
        struct hlist_node node;
 };
 
 struct qede_arfs {
+#define QEDE_ARFS_BUCKET_HEAD(edev, idx) (&(edev)->arfs->arfs_hl_head[idx])
 #define QEDE_ARFS_POLL_COUNT   100
 #define QEDE_RFS_FLW_BITSHIFT  (4)
 #define QEDE_RFS_FLW_MASK      ((1 << QEDE_RFS_FLW_BITSHIFT) - 1)
@@ -121,11 +122,56 @@ qede_free_arfs_filter(struct qede_dev *edev,  struct qede_arfs_fltr_node *fltr)
        kfree(fltr);
 }
 
+static int
+qede_enqueue_fltr_and_config_searcher(struct qede_dev *edev,
+                                     struct qede_arfs_fltr_node *fltr,
+                                     u16 bucket_idx)
+{
+       fltr->mapping = dma_map_single(&edev->pdev->dev, fltr->data,
+                                      fltr->buf_len, DMA_TO_DEVICE);
+       if (dma_mapping_error(&edev->pdev->dev, fltr->mapping)) {
+               DP_NOTICE(edev, "Failed to map DMA memory for rule\n");
+               qede_free_arfs_filter(edev, fltr);
+               return -ENOMEM;
+       }
+
+       INIT_HLIST_NODE(&fltr->node);
+       hlist_add_head(&fltr->node,
+                      QEDE_ARFS_BUCKET_HEAD(edev, bucket_idx));
+       edev->arfs->filter_count++;
+
+       if (edev->arfs->filter_count == 1 && !edev->arfs->enable) {
+               edev->ops->configure_arfs_searcher(edev->cdev, true);
+               edev->arfs->enable = true;
+       }
+
+       return 0;
+}
+
+static void
+qede_dequeue_fltr_and_config_searcher(struct qede_dev *edev,
+                                     struct qede_arfs_fltr_node *fltr)
+{
+       hlist_del(&fltr->node);
+       dma_unmap_single(&edev->pdev->dev, fltr->mapping,
+                        fltr->buf_len, DMA_TO_DEVICE);
+
+       qede_free_arfs_filter(edev, fltr);
+       edev->arfs->filter_count--;
+
+       if (!edev->arfs->filter_count && edev->arfs->enable) {
+               edev->arfs->enable = false;
+               edev->ops->configure_arfs_searcher(edev->cdev, false);
+       }
+}
+
 void qede_arfs_filter_op(void *dev, void *filter, u8 fw_rc)
 {
        struct qede_arfs_fltr_node *fltr = filter;
        struct qede_dev *edev = dev;
 
+       fltr->fw_rc = fw_rc;
+
        if (fw_rc) {
                DP_NOTICE(edev,
                          "Failed arfs filter configuration fw_rc=%d, flow_id=%d, sw_id=%d, src_port=%d, dst_port=%d, rxq=%d\n",
@@ -185,18 +231,17 @@ void qede_process_arfs_filters(struct qede_dev *edev, bool free_fltr)
 
                        if ((!test_bit(QEDE_FLTR_VALID, &fltr->state) &&
                             !fltr->used) || free_fltr) {
-                               hlist_del(&fltr->node);
-                               dma_unmap_single(&edev->pdev->dev,
-                                                fltr->mapping,
-                                                fltr->buf_len, DMA_TO_DEVICE);
-                               qede_free_arfs_filter(edev, fltr);
-                               edev->arfs->filter_count--;
+                               qede_dequeue_fltr_and_config_searcher(edev,
+                                                                     fltr);
                        } else {
-                               if ((rps_may_expire_flow(edev->ndev,
-                                                        fltr->rxq_id,
-                                                        fltr->flow_id,
-                                                        fltr->sw_id) || del) &&
-                                                        !free_fltr)
+                               bool flow_exp = false;
+#ifdef CONFIG_RFS_ACCEL
+                               flow_exp = rps_may_expire_flow(edev->ndev,
+                                                              fltr->rxq_id,
+                                                              fltr->flow_id,
+                                                              fltr->sw_id);
+#endif
+                               if ((flow_exp || del) && !free_fltr)
                                        qede_configure_arfs_fltr(edev, fltr,
                                                                 fltr->rxq_id,
                                                                 false);
@@ -213,10 +258,12 @@ void qede_process_arfs_filters(struct qede_dev *edev, bool free_fltr)
                        edev->arfs->enable = false;
                        edev->ops->configure_arfs_searcher(edev->cdev, false);
                }
+#ifdef CONFIG_RFS_ACCEL
        } else {
                set_bit(QEDE_SP_ARFS_CONFIG, &edev->sp_flags);
                schedule_delayed_work(&edev->sp_task,
                                      QEDE_SP_TASK_POLL_DELAY);
+#endif
        }
 
        spin_unlock_bh(&edev->arfs->arfs_list_lock);
@@ -258,25 +305,26 @@ int qede_alloc_arfs(struct qede_dev *edev)
        spin_lock_init(&edev->arfs->arfs_list_lock);
 
        for (i = 0; i <= QEDE_RFS_FLW_MASK; i++)
-               INIT_HLIST_HEAD(&edev->arfs->arfs_hl_head[i]);
+               INIT_HLIST_HEAD(QEDE_ARFS_BUCKET_HEAD(edev, i));
 
-       edev->ndev->rx_cpu_rmap = alloc_irq_cpu_rmap(QEDE_RSS_COUNT(edev));
-       if (!edev->ndev->rx_cpu_rmap) {
+       edev->arfs->arfs_fltr_bmap = vzalloc(BITS_TO_LONGS(QEDE_RFS_MAX_FLTR) *
+                                            sizeof(long));
+       if (!edev->arfs->arfs_fltr_bmap) {
                vfree(edev->arfs);
                edev->arfs = NULL;
                return -ENOMEM;
        }
 
-       edev->arfs->arfs_fltr_bmap = vzalloc(BITS_TO_LONGS(QEDE_RFS_MAX_FLTR) *
-                                            sizeof(long));
-       if (!edev->arfs->arfs_fltr_bmap) {
-               free_irq_cpu_rmap(edev->ndev->rx_cpu_rmap);
-               edev->ndev->rx_cpu_rmap = NULL;
+#ifdef CONFIG_RFS_ACCEL
+       edev->ndev->rx_cpu_rmap = alloc_irq_cpu_rmap(QEDE_RSS_COUNT(edev));
+       if (!edev->ndev->rx_cpu_rmap) {
+               vfree(edev->arfs->arfs_fltr_bmap);
+               edev->arfs->arfs_fltr_bmap = NULL;
                vfree(edev->arfs);
                edev->arfs = NULL;
                return -ENOMEM;
        }
-
+#endif
        return 0;
 }
 
@@ -285,16 +333,19 @@ void qede_free_arfs(struct qede_dev *edev)
        if (!edev->arfs)
                return;
 
+#ifdef CONFIG_RFS_ACCEL
        if (edev->ndev->rx_cpu_rmap)
                free_irq_cpu_rmap(edev->ndev->rx_cpu_rmap);
 
        edev->ndev->rx_cpu_rmap = NULL;
+#endif
        vfree(edev->arfs->arfs_fltr_bmap);
        edev->arfs->arfs_fltr_bmap = NULL;
        vfree(edev->arfs);
        edev->arfs = NULL;
 }
 
+#ifdef CONFIG_RFS_ACCEL
 static bool qede_compare_ip_addr(struct qede_arfs_fltr_node *tpos,
                                 const struct sk_buff *skb)
 {
@@ -394,9 +445,8 @@ int qede_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
 
        spin_lock_bh(&edev->arfs->arfs_list_lock);
 
-       n = qede_arfs_htbl_key_search(&edev->arfs->arfs_hl_head[tbl_idx],
+       n = qede_arfs_htbl_key_search(QEDE_ARFS_BUCKET_HEAD(edev, tbl_idx),
                                      skb, ports[0], ports[1], ip_proto);
-
        if (n) {
                /* Filter match */
                n->next_rxq_id = rxq_index;
@@ -448,23 +498,9 @@ int qede_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
        n->tuple.ip_proto = ip_proto;
        memcpy(n->data + ETH_HLEN, skb->data, skb_headlen(skb));
 
-       n->mapping = dma_map_single(&edev->pdev->dev, n->data,
-                                   n->buf_len, DMA_TO_DEVICE);
-       if (dma_mapping_error(&edev->pdev->dev, n->mapping)) {
-               DP_NOTICE(edev, "Failed to map DMA memory for arfs\n");
-               qede_free_arfs_filter(edev, n);
-               rc = -ENOMEM;
+       rc = qede_enqueue_fltr_and_config_searcher(edev, n, tbl_idx);
+       if (rc)
                goto ret_unlock;
-       }
-
-       INIT_HLIST_NODE(&n->node);
-       hlist_add_head(&n->node, &edev->arfs->arfs_hl_head[tbl_idx]);
-       edev->arfs->filter_count++;
-
-       if (edev->arfs->filter_count == 1 && !edev->arfs->enable) {
-               edev->ops->configure_arfs_searcher(edev->cdev, true);
-               edev->arfs->enable = true;
-       }
 
        qede_configure_arfs_fltr(edev, n, n->rxq_id, true);
 
@@ -472,6 +508,7 @@ int qede_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
 
        set_bit(QEDE_SP_ARFS_CONFIG, &edev->sp_flags);
        schedule_delayed_work(&edev->sp_task, 0);
+
        return n->sw_id;
 
 ret_unlock:
@@ -1263,3 +1300,371 @@ void qede_config_rx_mode(struct net_device *ndev)
 out:
        kfree(uc_macs);
 }
+
+static struct qede_arfs_fltr_node *
+qede_get_arfs_fltr_by_loc(struct hlist_head *head, u32 location)
+{
+       struct qede_arfs_fltr_node *fltr;
+
+       hlist_for_each_entry(fltr, head, node)
+               if (location == fltr->sw_id)
+                       return fltr;
+
+       return NULL;
+}
+
+static bool
+qede_compare_user_flow_ips(struct qede_arfs_fltr_node *tpos,
+                          struct ethtool_rx_flow_spec *fsp,
+                          __be16 proto)
+{
+       if (proto == htons(ETH_P_IP)) {
+               struct ethtool_tcpip4_spec *ip;
+
+               ip = &fsp->h_u.tcp_ip4_spec;
+
+               if (tpos->tuple.src_ipv4 == ip->ip4src &&
+                   tpos->tuple.dst_ipv4 == ip->ip4dst)
+                       return true;
+               else
+                       return false;
+       } else {
+               struct ethtool_tcpip6_spec *ip6;
+               struct in6_addr *src;
+
+               ip6 = &fsp->h_u.tcp_ip6_spec;
+               src = &tpos->tuple.src_ipv6;
+
+               if (!memcmp(src, &ip6->ip6src, sizeof(struct in6_addr)) &&
+                   !memcmp(&tpos->tuple.dst_ipv6, &ip6->ip6dst,
+                           sizeof(struct in6_addr)))
+                       return true;
+               else
+                       return false;
+       }
+       return false;
+}
+
+int qede_get_cls_rule_all(struct qede_dev *edev, struct ethtool_rxnfc *info,
+                         u32 *rule_locs)
+{
+       struct qede_arfs_fltr_node *fltr;
+       struct hlist_head *head;
+       int cnt = 0, rc = 0;
+
+       info->data = QEDE_RFS_MAX_FLTR;
+
+       __qede_lock(edev);
+
+       if (!edev->arfs) {
+               rc = -EPERM;
+               goto unlock;
+       }
+
+       head = QEDE_ARFS_BUCKET_HEAD(edev, 0);
+
+       hlist_for_each_entry(fltr, head, node) {
+               if (cnt == info->rule_cnt) {
+                       rc = -EMSGSIZE;
+                       goto unlock;
+               }
+
+               rule_locs[cnt] = fltr->sw_id;
+               cnt++;
+       }
+
+       info->rule_cnt = cnt;
+
+unlock:
+       __qede_unlock(edev);
+       return rc;
+}
+
+int qede_get_cls_rule_entry(struct qede_dev *edev, struct ethtool_rxnfc *cmd)
+{
+       struct ethtool_rx_flow_spec *fsp = &cmd->fs;
+       struct qede_arfs_fltr_node *fltr = NULL;
+       int rc = 0;
+
+       cmd->data = QEDE_RFS_MAX_FLTR;
+
+       __qede_lock(edev);
+
+       if (!edev->arfs) {
+               rc = -EPERM;
+               goto unlock;
+       }
+
+       fltr = qede_get_arfs_fltr_by_loc(QEDE_ARFS_BUCKET_HEAD(edev, 0),
+                                        fsp->location);
+       if (!fltr) {
+               DP_NOTICE(edev, "Rule not found - location=0x%x\n",
+                         fsp->location);
+               rc = -EINVAL;
+               goto unlock;
+       }
+
+       if (fltr->tuple.eth_proto == htons(ETH_P_IP)) {
+               if (fltr->tuple.ip_proto == IPPROTO_TCP)
+                       fsp->flow_type = TCP_V4_FLOW;
+               else
+                       fsp->flow_type = UDP_V4_FLOW;
+
+               fsp->h_u.tcp_ip4_spec.psrc = fltr->tuple.src_port;
+               fsp->h_u.tcp_ip4_spec.pdst = fltr->tuple.dst_port;
+               fsp->h_u.tcp_ip4_spec.ip4src = fltr->tuple.src_ipv4;
+               fsp->h_u.tcp_ip4_spec.ip4dst = fltr->tuple.dst_ipv4;
+       } else {
+               if (fltr->tuple.ip_proto == IPPROTO_TCP)
+                       fsp->flow_type = TCP_V6_FLOW;
+               else
+                       fsp->flow_type = UDP_V6_FLOW;
+               fsp->h_u.tcp_ip6_spec.psrc = fltr->tuple.src_port;
+               fsp->h_u.tcp_ip6_spec.pdst = fltr->tuple.dst_port;
+               memcpy(&fsp->h_u.tcp_ip6_spec.ip6src,
+                      &fltr->tuple.src_ipv6, sizeof(struct in6_addr));
+               memcpy(&fsp->h_u.tcp_ip6_spec.ip6dst,
+                      &fltr->tuple.dst_ipv6, sizeof(struct in6_addr));
+       }
+
+       fsp->ring_cookie = fltr->rxq_id;
+
+unlock:
+       __qede_unlock(edev);
+       return rc;
+}
+
+static int
+qede_validate_and_check_flow_exist(struct qede_dev *edev,
+                                  struct ethtool_rx_flow_spec *fsp,
+                                  int *min_hlen)
+{
+       __be16 src_port = 0x0, dst_port = 0x0;
+       struct qede_arfs_fltr_node *fltr;
+       struct hlist_node *temp;
+       struct hlist_head *head;
+       __be16 eth_proto;
+       u8 ip_proto;
+
+       if (fsp->location >= QEDE_RFS_MAX_FLTR ||
+           fsp->ring_cookie >= QEDE_RSS_COUNT(edev))
+               return -EINVAL;
+
+       if (fsp->flow_type == TCP_V4_FLOW) {
+               *min_hlen += sizeof(struct iphdr) +
+                               sizeof(struct tcphdr);
+               eth_proto = htons(ETH_P_IP);
+               ip_proto = IPPROTO_TCP;
+       } else if (fsp->flow_type == UDP_V4_FLOW) {
+               *min_hlen += sizeof(struct iphdr) +
+                               sizeof(struct udphdr);
+               eth_proto = htons(ETH_P_IP);
+               ip_proto = IPPROTO_UDP;
+       } else if (fsp->flow_type == TCP_V6_FLOW) {
+               *min_hlen += sizeof(struct ipv6hdr) +
+                               sizeof(struct tcphdr);
+               eth_proto = htons(ETH_P_IPV6);
+               ip_proto = IPPROTO_TCP;
+       } else if (fsp->flow_type == UDP_V6_FLOW) {
+               *min_hlen += sizeof(struct ipv6hdr) +
+                               sizeof(struct udphdr);
+               eth_proto = htons(ETH_P_IPV6);
+               ip_proto = IPPROTO_UDP;
+       } else {
+               DP_NOTICE(edev, "Unsupported flow type = 0x%x\n",
+                         fsp->flow_type);
+               return -EPROTONOSUPPORT;
+       }
+
+       if (eth_proto == htons(ETH_P_IP)) {
+               src_port = fsp->h_u.tcp_ip4_spec.psrc;
+               dst_port = fsp->h_u.tcp_ip4_spec.pdst;
+       } else {
+               src_port = fsp->h_u.tcp_ip6_spec.psrc;
+               dst_port = fsp->h_u.tcp_ip6_spec.pdst;
+       }
+
+       head = QEDE_ARFS_BUCKET_HEAD(edev, 0);
+       hlist_for_each_entry_safe(fltr, temp, head, node) {
+               if ((fltr->tuple.ip_proto == ip_proto &&
+                    fltr->tuple.eth_proto == eth_proto &&
+                    qede_compare_user_flow_ips(fltr, fsp, eth_proto) &&
+                    fltr->tuple.src_port == src_port &&
+                    fltr->tuple.dst_port == dst_port) ||
+                   fltr->sw_id == fsp->location)
+                       return -EEXIST;
+       }
+
+       return 0;
+}
+
+static int
+qede_poll_arfs_filter_config(struct qede_dev *edev,
+                            struct qede_arfs_fltr_node *fltr)
+{
+       int count = QEDE_ARFS_POLL_COUNT;
+
+       while (fltr->used && count) {
+               msleep(20);
+               count--;
+       }
+
+       if (count == 0 || fltr->fw_rc) {
+               qede_dequeue_fltr_and_config_searcher(edev, fltr);
+               return -EIO;
+       }
+
+       return fltr->fw_rc;
+}
+
+int qede_add_cls_rule(struct qede_dev *edev, struct ethtool_rxnfc *info)
+{
+       struct ethtool_rx_flow_spec *fsp = &info->fs;
+       struct qede_arfs_fltr_node *n;
+       int min_hlen = ETH_HLEN, rc;
+       struct ethhdr *eth;
+       struct iphdr *ip;
+       __be16 *ports;
+
+       __qede_lock(edev);
+
+       if (!edev->arfs) {
+               rc = -EPERM;
+               goto unlock;
+       }
+
+       rc = qede_validate_and_check_flow_exist(edev, fsp, &min_hlen);
+       if (rc)
+               goto unlock;
+
+       n = kzalloc(sizeof(*n), GFP_KERNEL);
+       if (!n) {
+               rc = -ENOMEM;
+               goto unlock;
+       }
+
+       n->data = kzalloc(min_hlen, GFP_KERNEL);
+       if (!n->data) {
+               kfree(n);
+               rc = -ENOMEM;
+               goto unlock;
+       }
+
+       n->sw_id = fsp->location;
+       set_bit(n->sw_id, edev->arfs->arfs_fltr_bmap);
+       n->buf_len = min_hlen;
+       n->rxq_id = fsp->ring_cookie;
+       n->next_rxq_id = n->rxq_id;
+       eth = (struct ethhdr *)n->data;
+
+       if (info->fs.flow_type == TCP_V4_FLOW ||
+           info->fs.flow_type == UDP_V4_FLOW) {
+               ports = (__be16 *)(n->data + ETH_HLEN +
+                                       sizeof(struct iphdr));
+               eth->h_proto = htons(ETH_P_IP);
+               n->tuple.eth_proto = htons(ETH_P_IP);
+               n->tuple.src_ipv4 = info->fs.h_u.tcp_ip4_spec.ip4src;
+               n->tuple.dst_ipv4 = info->fs.h_u.tcp_ip4_spec.ip4dst;
+               n->tuple.src_port = info->fs.h_u.tcp_ip4_spec.psrc;
+               n->tuple.dst_port = info->fs.h_u.tcp_ip4_spec.pdst;
+               ports[0] = n->tuple.src_port;
+               ports[1] = n->tuple.dst_port;
+               ip = (struct iphdr *)(n->data + ETH_HLEN);
+               ip->saddr = info->fs.h_u.tcp_ip4_spec.ip4src;
+               ip->daddr = info->fs.h_u.tcp_ip4_spec.ip4dst;
+               ip->version = 0x4;
+               ip->ihl = 0x5;
+
+               if (info->fs.flow_type == TCP_V4_FLOW) {
+                       n->tuple.ip_proto = IPPROTO_TCP;
+                       ip->protocol = IPPROTO_TCP;
+               } else {
+                       n->tuple.ip_proto = IPPROTO_UDP;
+                       ip->protocol = IPPROTO_UDP;
+               }
+               ip->tot_len = cpu_to_be16(min_hlen - ETH_HLEN);
+       } else {
+               struct ipv6hdr *ip6;
+
+               ip6 = (struct ipv6hdr *)(n->data + ETH_HLEN);
+               ports = (__be16 *)(n->data + ETH_HLEN +
+                                       sizeof(struct ipv6hdr));
+               eth->h_proto = htons(ETH_P_IPV6);
+               n->tuple.eth_proto = htons(ETH_P_IPV6);
+               memcpy(&n->tuple.src_ipv6, &info->fs.h_u.tcp_ip6_spec.ip6src,
+                      sizeof(struct in6_addr));
+               memcpy(&n->tuple.dst_ipv6, &info->fs.h_u.tcp_ip6_spec.ip6dst,
+                      sizeof(struct in6_addr));
+               n->tuple.src_port = info->fs.h_u.tcp_ip6_spec.psrc;
+               n->tuple.dst_port = info->fs.h_u.tcp_ip6_spec.pdst;
+               ports[0] = n->tuple.src_port;
+               ports[1] = n->tuple.dst_port;
+               memcpy(&ip6->saddr, &n->tuple.src_ipv6,
+                      sizeof(struct in6_addr));
+               memcpy(&ip6->daddr, &n->tuple.dst_ipv6,
+                      sizeof(struct in6_addr));
+               ip6->version = 0x6;
+
+               if (info->fs.flow_type == TCP_V6_FLOW) {
+                       n->tuple.ip_proto = IPPROTO_TCP;
+                       ip6->nexthdr = NEXTHDR_TCP;
+                       ip6->payload_len = cpu_to_be16(sizeof(struct tcphdr));
+               } else {
+                       n->tuple.ip_proto = IPPROTO_UDP;
+                       ip6->nexthdr = NEXTHDR_UDP;
+                       ip6->payload_len = cpu_to_be16(sizeof(struct udphdr));
+               }
+       }
+
+       rc = qede_enqueue_fltr_and_config_searcher(edev, n, 0);
+       if (rc)
+               goto unlock;
+
+       qede_configure_arfs_fltr(edev, n, n->rxq_id, true);
+       rc = qede_poll_arfs_filter_config(edev, n);
+unlock:
+       __qede_unlock(edev);
+       return rc;
+}
+
+int qede_del_cls_rule(struct qede_dev *edev, struct ethtool_rxnfc *info)
+{
+       struct ethtool_rx_flow_spec *fsp = &info->fs;
+       struct qede_arfs_fltr_node *fltr = NULL;
+       int rc = -EPERM;
+
+       __qede_lock(edev);
+       if (!edev->arfs)
+               goto unlock;
+
+       fltr = qede_get_arfs_fltr_by_loc(QEDE_ARFS_BUCKET_HEAD(edev, 0),
+                                        fsp->location);
+       if (!fltr)
+               goto unlock;
+
+       qede_configure_arfs_fltr(edev, fltr, fltr->rxq_id, false);
+
+       rc = qede_poll_arfs_filter_config(edev, fltr);
+       if (rc == 0)
+               qede_dequeue_fltr_and_config_searcher(edev, fltr);
+
+unlock:
+       __qede_unlock(edev);
+       return rc;
+}
+
+int qede_get_arfs_filter_count(struct qede_dev *edev)
+{
+       int count = 0;
+
+       __qede_lock(edev);
+
+       if (!edev->arfs)
+               goto unlock;
+
+       count = edev->arfs->filter_count;
+
+unlock:
+       __qede_unlock(edev);
+       return count;
+}
index 06ca13d..e5ee9f2 100644 (file)
@@ -873,9 +873,7 @@ static void qede_update_pf_params(struct qed_dev *cdev)
         */
        pf_params.eth_pf_params.num_vf_cons = 48;
 
-#ifdef CONFIG_RFS_ACCEL
        pf_params.eth_pf_params.num_arfs_filters = QEDE_RFS_MAX_FLTR;
-#endif
        qed_ops->common->update_pf_params(cdev, &pf_params);
 }
 
@@ -1984,12 +1982,12 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode,
 
        qede_vlan_mark_nonconfigured(edev);
        edev->ops->fastpath_stop(edev->cdev);
-#ifdef CONFIG_RFS_ACCEL
+
        if (!IS_VF(edev) && edev->dev_info.common.num_hwfns == 1) {
                qede_poll_for_freeing_arfs_filters(edev);
                qede_free_arfs(edev);
        }
-#endif
+
        /* Release the interrupts */
        qede_sync_free_irqs(edev);
        edev->ops->common->set_fp_int(edev->cdev, 0);
@@ -2041,13 +2039,12 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode,
        if (rc)
                goto err2;
 
-#ifdef CONFIG_RFS_ACCEL
        if (!IS_VF(edev) && edev->dev_info.common.num_hwfns == 1) {
                rc = qede_alloc_arfs(edev);
                if (rc)
                        DP_NOTICE(edev, "aRFS memory allocation failed\n");
        }
-#endif
+
        qede_napi_add_enable(edev);
        DP_INFO(edev, "Napi added and enabled\n");
 
index 746d94e..60850bf 100644 (file)
@@ -766,11 +766,13 @@ static void emac_shutdown(struct platform_device *pdev)
        struct emac_adapter *adpt = netdev_priv(netdev);
        struct emac_sgmii *sgmii = &adpt->phy;
 
-       /* Closing the SGMII turns off its interrupts */
-       sgmii->close(adpt);
+       if (netdev->flags & IFF_UP) {
+               /* Closing the SGMII turns off its interrupts */
+               sgmii->close(adpt);
 
-       /* Resetting the MAC turns off all DMA and its interrupts */
-       emac_mac_reset(adpt);
+               /* Resetting the MAC turns off all DMA and its interrupts */
+               emac_mac_reset(adpt);
+       }
 }
 
 static struct platform_driver emac_platform_driver = {
index b607936..9c0488e 100644 (file)
@@ -90,17 +90,13 @@ struct ioc3_private {
        spinlock_t ioc3_lock;
        struct mii_if_info mii;
 
+       struct net_device *dev;
        struct pci_dev *pdev;
 
        /* Members used by autonegotiation  */
        struct timer_list ioc3_timer;
 };
 
-static inline struct net_device *priv_netdev(struct ioc3_private *dev)
-{
-       return (void *)dev - ((sizeof(struct net_device) + 31) & ~31);
-}
-
 static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void ioc3_set_multicast_list(struct net_device *dev);
 static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -427,7 +423,7 @@ static void ioc3_get_eaddr_nic(struct ioc3_private *ip)
                nic[i] = nic_read_byte(ioc3);
 
        for (i = 2; i < 8; i++)
-               priv_netdev(ip)->dev_addr[i - 2] = nic[i];
+               ip->dev->dev_addr[i - 2] = nic[i];
 }
 
 /*
@@ -439,7 +435,7 @@ static void ioc3_get_eaddr(struct ioc3_private *ip)
 {
        ioc3_get_eaddr_nic(ip);
 
-       printk("Ethernet address is %pM.\n", priv_netdev(ip)->dev_addr);
+       printk("Ethernet address is %pM.\n", ip->dev->dev_addr);
 }
 
 static void __ioc3_set_mac_address(struct net_device *dev)
@@ -790,13 +786,12 @@ static void ioc3_timer(unsigned long data)
  */
 static int ioc3_mii_init(struct ioc3_private *ip)
 {
-       struct net_device *dev = priv_netdev(ip);
        int i, found = 0, res = 0;
        int ioc3_phy_workaround = 1;
        u16 word;
 
        for (i = 0; i < 32; i++) {
-               word = ioc3_mdio_read(dev, i, MII_PHYSID1);
+               word = ioc3_mdio_read(ip->dev, i, MII_PHYSID1);
 
                if (word != 0xffff && word != 0x0000) {
                        found = 1;
@@ -1276,6 +1271,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        SET_NETDEV_DEV(dev, &pdev->dev);
 
        ip = netdev_priv(dev);
+       ip->dev = dev;
 
        dev->irq = pdev->irq;
 
index 22cf635..7ecf549 100644 (file)
@@ -205,7 +205,7 @@ static void dwmac1000_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space)
 {
        int i;
 
-       for (i = 0; i < 23; i++)
+       for (i = 0; i < NUM_DWMAC1000_DMA_REGS; i++)
                if ((i < 12) || (i > 17))
                        reg_space[DMA_BUS_MODE / 4 + i] =
                                readl(ioaddr + DMA_BUS_MODE + i * 4);
index eef2f22..6502b9a 100644 (file)
@@ -70,7 +70,7 @@ static void dwmac100_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space)
 {
        int i;
 
-       for (i = 0; i < 9; i++)
+       for (i = 0; i < NUM_DWMAC100_DMA_REGS; i++)
                reg_space[DMA_BUS_MODE / 4 + i] =
                        readl(ioaddr + DMA_BUS_MODE + i * 4);
 
index f233bf8..c4407e8 100644 (file)
@@ -117,7 +117,7 @@ static void dwmac4_tx_queue_routing(struct mac_device_info *hw,
        void __iomem *ioaddr = hw->pcsr;
        u32 value;
 
-       const struct stmmac_rx_routing route_possibilities[] = {
+       static const struct stmmac_rx_routing route_possibilities[] = {
                { GMAC_RXQCTRL_AVCPQ_MASK, GMAC_RXQCTRL_AVCPQ_SHIFT },
                { GMAC_RXQCTRL_PTPQ_MASK, GMAC_RXQCTRL_PTPQ_SHIFT },
                { GMAC_RXQCTRL_DCBCPQ_MASK, GMAC_RXQCTRL_DCBCPQ_SHIFT },
index 9091df8..adc5400 100644 (file)
 #define DMA_STATUS_TI  0x00000001      /* Transmit Interrupt */
 #define DMA_CONTROL_FTF                0x00100000      /* Flush transmit FIFO */
 
+#define NUM_DWMAC100_DMA_REGS  9
+#define NUM_DWMAC1000_DMA_REGS 23
+
 void dwmac_enable_dma_transmission(void __iomem *ioaddr);
 void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan);
 void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan);
index babb39c..af30b48 100644 (file)
@@ -33,6 +33,8 @@
 #define MAC100_ETHTOOL_NAME    "st_mac100"
 #define GMAC_ETHTOOL_NAME      "st_gmac"
 
+#define ETHTOOL_DMA_OFFSET     55
+
 struct stmmac_stats {
        char stat_string[ETH_GSTRING_LEN];
        int sizeof_stat;
@@ -442,6 +444,9 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
 
        priv->hw->mac->dump_regs(priv->hw, reg_space);
        priv->hw->dma->dump_regs(priv->ioaddr, reg_space);
+       /* Copy DMA registers to where ethtool expects them */
+       memcpy(&reg_space[ETHTOOL_DMA_OFFSET], &reg_space[DMA_BUS_MODE / 4],
+              NUM_DWMAC1000_DMA_REGS * 4);
 }
 
 static void
index 1853f7f..1763e48 100644 (file)
@@ -4120,8 +4120,15 @@ int stmmac_dvr_probe(struct device *device,
        if ((phyaddr >= 0) && (phyaddr <= 31))
                priv->plat->phy_addr = phyaddr;
 
-       if (priv->plat->stmmac_rst)
+       if (priv->plat->stmmac_rst) {
+               ret = reset_control_assert(priv->plat->stmmac_rst);
                reset_control_deassert(priv->plat->stmmac_rst);
+               /* Some reset controllers have only reset callback instead of
+                * assert + deassert callbacks pair.
+                */
+               if (ret == -ENOTSUPP)
+                       reset_control_reset(priv->plat->stmmac_rst);
+       }
 
        /* Init MAC and get the capabilities */
        ret = stmmac_hw_init(priv);
index 46cb7f8..6a4e8e1 100644 (file)
@@ -9221,8 +9221,7 @@ static int niu_get_of_props(struct niu *np)
 
        phy_type = of_get_property(dp, "phy-type", &prop_len);
        if (!phy_type) {
-               netdev_err(dev, "%s: OF node lacks phy-type property\n",
-                          dp->full_name);
+               netdev_err(dev, "%pOF: OF node lacks phy-type property\n", dp);
                return -EINVAL;
        }
 
@@ -9232,26 +9231,25 @@ static int niu_get_of_props(struct niu *np)
        strcpy(np->vpd.phy_type, phy_type);
 
        if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
-               netdev_err(dev, "%s: Illegal phy string [%s]\n",
-                          dp->full_name, np->vpd.phy_type);
+               netdev_err(dev, "%pOF: Illegal phy string [%s]\n",
+                          dp, np->vpd.phy_type);
                return -EINVAL;
        }
 
        mac_addr = of_get_property(dp, "local-mac-address", &prop_len);
        if (!mac_addr) {
-               netdev_err(dev, "%s: OF node lacks local-mac-address property\n",
-                          dp->full_name);
+               netdev_err(dev, "%pOF: OF node lacks local-mac-address property\n",
+                          dp);
                return -EINVAL;
        }
        if (prop_len != dev->addr_len) {
-               netdev_err(dev, "%s: OF MAC address prop len (%d) is wrong\n",
-                          dp->full_name, prop_len);
+               netdev_err(dev, "%pOF: OF MAC address prop len (%d) is wrong\n",
+                          dp, prop_len);
        }
        memcpy(dev->dev_addr, mac_addr, dev->addr_len);
        if (!is_valid_ether_addr(&dev->dev_addr[0])) {
-               netdev_err(dev, "%s: OF MAC address is invalid\n",
-                          dp->full_name);
-               netdev_err(dev, "%s: [ %pM ]\n", dp->full_name, dev->dev_addr);
+               netdev_err(dev, "%pOF: OF MAC address is invalid\n", dp);
+               netdev_err(dev, "%pOF: [ %pM ]\n", dp, dev->dev_addr);
                return -EINVAL;
        }
 
@@ -9532,7 +9530,7 @@ static struct niu_parent *niu_get_parent(struct niu *np,
                p = niu_new_parent(np, id, ptype);
 
        if (p) {
-               char port_name[6];
+               char port_name[8];
                int err;
 
                sprintf(port_name, "port%d", port);
@@ -9553,7 +9551,7 @@ static void niu_put_parent(struct niu *np)
 {
        struct niu_parent *p = np->parent;
        u8 port = np->port;
-       char port_name[6];
+       char port_name[8];
 
        BUG_ON(!p || p->ports[port] != np);
 
@@ -10027,8 +10025,8 @@ static int niu_of_probe(struct platform_device *op)
 
        reg = of_get_property(op->dev.of_node, "reg", NULL);
        if (!reg) {
-               dev_err(&op->dev, "%s: No 'reg' property, aborting\n",
-                       op->dev.of_node->full_name);
+               dev_err(&op->dev, "%pOF: No 'reg' property, aborting\n",
+                       op->dev.of_node);
                return -ENODEV;
        }
 
index 3af540a..fca1bca 100644 (file)
@@ -13,9 +13,9 @@
 /* Happy Meal global registers. */
 #define GREG_SWRESET   0x000UL /* Software Reset  */
 #define GREG_CFG       0x004UL /* Config Register */
-#define GREG_STAT      0x108UL /* Status          */
-#define GREG_IMASK     0x10cUL /* Interrupt Mask  */
-#define GREG_REG_SIZE  0x110UL
+#define GREG_STAT      0x100UL /* Status          */
+#define GREG_IMASK     0x104UL /* Interrupt Mask  */
+#define GREG_REG_SIZE  0x108UL
 
 /* Global reset register. */
 #define GREG_RESET_ETX         0x01
index 711fbbb..163d8d1 100644 (file)
@@ -654,6 +654,8 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd)
                        RET(-EFAULT);
                }
                DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]);
+       } else {
+               return -EOPNOTSUPP;
        }
 
        if (!capable(CAP_SYS_RAWIO))
index 1850e34..c8776db 100644 (file)
@@ -1321,8 +1321,8 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
                phy = of_phy_connect(priv->ndev, slave->data->phy_node,
                                 &cpsw_adjust_link, 0, slave->data->phy_if);
                if (!phy) {
-                       dev_err(priv->dev, "phy \"%s\" not found on slave %d\n",
-                               slave->data->phy_node->full_name,
+                       dev_err(priv->dev, "phy \"%pOF\" not found on slave %d\n",
+                               slave->data->phy_node,
                                slave->slave_num);
                        return;
                }
@@ -2670,8 +2670,8 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                parp = of_get_property(slave_node, "phy_id", &lenp);
                if (slave_data->phy_node) {
                        dev_dbg(&pdev->dev,
-                               "slave[%d] using phy-handle=\"%s\"\n",
-                               i, slave_data->phy_node->full_name);
+                               "slave[%d] using phy-handle=\"%pOF\"\n",
+                               i, slave_data->phy_node);
                } else if (of_phy_is_fixed_link(slave_node)) {
                        /* In the case of a fixed PHY, the DT node associated
                         * to the PHY is the Ethernet MAC DT node.
@@ -3089,6 +3089,31 @@ static int cpsw_probe(struct platform_device *pdev)
                        cpsw->quirk_irq = true;
        }
 
+       ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+
+       ndev->netdev_ops = &cpsw_netdev_ops;
+       ndev->ethtool_ops = &cpsw_ethtool_ops;
+       netif_napi_add(ndev, &cpsw->napi_rx, cpsw_rx_poll, CPSW_POLL_WEIGHT);
+       netif_tx_napi_add(ndev, &cpsw->napi_tx, cpsw_tx_poll, CPSW_POLL_WEIGHT);
+       cpsw_split_res(ndev);
+
+       /* register the network device */
+       SET_NETDEV_DEV(ndev, &pdev->dev);
+       ret = register_netdev(ndev);
+       if (ret) {
+               dev_err(priv->dev, "error registering net device\n");
+               ret = -ENODEV;
+               goto clean_ale_ret;
+       }
+
+       if (cpsw->data.dual_emac) {
+               ret = cpsw_probe_dual_emac(priv);
+               if (ret) {
+                       cpsw_err(priv, probe, "error probe slave 2 emac interface\n");
+                       goto clean_unregister_netdev_ret;
+               }
+       }
+
        /* Grab RX and TX IRQs. Note that we also have RX_THRESHOLD and
         * MISC IRQs which are always kept disabled with this driver so
         * we will not request them.
@@ -3127,33 +3152,9 @@ static int cpsw_probe(struct platform_device *pdev)
                goto clean_ale_ret;
        }
 
-       ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
-
-       ndev->netdev_ops = &cpsw_netdev_ops;
-       ndev->ethtool_ops = &cpsw_ethtool_ops;
-       netif_napi_add(ndev, &cpsw->napi_rx, cpsw_rx_poll, CPSW_POLL_WEIGHT);
-       netif_tx_napi_add(ndev, &cpsw->napi_tx, cpsw_tx_poll, CPSW_POLL_WEIGHT);
-       cpsw_split_res(ndev);
-
-       /* register the network device */
-       SET_NETDEV_DEV(ndev, &pdev->dev);
-       ret = register_netdev(ndev);
-       if (ret) {
-               dev_err(priv->dev, "error registering net device\n");
-               ret = -ENODEV;
-               goto clean_ale_ret;
-       }
-
        cpsw_notice(priv, probe,
                    "initialized device (regs %pa, irq %d, pool size %d)\n",
                    &ss_res->start, ndev->irq, dma_params.descs_pool_size);
-       if (cpsw->data.dual_emac) {
-               ret = cpsw_probe_dual_emac(priv);
-               if (ret) {
-                       cpsw_err(priv, probe, "error probe slave 2 emac interface\n");
-                       goto clean_unregister_netdev_ret;
-               }
-       }
 
        pm_runtime_put(&pdev->dev);
 
index 64d5527..4bb5618 100644 (file)
@@ -1480,8 +1480,8 @@ static int emac_dev_open(struct net_device *ndev)
                phydev = of_phy_connect(ndev, priv->phy_node,
                                        &emac_adjust_link, 0, 0);
                if (!phydev) {
-                       dev_err(emac_dev, "could not connect to phy %s\n",
-                               priv->phy_node->full_name);
+                       dev_err(emac_dev, "could not connect to phy %pOF\n",
+                               priv->phy_node);
                        ret = -ENODEV;
                        goto err;
                }
index d9db8a0..cce9c9e 100644 (file)
@@ -1338,7 +1338,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
 static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status)
 {
        static int count;
-       printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
+       printk(KERN_WARNING "%s: Fatal Error Interrupt (%#x):",
               dev->name, status);
        if (status & Int_IntPCI)
                printk(" IntPCI");
index d73da8a..60abc92 100644 (file)
@@ -1089,7 +1089,7 @@ static int temac_of_probe(struct platform_device *op)
 
        lp->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0);
        if (lp->phy_node)
-               dev_dbg(lp->dev, "using PHY node %s (%p)\n", np->full_name, np);
+               dev_dbg(lp->dev, "using PHY node %pOF (%p)\n", np, np);
 
        /* Add the device attributes */
        rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group);
index de8156c..745d57a 100644 (file)
@@ -715,6 +715,7 @@ free_dst:
 
 static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
                                       struct net_device *dev,
+                                      struct geneve_sock *gs4,
                                       struct flowi4 *fl4,
                                       const struct ip_tunnel_info *info)
 {
@@ -724,7 +725,7 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
        struct rtable *rt = NULL;
        __u8 tos;
 
-       if (!rcu_dereference(geneve->sock4))
+       if (!gs4)
                return ERR_PTR(-EIO);
 
        memset(fl4, 0, sizeof(*fl4));
@@ -764,6 +765,7 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
 #if IS_ENABLED(CONFIG_IPV6)
 static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
                                           struct net_device *dev,
+                                          struct geneve_sock *gs6,
                                           struct flowi6 *fl6,
                                           const struct ip_tunnel_info *info)
 {
@@ -771,10 +773,8 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
        struct geneve_dev *geneve = netdev_priv(dev);
        struct dst_entry *dst = NULL;
        struct dst_cache *dst_cache;
-       struct geneve_sock *gs6;
        __u8 prio;
 
-       gs6 = rcu_dereference(geneve->sock6);
        if (!gs6)
                return ERR_PTR(-EIO);
 
@@ -827,7 +827,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
        __be16 df;
        int err;
 
-       rt = geneve_get_v4_rt(skb, dev, &fl4, info);
+       rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info);
        if (IS_ERR(rt))
                return PTR_ERR(rt);
 
@@ -866,7 +866,7 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
        __be16 sport;
        int err;
 
-       dst = geneve_get_v6_dst(skb, dev, &fl6, info);
+       dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info);
        if (IS_ERR(dst))
                return PTR_ERR(dst);
 
@@ -951,8 +951,9 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
        if (ip_tunnel_info_af(info) == AF_INET) {
                struct rtable *rt;
                struct flowi4 fl4;
+               struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
 
-               rt = geneve_get_v4_rt(skb, dev, &fl4, info);
+               rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info);
                if (IS_ERR(rt))
                        return PTR_ERR(rt);
 
@@ -962,8 +963,9 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
        } else if (ip_tunnel_info_af(info) == AF_INET6) {
                struct dst_entry *dst;
                struct flowi6 fl6;
+               struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
 
-               dst = geneve_get_v6_dst(skb, dev, &fl6, info);
+               dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info);
                if (IS_ERR(dst))
                        return PTR_ERR(dst);
 
@@ -1014,16 +1016,22 @@ static struct device_type geneve_type = {
  * supply the listening GENEVE udp ports. Callers are expected
  * to implement the ndo_udp_tunnel_add.
  */
-static void geneve_push_rx_ports(struct net_device *dev)
+static void geneve_offload_rx_ports(struct net_device *dev, bool push)
 {
        struct net *net = dev_net(dev);
        struct geneve_net *gn = net_generic(net, geneve_net_id);
        struct geneve_sock *gs;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(gs, &gn->sock_list, list)
-               udp_tunnel_push_rx_port(dev, gs->sock,
-                                       UDP_TUNNEL_TYPE_GENEVE);
+       list_for_each_entry_rcu(gs, &gn->sock_list, list) {
+               if (push) {
+                       udp_tunnel_push_rx_port(dev, gs->sock,
+                                               UDP_TUNNEL_TYPE_GENEVE);
+               } else {
+                       udp_tunnel_drop_rx_port(dev, gs->sock,
+                                               UDP_TUNNEL_TYPE_GENEVE);
+               }
+       }
        rcu_read_unlock();
 }
 
@@ -1140,6 +1148,15 @@ static bool is_tnl_info_zero(const struct ip_tunnel_info *info)
                return true;
 }
 
+static bool geneve_dst_addr_equal(struct ip_tunnel_info *a,
+                                 struct ip_tunnel_info *b)
+{
+       if (ip_tunnel_info_af(a) == AF_INET)
+               return a->key.u.ipv4.dst == b->key.u.ipv4.dst;
+       else
+               return ipv6_addr_equal(&a->key.u.ipv6.dst, &b->key.u.ipv6.dst);
+}
+
 static int geneve_configure(struct net *net, struct net_device *dev,
                            const struct ip_tunnel_info *info,
                            bool metadata, bool ipv6_rx_csum)
@@ -1197,24 +1214,22 @@ static void init_tnl_info(struct ip_tunnel_info *info, __u16 dst_port)
        info->key.tp_dst = htons(dst_port);
 }
 
-static int geneve_newlink(struct net *net, struct net_device *dev,
-                         struct nlattr *tb[], struct nlattr *data[],
-                         struct netlink_ext_ack *extack)
+static int geneve_nl2info(struct net_device *dev, struct nlattr *tb[],
+                         struct nlattr *data[], struct ip_tunnel_info *info,
+                         bool *metadata, bool *use_udp6_rx_checksums,
+                         bool changelink)
 {
-       bool use_udp6_rx_checksums = false;
-       struct ip_tunnel_info info;
-       bool metadata = false;
-
-       init_tnl_info(&info, GENEVE_UDP_PORT);
-
        if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6])
                return -EINVAL;
 
        if (data[IFLA_GENEVE_REMOTE]) {
-               info.key.u.ipv4.dst =
+               if (changelink && (ip_tunnel_info_af(info) == AF_INET6))
+                       return -EOPNOTSUPP;
+
+               info->key.u.ipv4.dst =
                        nla_get_in_addr(data[IFLA_GENEVE_REMOTE]);
 
-               if (IN_MULTICAST(ntohl(info.key.u.ipv4.dst))) {
+               if (IN_MULTICAST(ntohl(info->key.u.ipv4.dst))) {
                        netdev_dbg(dev, "multicast remote is unsupported\n");
                        return -EINVAL;
                }
@@ -1222,21 +1237,24 @@ static int geneve_newlink(struct net *net, struct net_device *dev,
 
        if (data[IFLA_GENEVE_REMOTE6]) {
  #if IS_ENABLED(CONFIG_IPV6)
-               info.mode = IP_TUNNEL_INFO_IPV6;
-               info.key.u.ipv6.dst =
+               if (changelink && (ip_tunnel_info_af(info) == AF_INET))
+                       return -EOPNOTSUPP;
+
+               info->mode = IP_TUNNEL_INFO_IPV6;
+               info->key.u.ipv6.dst =
                        nla_get_in6_addr(data[IFLA_GENEVE_REMOTE6]);
 
-               if (ipv6_addr_type(&info.key.u.ipv6.dst) &
+               if (ipv6_addr_type(&info->key.u.ipv6.dst) &
                    IPV6_ADDR_LINKLOCAL) {
                        netdev_dbg(dev, "link-local remote is unsupported\n");
                        return -EINVAL;
                }
-               if (ipv6_addr_is_multicast(&info.key.u.ipv6.dst)) {
+               if (ipv6_addr_is_multicast(&info->key.u.ipv6.dst)) {
                        netdev_dbg(dev, "multicast remote is unsupported\n");
                        return -EINVAL;
                }
-               info.key.tun_flags |= TUNNEL_CSUM;
-               use_udp6_rx_checksums = true;
+               info->key.tun_flags |= TUNNEL_CSUM;
+               *use_udp6_rx_checksums = true;
 #else
                return -EPFNOSUPPORT;
 #endif
@@ -1245,48 +1263,169 @@ static int geneve_newlink(struct net *net, struct net_device *dev,
        if (data[IFLA_GENEVE_ID]) {
                __u32 vni;
                __u8 tvni[3];
+               __be64 tunid;
 
                vni = nla_get_u32(data[IFLA_GENEVE_ID]);
                tvni[0] = (vni & 0x00ff0000) >> 16;
                tvni[1] = (vni & 0x0000ff00) >> 8;
                tvni[2] =  vni & 0x000000ff;
 
-               info.key.tun_id = vni_to_tunnel_id(tvni);
+               tunid = vni_to_tunnel_id(tvni);
+               if (changelink && (tunid != info->key.tun_id))
+                       return -EOPNOTSUPP;
+               info->key.tun_id = tunid;
        }
+
        if (data[IFLA_GENEVE_TTL])
-               info.key.ttl = nla_get_u8(data[IFLA_GENEVE_TTL]);
+               info->key.ttl = nla_get_u8(data[IFLA_GENEVE_TTL]);
 
        if (data[IFLA_GENEVE_TOS])
-               info.key.tos = nla_get_u8(data[IFLA_GENEVE_TOS]);
+               info->key.tos = nla_get_u8(data[IFLA_GENEVE_TOS]);
 
        if (data[IFLA_GENEVE_LABEL]) {
-               info.key.label = nla_get_be32(data[IFLA_GENEVE_LABEL]) &
+               info->key.label = nla_get_be32(data[IFLA_GENEVE_LABEL]) &
                                  IPV6_FLOWLABEL_MASK;
-               if (info.key.label && (!(info.mode & IP_TUNNEL_INFO_IPV6)))
+               if (info->key.label && (!(info->mode & IP_TUNNEL_INFO_IPV6)))
                        return -EINVAL;
        }
 
-       if (data[IFLA_GENEVE_PORT])
-               info.key.tp_dst = nla_get_be16(data[IFLA_GENEVE_PORT]);
+       if (data[IFLA_GENEVE_PORT]) {
+               if (changelink)
+                       return -EOPNOTSUPP;
+               info->key.tp_dst = nla_get_be16(data[IFLA_GENEVE_PORT]);
+       }
 
-       if (data[IFLA_GENEVE_COLLECT_METADATA])
-               metadata = true;
+       if (data[IFLA_GENEVE_COLLECT_METADATA]) {
+               if (changelink)
+                       return -EOPNOTSUPP;
+               *metadata = true;
+       }
 
-       if (data[IFLA_GENEVE_UDP_CSUM] &&
-           nla_get_u8(data[IFLA_GENEVE_UDP_CSUM]))
-               info.key.tun_flags |= TUNNEL_CSUM;
+       if (data[IFLA_GENEVE_UDP_CSUM]) {
+               if (changelink)
+                       return -EOPNOTSUPP;
+               if (nla_get_u8(data[IFLA_GENEVE_UDP_CSUM]))
+                       info->key.tun_flags |= TUNNEL_CSUM;
+       }
+
+       if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) {
+               if (changelink)
+                       return -EOPNOTSUPP;
+               if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
+                       info->key.tun_flags &= ~TUNNEL_CSUM;
+       }
+
+       if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) {
+               if (changelink)
+                       return -EOPNOTSUPP;
+               if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
+                       *use_udp6_rx_checksums = false;
+       }
+
+       return 0;
+}
 
-       if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX] &&
-           nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
-               info.key.tun_flags &= ~TUNNEL_CSUM;
+static int geneve_newlink(struct net *net, struct net_device *dev,
+                         struct nlattr *tb[], struct nlattr *data[],
+                         struct netlink_ext_ack *extack)
+{
+       bool use_udp6_rx_checksums = false;
+       struct ip_tunnel_info info;
+       bool metadata = false;
+       int err;
 
-       if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX] &&
-           nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
-               use_udp6_rx_checksums = false;
+       init_tnl_info(&info, GENEVE_UDP_PORT);
+       err = geneve_nl2info(dev, tb, data, &info, &metadata,
+                            &use_udp6_rx_checksums, false);
+       if (err)
+               return err;
 
        return geneve_configure(net, dev, &info, metadata, use_udp6_rx_checksums);
 }
 
+/* Quiesces the geneve device data path for both TX and RX.
+ *
+ * On transmit geneve checks for non-NULL geneve_sock before it proceeds.
+ * So, if we set that socket to NULL under RCU and wait for synchronize_net()
+ * to complete for the existing set of in-flight packets to be transmitted,
+ * then we would have quiesced the transmit data path. All the future packets
+ * will get dropped until we unquiesce the data path.
+ *
+ * On receive geneve dereference the geneve_sock stashed in the socket. So,
+ * if we set that to NULL under RCU and wait for synchronize_net() to
+ * complete, then we would have quiesced the receive data path.
+ */
+static void geneve_quiesce(struct geneve_dev *geneve, struct geneve_sock **gs4,
+                          struct geneve_sock **gs6)
+{
+       *gs4 = rtnl_dereference(geneve->sock4);
+       rcu_assign_pointer(geneve->sock4, NULL);
+       if (*gs4)
+               rcu_assign_sk_user_data((*gs4)->sock->sk, NULL);
+#if IS_ENABLED(CONFIG_IPV6)
+       *gs6 = rtnl_dereference(geneve->sock6);
+       rcu_assign_pointer(geneve->sock6, NULL);
+       if (*gs6)
+               rcu_assign_sk_user_data((*gs6)->sock->sk, NULL);
+#else
+       *gs6 = NULL;
+#endif
+       synchronize_net();
+}
+
+/* Resumes the geneve device data path for both TX and RX. */
+static void geneve_unquiesce(struct geneve_dev *geneve, struct geneve_sock *gs4,
+                            struct geneve_sock __maybe_unused *gs6)
+{
+       rcu_assign_pointer(geneve->sock4, gs4);
+       if (gs4)
+               rcu_assign_sk_user_data(gs4->sock->sk, gs4);
+#if IS_ENABLED(CONFIG_IPV6)
+       rcu_assign_pointer(geneve->sock6, gs6);
+       if (gs6)
+               rcu_assign_sk_user_data(gs6->sock->sk, gs6);
+#endif
+       synchronize_net();
+}
+
+static int geneve_changelink(struct net_device *dev, struct nlattr *tb[],
+                            struct nlattr *data[],
+                            struct netlink_ext_ack *extack)
+{
+       struct geneve_dev *geneve = netdev_priv(dev);
+       struct geneve_sock *gs4, *gs6;
+       struct ip_tunnel_info info;
+       bool metadata;
+       bool use_udp6_rx_checksums;
+       int err;
+
+       /* If the geneve device is configured for metadata (or externally
+        * controlled, for example, OVS), then nothing can be changed.
+        */
+       if (geneve->collect_md)
+               return -EOPNOTSUPP;
+
+       /* Start with the existing info. */
+       memcpy(&info, &geneve->info, sizeof(info));
+       metadata = geneve->collect_md;
+       use_udp6_rx_checksums = geneve->use_udp6_rx_checksums;
+       err = geneve_nl2info(dev, tb, data, &info, &metadata,
+                            &use_udp6_rx_checksums, true);
+       if (err)
+               return err;
+
+       if (!geneve_dst_addr_equal(&geneve->info, &info))
+               dst_cache_reset(&info.dst_cache);
+
+       geneve_quiesce(geneve, &gs4, &gs6);
+       geneve->info = info;
+       geneve->collect_md = metadata;
+       geneve->use_udp6_rx_checksums = use_udp6_rx_checksums;
+       geneve_unquiesce(geneve, gs4, gs6);
+
+       return 0;
+}
+
 static void geneve_dellink(struct net_device *dev, struct list_head *head)
 {
        struct geneve_dev *geneve = netdev_priv(dev);
@@ -1375,6 +1514,7 @@ static struct rtnl_link_ops geneve_link_ops __read_mostly = {
        .setup          = geneve_setup,
        .validate       = geneve_validate,
        .newlink        = geneve_newlink,
+       .changelink     = geneve_changelink,
        .dellink        = geneve_dellink,
        .get_size       = geneve_get_size,
        .fill_info      = geneve_fill_info,
@@ -1426,8 +1566,14 @@ static int geneve_netdevice_event(struct notifier_block *unused,
 {
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 
-       if (event == NETDEV_UDP_TUNNEL_PUSH_INFO)
-               geneve_push_rx_ports(dev);
+       if (event == NETDEV_UDP_TUNNEL_PUSH_INFO ||
+           event == NETDEV_UDP_TUNNEL_DROP_INFO) {
+               geneve_offload_rx_ports(dev, event == NETDEV_UDP_TUNNEL_PUSH_INFO);
+       } else if (event == NETDEV_UNREGISTER) {
+               geneve_offload_rx_ports(dev, false);
+       } else if (event == NETDEV_REGISTER) {
+               geneve_offload_rx_ports(dev, true);
+       }
 
        return NOTIFY_DONE;
 }
index dec6b76..cde4120 100644 (file)
@@ -581,7 +581,7 @@ static int __init setup_adapter(int card_base, int type, int n)
                priv->param.dma = -1;
                INIT_WORK(&priv->rx_work, rx_bh);
                dev->ml_priv = priv;
-               sprintf(dev->name, "dmascc%i", 2 * n + i);
+               snprintf(dev->name, sizeof(dev->name), "dmascc%i", 2 * n + i);
                dev->base_addr = card_base;
                dev->irq = irq;
                dev->netdev_ops = &scc_netdev_ops;
index afb65f7..f2cef5a 100644 (file)
@@ -147,7 +147,6 @@ struct hv_netvsc_packet {
 struct netvsc_device_info {
        unsigned char mac_adr[ETH_ALEN];
        int  ring_size;
-       u32  max_num_vrss_chns;
        u32  num_chn;
 };
 
@@ -187,11 +186,12 @@ struct net_device_context;
 
 struct netvsc_device *netvsc_device_add(struct hv_device *device,
                                        const struct netvsc_device_info *info);
+int netvsc_alloc_recv_comp_ring(struct netvsc_device *net_device, u32 q_idx);
 void netvsc_device_remove(struct hv_device *device);
 int netvsc_send(struct net_device_context *ndc,
                struct hv_netvsc_packet *packet,
                struct rndis_message *rndis_msg,
-               struct hv_page_buffer **page_buffer,
+               struct hv_page_buffer *page_buffer,
                struct sk_buff *skb);
 void netvsc_linkstatus_callback(struct hv_device *device_obj,
                                struct rndis_message *resp);
@@ -218,7 +218,8 @@ int rndis_filter_receive(struct net_device *ndev,
                         struct vmbus_channel *channel,
                         void *data, u32 buflen);
 
-int rndis_filter_set_device_mac(struct net_device *ndev, char *mac);
+int rndis_filter_set_device_mac(struct netvsc_device *ndev,
+                               const char *mac);
 
 void netvsc_switch_datapath(struct net_device *nv_dev, bool vf);
 
@@ -657,13 +658,10 @@ struct recv_comp_data {
        u32 status;
 };
 
-/* Netvsc Receive Slots Max */
-#define NETVSC_RECVSLOT_MAX (NETVSC_RECEIVE_BUFFER_SIZE / ETH_DATA_LEN + 1)
-
 struct multi_recv_comp {
-       void *buf; /* queued receive completions */
-       u32 first; /* first data entry */
-       u32 next; /* next entry for writing */
+       struct recv_comp_data *slots;
+       u32 first;      /* first data entry */
+       u32 next;       /* next entry for writing */
 };
 
 struct netvsc_stats {
@@ -750,7 +748,7 @@ struct netvsc_device {
        u32 recv_buf_size;
        u32 recv_buf_gpadl_handle;
        u32 recv_section_cnt;
-       struct nvsp_1_receive_buffer_section *recv_section;
+       u32 recv_completion_cnt;
 
        /* Send buffer allocated by us */
        void *send_buf;
@@ -778,8 +776,6 @@ struct netvsc_device {
        u32 max_pkt; /* max number of pkt in one send, e.g. 8 */
        u32 pkt_align; /* alignment bytes, e.g. 8 */
 
-       atomic_t num_outstanding_recvs;
-
        atomic_t open_cnt;
 
        struct netvsc_channel chan_table[VRSS_CHANNEL_MAX];
index 0a9d9fe..c64934c 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/if_ether.h>
 #include <linux/vmalloc.h>
 #include <linux/rtnetlink.h>
+#include <linux/prefetch.h>
 
 #include <asm/sync_bitops.h>
 
@@ -71,9 +72,6 @@ static struct netvsc_device *alloc_net_device(void)
        if (!net_device)
                return NULL;
 
-       net_device->chan_table[0].mrc.buf
-               = vzalloc(NETVSC_RECVSLOT_MAX * sizeof(struct recv_comp_data));
-
        init_waitqueue_head(&net_device->wait_drain);
        net_device->destroy = false;
        atomic_set(&net_device->open_cnt, 0);
@@ -91,7 +89,7 @@ static void free_netvsc_device(struct rcu_head *head)
        int i;
 
        for (i = 0; i < VRSS_CHANNEL_MAX; i++)
-               vfree(nvdev->chan_table[i].mrc.buf);
+               vfree(nvdev->chan_table[i].mrc.slots);
 
        kfree(nvdev);
 }
@@ -170,12 +168,6 @@ static void netvsc_destroy_buf(struct hv_device *device)
                net_device->recv_buf = NULL;
        }
 
-       if (net_device->recv_section) {
-               net_device->recv_section_cnt = 0;
-               kfree(net_device->recv_section);
-               net_device->recv_section = NULL;
-       }
-
        /* Deal with the send buffer we may have setup.
         * If we got a  send section size, it means we received a
         * NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE msg (ie sent
@@ -238,11 +230,26 @@ static void netvsc_destroy_buf(struct hv_device *device)
        kfree(net_device->send_section_map);
 }
 
+int netvsc_alloc_recv_comp_ring(struct netvsc_device *net_device, u32 q_idx)
+{
+       struct netvsc_channel *nvchan = &net_device->chan_table[q_idx];
+       int node = cpu_to_node(nvchan->channel->target_cpu);
+       size_t size;
+
+       size = net_device->recv_completion_cnt * sizeof(struct recv_comp_data);
+       nvchan->mrc.slots = vzalloc_node(size, node);
+       if (!nvchan->mrc.slots)
+               nvchan->mrc.slots = vzalloc(size);
+
+       return nvchan->mrc.slots ? 0 : -ENOMEM;
+}
+
 static int netvsc_init_buf(struct hv_device *device,
                           struct netvsc_device *net_device)
 {
        int ret = 0;
        struct nvsp_message *init_packet;
+       struct nvsp_1_message_send_receive_buffer_complete *resp;
        struct net_device *ndev;
        size_t map_words;
        int node;
@@ -299,43 +306,41 @@ static int netvsc_init_buf(struct hv_device *device,
        wait_for_completion(&net_device->channel_init_wait);
 
        /* Check the response */
-       if (init_packet->msg.v1_msg.
-           send_recv_buf_complete.status != NVSP_STAT_SUCCESS) {
-               netdev_err(ndev, "Unable to complete receive buffer "
-                          "initialization with NetVsp - status %d\n",
-                          init_packet->msg.v1_msg.
-                          send_recv_buf_complete.status);
+       resp = &init_packet->msg.v1_msg.send_recv_buf_complete;
+       if (resp->status != NVSP_STAT_SUCCESS) {
+               netdev_err(ndev,
+                          "Unable to complete receive buffer initialization with NetVsp - status %d\n",
+                          resp->status);
                ret = -EINVAL;
                goto cleanup;
        }
 
        /* Parse the response */
+       netdev_dbg(ndev, "Receive sections: %u sub_allocs: size %u count: %u\n",
+                  resp->num_sections, resp->sections[0].sub_alloc_size,
+                  resp->sections[0].num_sub_allocs);
 
-       net_device->recv_section_cnt = init_packet->msg.
-               v1_msg.send_recv_buf_complete.num_sections;
-
-       net_device->recv_section = kmemdup(
-               init_packet->msg.v1_msg.send_recv_buf_complete.sections,
-               net_device->recv_section_cnt *
-               sizeof(struct nvsp_1_receive_buffer_section),
-               GFP_KERNEL);
-       if (net_device->recv_section == NULL) {
-               ret = -EINVAL;
-               goto cleanup;
-       }
+       net_device->recv_section_cnt = resp->num_sections;
 
        /*
         * For 1st release, there should only be 1 section that represents the
         * entire receive buffer
         */
        if (net_device->recv_section_cnt != 1 ||
-           net_device->recv_section->offset != 0) {
+           resp->sections[0].offset != 0) {
                ret = -EINVAL;
                goto cleanup;
        }
 
-       /* Now setup the send buffer.
-        */
+       /* Setup receive completion ring */
+       net_device->recv_completion_cnt
+               = round_up(resp->sections[0].num_sub_allocs + 1,
+                          PAGE_SIZE / sizeof(u64));
+       ret = netvsc_alloc_recv_comp_ring(net_device, 0);
+       if (ret)
+               goto cleanup;
+
+       /* Now setup the send buffer. */
        net_device->send_buf = vzalloc_node(net_device->send_buf_size, node);
        if (!net_device->send_buf)
                net_device->send_buf = vzalloc(net_device->send_buf_size);
@@ -696,7 +701,7 @@ static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device,
                                   u32 pend_size,
                                   struct hv_netvsc_packet *packet,
                                   struct rndis_message *rndis_msg,
-                                  struct hv_page_buffer **pb,
+                                  struct hv_page_buffer *pb,
                                   struct sk_buff *skb)
 {
        char *start = net_device->send_buf;
@@ -717,9 +722,9 @@ static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device,
        }
 
        for (i = 0; i < page_count; i++) {
-               char *src = phys_to_virt((*pb)[i].pfn << PAGE_SHIFT);
-               u32 offset = (*pb)[i].offset;
-               u32 len = (*pb)[i].len;
+               char *src = phys_to_virt(pb[i].pfn << PAGE_SHIFT);
+               u32 offset = pb[i].offset;
+               u32 len = pb[i].len;
 
                memcpy(dest, (src + offset), len);
                msg_size += len;
@@ -738,7 +743,7 @@ static inline int netvsc_send_pkt(
        struct hv_device *device,
        struct hv_netvsc_packet *packet,
        struct netvsc_device *net_device,
-       struct hv_page_buffer **pb,
+       struct hv_page_buffer *pb,
        struct sk_buff *skb)
 {
        struct nvsp_message nvmsg;
@@ -749,7 +754,6 @@ static inline int netvsc_send_pkt(
        struct netdev_queue *txq = netdev_get_tx_queue(ndev, packet->q_idx);
        u64 req_id;
        int ret;
-       struct hv_page_buffer *pgbuf;
        u32 ring_avail = hv_ringbuf_avail_percent(&out_channel->outbound);
 
        nvmsg.hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT;
@@ -775,11 +779,11 @@ static inline int netvsc_send_pkt(
                return -ENODEV;
 
        if (packet->page_buf_cnt) {
-               pgbuf = packet->cp_partial ? (*pb) +
-                       packet->rmsg_pgcnt : (*pb);
+               if (packet->cp_partial)
+                       pb += packet->rmsg_pgcnt;
+
                ret = vmbus_sendpacket_pagebuffer_ctl(out_channel,
-                                                     pgbuf,
-                                                     packet->page_buf_cnt,
+                                                     pb, packet->page_buf_cnt,
                                                      &nvmsg,
                                                      sizeof(struct nvsp_message),
                                                      req_id,
@@ -804,8 +808,10 @@ static inline int netvsc_send_pkt(
                        ret = -ENOSPC;
                }
        } else {
-               netdev_err(ndev, "Unable to send packet %p ret %d\n",
-                          packet, ret);
+               netdev_err(ndev,
+                          "Unable to send packet pages %u len %u, ret %d\n",
+                          packet->page_buf_cnt, packet->total_data_buflen,
+                          ret);
        }
 
        return ret;
@@ -827,11 +833,11 @@ static inline void move_pkt_msd(struct hv_netvsc_packet **msd_send,
 int netvsc_send(struct net_device_context *ndev_ctx,
                struct hv_netvsc_packet *packet,
                struct rndis_message *rndis_msg,
-               struct hv_page_buffer **pb,
+               struct hv_page_buffer *pb,
                struct sk_buff *skb)
 {
        struct netvsc_device *net_device
-               = rcu_dereference_rtnl(ndev_ctx->nvdev);
+               = rcu_dereference_bh(ndev_ctx->nvdev);
        struct hv_device *device = ndev_ctx->device_ctx;
        int ret = 0;
        struct netvsc_channel *nvchan;
@@ -949,130 +955,94 @@ send_now:
        return ret;
 }
 
-static int netvsc_send_recv_completion(struct vmbus_channel *channel,
-                                      u64 transaction_id, u32 status)
+/* Send pending recv completions */
+static int send_recv_completions(struct netvsc_channel *nvchan)
 {
-       struct nvsp_message recvcompMessage;
+       struct netvsc_device *nvdev = nvchan->net_device;
+       struct multi_recv_comp *mrc = &nvchan->mrc;
+       struct recv_comp_msg {
+               struct nvsp_message_header hdr;
+               u32 status;
+       }  __packed;
+       struct recv_comp_msg msg = {
+               .hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE,
+       };
        int ret;
 
-       recvcompMessage.hdr.msg_type =
-                               NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE;
-
-       recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status = status;
-
-       /* Send the completion */
-       ret = vmbus_sendpacket(channel, &recvcompMessage,
-                              sizeof(struct nvsp_message_header) + sizeof(u32),
-                              transaction_id, VM_PKT_COMP, 0);
-
-       return ret;
-}
-
-static inline void count_recv_comp_slot(struct netvsc_device *nvdev, u16 q_idx,
-                                       u32 *filled, u32 *avail)
-{
-       struct multi_recv_comp *mrc = &nvdev->chan_table[q_idx].mrc;
-       u32 first = mrc->first;
-       u32 next = mrc->next;
-
-       *filled = (first > next) ? NETVSC_RECVSLOT_MAX - first + next :
-                 next - first;
+       while (mrc->first != mrc->next) {
+               const struct recv_comp_data *rcd
+                       = mrc->slots + mrc->first;
 
-       *avail = NETVSC_RECVSLOT_MAX - *filled - 1;
-}
+               msg.status = rcd->status;
+               ret = vmbus_sendpacket(nvchan->channel, &msg, sizeof(msg),
+                                      rcd->tid, VM_PKT_COMP, 0);
+               if (unlikely(ret))
+                       return ret;
 
-/* Read the first filled slot, no change to index */
-static inline struct recv_comp_data *read_recv_comp_slot(struct netvsc_device
-                                                        *nvdev, u16 q_idx)
-{
-       struct multi_recv_comp *mrc = &nvdev->chan_table[q_idx].mrc;
-       u32 filled, avail;
-
-       if (unlikely(!mrc->buf))
-               return NULL;
+               if (++mrc->first == nvdev->recv_completion_cnt)
+                       mrc->first = 0;
+       }
 
-       count_recv_comp_slot(nvdev, q_idx, &filled, &avail);
-       if (!filled)
-               return NULL;
+       /* receive completion ring has been emptied */
+       if (unlikely(nvdev->destroy))
+               wake_up(&nvdev->wait_drain);
 
-       return mrc->buf + mrc->first * sizeof(struct recv_comp_data);
+       return 0;
 }
 
-/* Put the first filled slot back to available pool */
-static inline void put_recv_comp_slot(struct netvsc_device *nvdev, u16 q_idx)
+/* Count how many receive completions are outstanding */
+static void recv_comp_slot_avail(const struct netvsc_device *nvdev,
+                                const struct multi_recv_comp *mrc,
+                                u32 *filled, u32 *avail)
 {
-       struct multi_recv_comp *mrc = &nvdev->chan_table[q_idx].mrc;
-       int num_recv;
-
-       mrc->first = (mrc->first + 1) % NETVSC_RECVSLOT_MAX;
+       u32 count = nvdev->recv_completion_cnt;
 
-       num_recv = atomic_dec_return(&nvdev->num_outstanding_recvs);
+       if (mrc->next >= mrc->first)
+               *filled = mrc->next - mrc->first;
+       else
+               *filled = (count - mrc->first) + mrc->next;
 
-       if (nvdev->destroy && num_recv == 0)
-               wake_up(&nvdev->wait_drain);
+       *avail = count - *filled - 1;
 }
 
-/* Check and send pending recv completions */
-static void netvsc_chk_recv_comp(struct netvsc_device *nvdev,
-                                struct vmbus_channel *channel, u16 q_idx)
+/* Add receive complete to ring to send to host. */
+static void enq_receive_complete(struct net_device *ndev,
+                                struct netvsc_device *nvdev, u16 q_idx,
+                                u64 tid, u32 status)
 {
+       struct netvsc_channel *nvchan = &nvdev->chan_table[q_idx];
+       struct multi_recv_comp *mrc = &nvchan->mrc;
        struct recv_comp_data *rcd;
-       int ret;
-
-       while (true) {
-               rcd = read_recv_comp_slot(nvdev, q_idx);
-               if (!rcd)
-                       break;
+       u32 filled, avail;
 
-               ret = netvsc_send_recv_completion(channel, rcd->tid,
-                                                 rcd->status);
-               if (ret)
-                       break;
+       recv_comp_slot_avail(nvdev, mrc, &filled, &avail);
 
-               put_recv_comp_slot(nvdev, q_idx);
+       if (unlikely(filled > NAPI_POLL_WEIGHT)) {
+               send_recv_completions(nvchan);
+               recv_comp_slot_avail(nvdev, mrc, &filled, &avail);
        }
-}
-
-#define NETVSC_RCD_WATERMARK 80
-
-/* Get next available slot */
-static inline struct recv_comp_data *get_recv_comp_slot(
-       struct netvsc_device *nvdev, struct vmbus_channel *channel, u16 q_idx)
-{
-       struct multi_recv_comp *mrc = &nvdev->chan_table[q_idx].mrc;
-       u32 filled, avail, next;
-       struct recv_comp_data *rcd;
-
-       if (unlikely(!nvdev->recv_section))
-               return NULL;
-
-       if (unlikely(!mrc->buf))
-               return NULL;
 
-       if (atomic_read(&nvdev->num_outstanding_recvs) >
-           nvdev->recv_section->num_sub_allocs * NETVSC_RCD_WATERMARK / 100)
-               netvsc_chk_recv_comp(nvdev, channel, q_idx);
-
-       count_recv_comp_slot(nvdev, q_idx, &filled, &avail);
-       if (!avail)
-               return NULL;
-
-       next = mrc->next;
-       rcd = mrc->buf + next * sizeof(struct recv_comp_data);
-       mrc->next = (next + 1) % NETVSC_RECVSLOT_MAX;
+       if (unlikely(!avail)) {
+               netdev_err(ndev, "Recv_comp full buf q:%hd, tid:%llx\n",
+                          q_idx, tid);
+               return;
+       }
 
-       atomic_inc(&nvdev->num_outstanding_recvs);
+       rcd = mrc->slots + mrc->next;
+       rcd->tid = tid;
+       rcd->status = status;
 
-       return rcd;
+       if (++mrc->next == nvdev->recv_completion_cnt)
+               mrc->next = 0;
 }
 
 static int netvsc_receive(struct net_device *ndev,
-                  struct netvsc_device *net_device,
-                  struct net_device_context *net_device_ctx,
-                  struct hv_device *device,
-                  struct vmbus_channel *channel,
-                  const struct vmpacket_descriptor *desc,
-                  struct nvsp_message *nvsp)
+                         struct netvsc_device *net_device,
+                         struct net_device_context *net_device_ctx,
+                         struct hv_device *device,
+                         struct vmbus_channel *channel,
+                         const struct vmpacket_descriptor *desc,
+                         struct nvsp_message *nvsp)
 {
        const struct vmtransfer_page_packet_header *vmxferpage_packet
                = container_of(desc, const struct vmtransfer_page_packet_header, d);
@@ -1081,7 +1051,6 @@ static int netvsc_receive(struct net_device *ndev,
        u32 status = NVSP_STAT_SUCCESS;
        int i;
        int count = 0;
-       int ret;
 
        /* Make sure this is a valid nvsp packet */
        if (unlikely(nvsp->hdr.msg_type != NVSP_MSG1_TYPE_SEND_RNDIS_PKT)) {
@@ -1112,25 +1081,9 @@ static int netvsc_receive(struct net_device *ndev,
                                              channel, data, buflen);
        }
 
-       if (net_device->chan_table[q_idx].mrc.buf) {
-               struct recv_comp_data *rcd;
+       enq_receive_complete(ndev, net_device, q_idx,
+                            vmxferpage_packet->d.trans_id, status);
 
-               rcd = get_recv_comp_slot(net_device, channel, q_idx);
-               if (rcd) {
-                       rcd->tid = vmxferpage_packet->d.trans_id;
-                       rcd->status = status;
-               } else {
-                       netdev_err(ndev, "Recv_comp full buf q:%hd, tid:%llx\n",
-                                  q_idx, vmxferpage_packet->d.trans_id);
-               }
-       } else {
-               ret = netvsc_send_recv_completion(channel,
-                                                 vmxferpage_packet->d.trans_id,
-                                                 status);
-               if (ret)
-                       netdev_err(ndev, "Recv_comp q:%hd, tid:%llx, err:%d\n",
-                                  q_idx, vmxferpage_packet->d.trans_id, ret);
-       }
        return count;
 }
 
@@ -1229,7 +1182,6 @@ int netvsc_poll(struct napi_struct *napi, int budget)
        struct netvsc_device *net_device = nvchan->net_device;
        struct vmbus_channel *channel = nvchan->channel;
        struct hv_device *device = netvsc_channel_to_device(channel);
-       u16 q_idx = channel->offermsg.offer.sub_channel_index;
        struct net_device *ndev = hv_get_drvdata(device);
        int work_done = 0;
 
@@ -1243,17 +1195,23 @@ int netvsc_poll(struct napi_struct *napi, int budget)
                nvchan->desc = hv_pkt_iter_next(channel, nvchan->desc);
        }
 
-       /* If receive ring was exhausted
-        * and not doing busy poll
+       /* if ring is empty, signal host */
+       if (!nvchan->desc)
+               hv_pkt_iter_close(channel);
+
+       /* If send of pending receive completions suceeded
+        *   and did not exhaust NAPI budget this time
+        *   and not doing busy poll
         * then re-enable host interrupts
-        *  and reschedule if ring is not empty.
+        *     and reschedule if ring is not empty.
         */
-       if (work_done < budget &&
+       if (send_recv_completions(nvchan) == 0 &&
+           work_done < budget &&
            napi_complete_done(napi, work_done) &&
-           hv_end_read(&channel->inbound) != 0)
+           hv_end_read(&channel->inbound)) {
+               hv_begin_read(&channel->inbound);
                napi_reschedule(napi);
-
-       netvsc_chk_recv_comp(net_device, channel, q_idx);
+       }
 
        /* Driver may overshoot since multiple packets per descriptor */
        return min(work_done, budget);
@@ -1265,10 +1223,15 @@ int netvsc_poll(struct napi_struct *napi, int budget)
 void netvsc_channel_cb(void *context)
 {
        struct netvsc_channel *nvchan = context;
+       struct vmbus_channel *channel = nvchan->channel;
+       struct hv_ring_buffer_info *rbi = &channel->inbound;
+
+       /* preload first vmpacket descriptor */
+       prefetch(hv_get_ring_buffer(rbi) + rbi->priv_read_index);
 
        if (napi_schedule_prep(&nvchan->napi)) {
                /* disable interupts from host */
-               hv_begin_read(&nvchan->channel->inbound);
+               hv_begin_read(rbi);
 
                __napi_schedule(&nvchan->napi);
        }
@@ -1349,7 +1312,8 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device,
        return net_device;
 
 close:
-       netif_napi_del(&net_device->chan_table[0].napi);
+       RCU_INIT_POINTER(net_device_ctx->nvdev, NULL);
+       napi_disable(&net_device->chan_table[0].napi);
 
        /* Now, we can close the channel safely */
        vmbus_close(device->channel);
index a164981..9453eef 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/if_vlan.h>
 #include <linux/in.h>
 #include <linux/slab.h>
+#include <linux/rtnetlink.h>
+
 #include <net/arp.h>
 #include <net/route.h>
 #include <net/sock.h>
@@ -280,9 +282,8 @@ static u32 fill_pg_buf(struct page *page, u32 offset, u32 len,
 
 static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb,
                           struct hv_netvsc_packet *packet,
-                          struct hv_page_buffer **page_buf)
+                          struct hv_page_buffer *pb)
 {
-       struct hv_page_buffer *pb = *page_buf;
        u32 slots_used = 0;
        char *data = skb->data;
        int frags = skb_shinfo(skb)->nr_frags;
@@ -315,14 +316,34 @@ static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb,
        return slots_used;
 }
 
-/* Estimate number of page buffers neede to transmit
- * Need at most 2 for RNDIS header plus skb body and fragments.
- */
-static unsigned int netvsc_get_slots(const struct sk_buff *skb)
+static int count_skb_frag_slots(struct sk_buff *skb)
 {
-       return PFN_UP(offset_in_page(skb->data) + skb_headlen(skb))
-               + skb_shinfo(skb)->nr_frags
-               + 2;
+       int i, frags = skb_shinfo(skb)->nr_frags;
+       int pages = 0;
+
+       for (i = 0; i < frags; i++) {
+               skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+               unsigned long size = skb_frag_size(frag);
+               unsigned long offset = frag->page_offset;
+
+               /* Skip unused frames from start of page */
+               offset &= ~PAGE_MASK;
+               pages += PFN_UP(offset + size);
+       }
+       return pages;
+}
+
+static int netvsc_get_slots(struct sk_buff *skb)
+{
+       char *data = skb->data;
+       unsigned int offset = offset_in_page(data);
+       unsigned int len = skb_headlen(skb);
+       int slots;
+       int frag_slots;
+
+       slots = DIV_ROUND_UP(offset + len, PAGE_SIZE);
+       frag_slots = count_skb_frag_slots(skb);
+       return slots + frag_slots;
 }
 
 static u32 net_checksum_info(struct sk_buff *skb)
@@ -339,7 +360,7 @@ static u32 net_checksum_info(struct sk_buff *skb)
 
                if (ip6->nexthdr == IPPROTO_TCP)
                        return TRANSPORT_INFO_IPV6_TCP;
-               else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
+               else if (ip6->nexthdr == IPPROTO_UDP)
                        return TRANSPORT_INFO_IPV6_UDP;
        }
 
@@ -357,21 +378,23 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
        u32 rndis_msg_size;
        struct rndis_per_packet_info *ppi;
        u32 hash;
-       struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
-       struct hv_page_buffer *pb = page_buf;
+       struct hv_page_buffer pb[MAX_PAGE_BUFFER_COUNT];
 
-       /* We can only transmit MAX_PAGE_BUFFER_COUNT number
+       /* We will atmost need two pages to describe the rndis
+        * header. We can only transmit MAX_PAGE_BUFFER_COUNT number
         * of pages in a single packet. If skb is scattered around
         * more pages we try linearizing it.
         */
-       num_data_pgs = netvsc_get_slots(skb);
+
+       num_data_pgs = netvsc_get_slots(skb) + 2;
+
        if (unlikely(num_data_pgs > MAX_PAGE_BUFFER_COUNT)) {
                ++net_device_ctx->eth_stats.tx_scattered;
 
                if (skb_linearize(skb))
                        goto no_memory;
 
-               num_data_pgs = netvsc_get_slots(skb);
+               num_data_pgs = netvsc_get_slots(skb) + 2;
                if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
                        ++net_device_ctx->eth_stats.tx_too_big;
                        goto drop;
@@ -501,12 +524,12 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
        rndis_msg->msg_len += rndis_msg_size;
        packet->total_data_buflen = rndis_msg->msg_len;
        packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
-                                              skb, packet, &pb);
+                                              skb, packet, pb);
 
        /* timestamp packet in software */
        skb_tx_timestamp(skb);
 
-       ret = netvsc_send(net_device_ctx, packet, rndis_msg, &pb, skb);
+       ret = netvsc_send(net_device_ctx, packet, rndis_msg, pb, skb);
        if (likely(ret == 0))
                return NETDEV_TX_OK;
 
@@ -713,39 +736,16 @@ static void netvsc_get_channels(struct net_device *net,
        }
 }
 
-static int netvsc_set_queues(struct net_device *net, struct hv_device *dev,
-                            u32 num_chn)
-{
-       struct netvsc_device_info device_info;
-       struct netvsc_device *net_device;
-       int ret;
-
-       memset(&device_info, 0, sizeof(device_info));
-       device_info.num_chn = num_chn;
-       device_info.ring_size = ring_size;
-       device_info.max_num_vrss_chns = num_chn;
-
-       ret = netif_set_real_num_tx_queues(net, num_chn);
-       if (ret)
-               return ret;
-
-       ret = netif_set_real_num_rx_queues(net, num_chn);
-       if (ret)
-               return ret;
-
-       net_device = rndis_filter_device_add(dev, &device_info);
-       return IS_ERR(net_device) ? PTR_ERR(net_device) : 0;
-}
-
 static int netvsc_set_channels(struct net_device *net,
                               struct ethtool_channels *channels)
 {
        struct net_device_context *net_device_ctx = netdev_priv(net);
        struct hv_device *dev = net_device_ctx->device_ctx;
        struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
-       unsigned int count = channels->combined_count;
+       unsigned int orig, count = channels->combined_count;
+       struct netvsc_device_info device_info;
        bool was_opened;
-       int ret;
+       int ret = 0;
 
        /* We do not support separate count for rx, tx, or other */
        if (count == 0 ||
@@ -764,19 +764,27 @@ static int netvsc_set_channels(struct net_device *net,
        if (count > nvdev->max_chn)
                return -EINVAL;
 
+       orig = nvdev->num_chn;
        was_opened = rndis_filter_opened(nvdev);
        if (was_opened)
                rndis_filter_close(nvdev);
 
        rndis_filter_device_remove(dev, nvdev);
 
-       ret = netvsc_set_queues(net, dev, count);
-       if (ret == 0)
-               nvdev->num_chn = count;
-       else
-               netvsc_set_queues(net, dev, nvdev->num_chn);
+       memset(&device_info, 0, sizeof(device_info));
+       device_info.num_chn = count;
+       device_info.ring_size = ring_size;
+
+       nvdev = rndis_filter_device_add(dev, &device_info);
+       if (!IS_ERR(nvdev)) {
+               netif_set_real_num_tx_queues(net, nvdev->num_chn);
+               netif_set_real_num_rx_queues(net, nvdev->num_chn);
+       } else {
+               ret = PTR_ERR(nvdev);
+               device_info.num_chn = orig;
+               rndis_filter_device_add(dev, &device_info);
+       }
 
-       nvdev = rtnl_dereference(net_device_ctx->nvdev);
        if (was_opened)
                rndis_filter_open(nvdev);
 
@@ -863,7 +871,6 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
        memset(&device_info, 0, sizeof(device_info));
        device_info.ring_size = ring_size;
        device_info.num_chn = nvdev->num_chn;
-       device_info.max_num_vrss_chns = nvdev->num_chn;
 
        rndis_filter_device_remove(hdev, nvdev);
 
@@ -937,6 +944,8 @@ static void netvsc_get_stats64(struct net_device *net,
 
 static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
 {
+       struct net_device_context *ndc = netdev_priv(ndev);
+       struct netvsc_device *nvdev = rtnl_dereference(ndc->nvdev);
        struct sockaddr *addr = p;
        char save_adr[ETH_ALEN];
        unsigned char save_aatype;
@@ -949,7 +958,10 @@ static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
        if (err != 0)
                return err;
 
-       err = rndis_filter_set_device_mac(ndev, addr->sa_data);
+       if (!nvdev)
+               return -ENODEV;
+
+       err = rndis_filter_set_device_mac(nvdev, addr->sa_data);
        if (err != 0) {
                /* roll back to saved MAC */
                memcpy(ndev->dev_addr, save_adr, ETH_ALEN);
@@ -995,7 +1007,7 @@ static void netvsc_get_ethtool_stats(struct net_device *dev,
                                     struct ethtool_stats *stats, u64 *data)
 {
        struct net_device_context *ndc = netdev_priv(dev);
-       struct netvsc_device *nvdev = rcu_dereference(ndc->nvdev);
+       struct netvsc_device *nvdev = rtnl_dereference(ndc->nvdev);
        const void *nds = &ndc->eth_stats;
        const struct netvsc_stats *qstats;
        unsigned int start;
@@ -1033,7 +1045,7 @@ static void netvsc_get_ethtool_stats(struct net_device *dev,
 static void netvsc_get_strings(struct net_device *dev, u32 stringset, u8 *data)
 {
        struct net_device_context *ndc = netdev_priv(dev);
-       struct netvsc_device *nvdev = rcu_dereference(ndc->nvdev);
+       struct netvsc_device *nvdev = rtnl_dereference(ndc->nvdev);
        u8 *p = data;
        int i;
 
@@ -1091,7 +1103,7 @@ netvsc_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
                 u32 *rules)
 {
        struct net_device_context *ndc = netdev_priv(dev);
-       struct netvsc_device *nvdev = rcu_dereference(ndc->nvdev);
+       struct netvsc_device *nvdev = rtnl_dereference(ndc->nvdev);
 
        if (!nvdev)
                return -ENODEV;
@@ -1141,7 +1153,7 @@ static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
                           u8 *hfunc)
 {
        struct net_device_context *ndc = netdev_priv(dev);
-       struct netvsc_device *ndev = rcu_dereference(ndc->nvdev);
+       struct netvsc_device *ndev = rtnl_dereference(ndc->nvdev);
        struct rndis_device *rndis_dev;
        int i;
 
@@ -1548,7 +1560,6 @@ static int netvsc_probe(struct hv_device *dev,
 
        netif_set_real_num_tx_queues(net, nvdev->num_chn);
        netif_set_real_num_rx_queues(net, nvdev->num_chn);
-       rtnl_unlock();
 
        netdev_lockdep_set_classes(net);
 
index e439886..44165fe 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/if_vlan.h>
 #include <linux/nls.h>
 #include <linux/vmalloc.h>
+#include <linux/rtnetlink.h>
 
 #include "hyperv_net.h"
 
@@ -84,14 +85,6 @@ static struct rndis_device *get_rndis_device(void)
        return device;
 }
 
-static struct netvsc_device *
-net_device_to_netvsc_device(struct net_device *ndev)
-{
-       struct net_device_context *net_device_ctx = netdev_priv(ndev);
-
-       return rtnl_dereference(net_device_ctx->nvdev);
-}
-
 static struct rndis_request *get_rndis_request(struct rndis_device *dev,
                                             u32 msg_type,
                                             u32 msg_len)
@@ -221,11 +214,11 @@ static void dump_rndis_message(struct hv_device *hv_dev,
 static int rndis_filter_send_request(struct rndis_device *dev,
                                  struct rndis_request *req)
 {
-       int ret;
        struct hv_netvsc_packet *packet;
        struct hv_page_buffer page_buf[2];
        struct hv_page_buffer *pb = page_buf;
        struct net_device_context *net_device_ctx = netdev_priv(dev->ndev);
+       int ret;
 
        /* Setup the packet to send it */
        packet = &req->pkt;
@@ -251,7 +244,10 @@ static int rndis_filter_send_request(struct rndis_device *dev,
                        pb[0].len;
        }
 
-       ret = netvsc_send(net_device_ctx, packet, NULL, &pb, NULL);
+       rcu_read_lock_bh();
+       ret = netvsc_send(net_device_ctx, packet, NULL, pb, NULL);
+       rcu_read_unlock_bh();
+
        return ret;
 }
 
@@ -451,8 +447,9 @@ int rndis_filter_receive(struct net_device *ndev,
        return 0;
 }
 
-static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
-                                 void *result, u32 *result_size)
+static int rndis_filter_query_device(struct rndis_device *dev,
+                                    struct netvsc_device *nvdev,
+                                    u32 oid, void *result, u32 *result_size)
 {
        struct rndis_request *request;
        u32 inresult_size = *result_size;
@@ -479,8 +476,6 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
        query->dev_vc_handle = 0;
 
        if (oid == OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES) {
-               struct net_device_context *ndevctx = netdev_priv(dev->ndev);
-               struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev);
                struct ndis_offload *hwcaps;
                u32 nvsp_version = nvdev->nvsp_version;
                u8 ndis_rev;
@@ -549,14 +544,15 @@ cleanup:
 
 /* Get the hardware offload capabilities */
 static int
-rndis_query_hwcaps(struct rndis_device *dev, struct ndis_offload *caps)
+rndis_query_hwcaps(struct rndis_device *dev, struct netvsc_device *net_device,
+                  struct ndis_offload *caps)
 {
        u32 caps_len = sizeof(*caps);
        int ret;
 
        memset(caps, 0, sizeof(*caps));
 
-       ret = rndis_filter_query_device(dev,
+       ret = rndis_filter_query_device(dev, net_device,
                                        OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES,
                                        caps, &caps_len);
        if (ret)
@@ -585,11 +581,12 @@ rndis_query_hwcaps(struct rndis_device *dev, struct ndis_offload *caps)
        return 0;
 }
 
-static int rndis_filter_query_device_mac(struct rndis_device *dev)
+static int rndis_filter_query_device_mac(struct rndis_device *dev,
+                                        struct netvsc_device *net_device)
 {
        u32 size = ETH_ALEN;
 
-       return rndis_filter_query_device(dev,
+       return rndis_filter_query_device(dev, net_device,
                                      RNDIS_OID_802_3_PERMANENT_ADDRESS,
                                      dev->hw_mac_adr, &size);
 }
@@ -597,9 +594,9 @@ static int rndis_filter_query_device_mac(struct rndis_device *dev)
 #define NWADR_STR "NetworkAddress"
 #define NWADR_STRLEN 14
 
-int rndis_filter_set_device_mac(struct net_device *ndev, char *mac)
+int rndis_filter_set_device_mac(struct netvsc_device *nvdev,
+                               const char *mac)
 {
-       struct netvsc_device *nvdev = net_device_to_netvsc_device(ndev);
        struct rndis_device *rdev = nvdev->extension;
        struct rndis_request *request;
        struct rndis_set_request *set;
@@ -653,11 +650,8 @@ int rndis_filter_set_device_mac(struct net_device *ndev, char *mac)
        wait_for_completion(&request->wait_event);
 
        set_complete = &request->response_msg.msg.set_complete;
-       if (set_complete->status != RNDIS_STATUS_SUCCESS) {
-               netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
-                          set_complete->status);
-               ret = -EINVAL;
-       }
+       if (set_complete->status != RNDIS_STATUS_SUCCESS)
+               ret = -EIO;
 
 cleanup:
        put_rndis_request(rdev, request);
@@ -790,27 +784,27 @@ cleanup:
        return ret;
 }
 
-static int rndis_filter_query_device_link_status(struct rndis_device *dev)
+static int rndis_filter_query_device_link_status(struct rndis_device *dev,
+                                                struct netvsc_device *net_device)
 {
        u32 size = sizeof(u32);
        u32 link_status;
-       int ret;
-
-       ret = rndis_filter_query_device(dev,
-                                     RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
-                                     &link_status, &size);
 
-       return ret;
+       return rndis_filter_query_device(dev, net_device,
+                                        RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
+                                        &link_status, &size);
 }
 
-static int rndis_filter_query_link_speed(struct rndis_device *dev)
+static int rndis_filter_query_link_speed(struct rndis_device *dev,
+                                        struct netvsc_device *net_device)
 {
        u32 size = sizeof(u32);
        u32 link_speed;
        struct net_device_context *ndc;
        int ret;
 
-       ret = rndis_filter_query_device(dev, RNDIS_OID_GEN_LINK_SPEED,
+       ret = rndis_filter_query_device(dev, net_device,
+                                       RNDIS_OID_GEN_LINK_SPEED,
                                        &link_speed, &size);
 
        if (!ret) {
@@ -879,14 +873,14 @@ void rndis_filter_update(struct netvsc_device *nvdev)
        schedule_work(&rdev->mcast_work);
 }
 
-static int rndis_filter_init_device(struct rndis_device *dev)
+static int rndis_filter_init_device(struct rndis_device *dev,
+                                   struct netvsc_device *nvdev)
 {
        struct rndis_request *request;
        struct rndis_initialize_request *init;
        struct rndis_initialize_complete *init_complete;
        u32 status;
        int ret;
-       struct netvsc_device *nvdev = net_device_to_netvsc_device(dev->ndev);
 
        request = get_rndis_request(dev, RNDIS_MSG_INIT,
                        RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
@@ -934,12 +928,12 @@ static bool netvsc_device_idle(const struct netvsc_device *nvdev)
 {
        int i;
 
-       if (atomic_read(&nvdev->num_outstanding_recvs) > 0)
-               return false;
-
        for (i = 0; i < nvdev->num_chn; i++) {
                const struct netvsc_channel *nvchan = &nvdev->chan_table[i];
 
+               if (nvchan->mrc.first != nvchan->mrc.next)
+                       return false;
+
                if (atomic_read(&nvchan->queue_sends) > 0)
                        return false;
        }
@@ -1023,20 +1017,20 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc)
 {
        struct net_device *ndev =
                hv_get_drvdata(new_sc->primary_channel->device_obj);
-       struct netvsc_device *nvscdev = net_device_to_netvsc_device(ndev);
+       struct net_device_context *ndev_ctx = netdev_priv(ndev);
+       struct netvsc_device *nvscdev;
        u16 chn_index = new_sc->offermsg.offer.sub_channel_index;
        struct netvsc_channel *nvchan;
        int ret;
 
-       if (chn_index >= nvscdev->num_chn)
+       /* This is safe because this callback only happens when
+        * new device is being setup and waiting on the channel_init_wait.
+        */
+       nvscdev = rcu_dereference_raw(ndev_ctx->nvdev);
+       if (!nvscdev || chn_index >= nvscdev->num_chn)
                return;
 
        nvchan = nvscdev->chan_table + chn_index;
-       nvchan->mrc.buf
-               = vzalloc(NETVSC_RECVSLOT_MAX * sizeof(struct recv_comp_data));
-
-       if (!nvchan->mrc.buf)
-               return;
 
        /* Because the device uses NAPI, all the interrupt batching and
         * control is done via Net softirq, not the channel handling
@@ -1103,27 +1097,27 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
        rndis_device->ndev = net;
 
        /* Send the rndis initialization message */
-       ret = rndis_filter_init_device(rndis_device);
+       ret = rndis_filter_init_device(rndis_device, net_device);
        if (ret != 0)
                goto err_dev_remv;
 
        /* Get the MTU from the host */
        size = sizeof(u32);
-       ret = rndis_filter_query_device(rndis_device,
+       ret = rndis_filter_query_device(rndis_device, net_device,
                                        RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
                                        &mtu, &size);
        if (ret == 0 && size == sizeof(u32) && mtu < net->mtu)
                net->mtu = mtu;
 
        /* Get the mac address */
-       ret = rndis_filter_query_device_mac(rndis_device);
+       ret = rndis_filter_query_device_mac(rndis_device, net_device);
        if (ret != 0)
                goto err_dev_remv;
 
        memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
 
        /* Find HW offload capabilities */
-       ret = rndis_query_hwcaps(rndis_device, &hwcaps);
+       ret = rndis_query_hwcaps(rndis_device, net_device, &hwcaps);
        if (ret != 0)
                goto err_dev_remv;
 
@@ -1184,7 +1178,7 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
        if (ret)
                goto err_dev_remv;
 
-       rndis_filter_query_device_link_status(rndis_device);
+       rndis_filter_query_device_link_status(rndis_device, net_device);
 
        netdev_dbg(net, "Device MAC %pM link state %s\n",
                   rndis_device->hw_mac_adr,
@@ -1193,11 +1187,11 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
        if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5)
                return net_device;
 
-       rndis_filter_query_link_speed(rndis_device);
+       rndis_filter_query_link_speed(rndis_device, net_device);
 
        /* vRSS setup */
        memset(&rsscap, 0, rsscap_size);
-       ret = rndis_filter_query_device(rndis_device,
+       ret = rndis_filter_query_device(rndis_device, net_device,
                                        OID_GEN_RECEIVE_SCALE_CAPABILITIES,
                                        &rsscap, &rsscap_size);
        if (ret || rsscap.num_recv_que < 2)
@@ -1226,6 +1220,15 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
        if (num_rss_qs == 0)
                return net_device;
 
+       for (i = 1; i < net_device->num_chn; i++) {
+               ret = netvsc_alloc_recv_comp_ring(net_device, i);
+               if (ret) {
+                       while (--i != 0)
+                               vfree(net_device->chan_table[i].mrc.slots);
+                       goto out;
+               }
+       }
+
        refcount_set(&net_device->sc_offered, num_rss_qs);
        vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open);
 
index 6f6ed75..765de3b 100644 (file)
@@ -141,9 +141,19 @@ static int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val)
 static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val)
 {
        struct usb_device *dev = mcs->usbdev;
-       int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
-                                 MCS_RD_RTYPE, 0, reg, val, 2,
-                                 msecs_to_jiffies(MCS_CTRL_TIMEOUT));
+       void *dmabuf;
+       int ret;
+
+       dmabuf = kmalloc(sizeof(__u16), GFP_KERNEL);
+       if (!dmabuf)
+               return -ENOMEM;
+
+       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
+                             MCS_RD_RTYPE, 0, reg, dmabuf, 2,
+                             msecs_to_jiffies(MCS_CTRL_TIMEOUT));
+
+       memcpy(val, dmabuf, sizeof(__u16));
+       kfree(dmabuf);
 
        return ret;
 }
index 4daf3d0..0250aa9 100644 (file)
@@ -418,6 +418,8 @@ static int ntb_netdev_probe(struct device *client_dev)
        if (!ndev)
                return -ENOMEM;
 
+       SET_NETDEV_DEV(ndev, client_dev);
+
        dev = netdev_priv(ndev);
        dev->ndev = ndev;
        dev->pdev = pdev;
index 2dda720..928fd89 100644 (file)
@@ -7,7 +7,16 @@ menuconfig MDIO_DEVICE
        help
           MDIO devices and driver infrastructure code.
 
-if MDIO_DEVICE
+config MDIO_BUS
+       tristate
+       default m if PHYLIB=m
+       default MDIO_DEVICE
+       help
+         This internal symbol is used for link time dependencies and it
+         reflects whether the mdio_bus/mdio_device code is built as a
+         loadable module or built-in.
+
+if MDIO_BUS
 
 config MDIO_BCM_IPROC
        tristate "Broadcom iProc MDIO bus controller"
@@ -28,7 +37,6 @@ config MDIO_BCM_UNIMAC
 
 config MDIO_BITBANG
        tristate "Bitbanged MDIO buses"
-       depends on !(MDIO_DEVICE=y && PHYLIB=m)
        help
          This module implements the MDIO bus protocol in software,
          for use by low level drivers that export the ability to
@@ -127,7 +135,6 @@ config MDIO_THUNDER
        tristate "ThunderX SOCs MDIO buses"
        depends on 64BIT
        depends on PCI
-       depends on !(MDIO_DEVICE=y && PHYLIB=m)
        select MDIO_CAVIUM
        help
          This driver supports the MDIO interfaces found on Cavium
index 5d314f1..361fe99 100644 (file)
 #define MII_M1011_IMASK_INIT           0x6400
 #define MII_M1011_IMASK_CLEAR          0x0000
 
-#define MII_M1011_PHY_SCR              0x10
-#define MII_M1011_PHY_SCR_MDI          0x0000
-#define MII_M1011_PHY_SCR_MDI_X                0x0020
-#define MII_M1011_PHY_SCR_AUTO_CROSS   0x0060
-
-#define MII_M1145_PHY_EXT_SR           0x1b
-#define MII_M1145_PHY_EXT_CR           0x14
-#define MII_M1145_RGMII_RX_DELAY       0x0080
-#define MII_M1145_RGMII_TX_DELAY       0x0002
-#define MII_M1145_HWCFG_MODE_SGMII_NO_CLK      0x4
-#define MII_M1145_HWCFG_MODE_MASK              0xf
-#define MII_M1145_HWCFG_FIBER_COPPER_AUTO      0x8000
-
-#define MII_M1145_HWCFG_MODE_SGMII_NO_CLK      0x4
-#define MII_M1145_HWCFG_MODE_MASK              0xf
-#define MII_M1145_HWCFG_FIBER_COPPER_AUTO      0x8000
+#define MII_M1011_PHY_SCR                      0x10
+#define MII_M1011_PHY_SCR_DOWNSHIFT_EN         BIT(11)
+#define MII_M1011_PHY_SCR_DOWNSHIFT_SHIFT      12
+#define MII_M1011_PHY_SRC_DOWNSHIFT_MASK       0x7800
+#define MII_M1011_PHY_SCR_MDI                  (0x0 << 5)
+#define MII_M1011_PHY_SCR_MDI_X                        (0x1 << 5)
+#define MII_M1011_PHY_SCR_AUTO_CROSS           (0x3 << 5)
 
 #define MII_M1111_PHY_LED_CONTROL      0x18
 #define MII_M1111_PHY_LED_DIRECT       0x4100
 #define MII_M1111_PHY_LED_COMBINE      0x411c
 #define MII_M1111_PHY_EXT_CR           0x14
-#define MII_M1111_RX_DELAY             0x80
-#define MII_M1111_TX_DELAY             0x2
+#define MII_M1111_RGMII_RX_DELAY       BIT(7)
+#define MII_M1111_RGMII_TX_DELAY       BIT(1)
 #define MII_M1111_PHY_EXT_SR           0x1b
 
 #define MII_M1111_HWCFG_MODE_MASK              0xf
-#define MII_M1111_HWCFG_MODE_COPPER_RGMII      0xb
 #define MII_M1111_HWCFG_MODE_FIBER_RGMII       0x3
 #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK      0x4
+#define MII_M1111_HWCFG_MODE_RTBI              0x7
 #define MII_M1111_HWCFG_MODE_COPPER_RTBI       0x9
-#define MII_M1111_HWCFG_FIBER_COPPER_AUTO      0x8000
-#define MII_M1111_HWCFG_FIBER_COPPER_RES       0x2000
+#define MII_M1111_HWCFG_MODE_COPPER_RGMII      0xb
+#define MII_M1111_HWCFG_FIBER_COPPER_RES       BIT(13)
+#define MII_M1111_HWCFG_FIBER_COPPER_AUTO      BIT(15)
 
 #define MII_88E1121_PHY_MSCR_REG       21
 #define MII_88E1121_PHY_MSCR_RX_DELAY  BIT(5)
 #define MII_88E1121_PHY_MSCR_TX_DELAY  BIT(4)
-#define MII_88E1121_PHY_MSCR_DELAY_MASK        (~(0x3 << 4))
+#define MII_88E1121_PHY_MSCR_DELAY_MASK        (~(BIT(5) || BIT(4)))
 
 #define MII_88E1121_MISC_TEST                          0x1a
 #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK      0x1f00
 #define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6)
 
 /* Copper Specific Interrupt Enable Register */
-#define MII_88E1318S_PHY_CSIER                              0x12
+#define MII_88E1318S_PHY_CSIER                         0x12
 /* WOL Event Interrupt Enable */
-#define MII_88E1318S_PHY_CSIER_WOL_EIE                      BIT(7)
+#define MII_88E1318S_PHY_CSIER_WOL_EIE                 BIT(7)
 
 /* LED Timer Control Register */
-#define MII_88E1318S_PHY_LED_TCR                            0x12
-#define MII_88E1318S_PHY_LED_TCR_FORCE_INT                  BIT(15)
-#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE                BIT(7)
-#define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW             BIT(11)
+#define MII_88E1318S_PHY_LED_TCR                       0x12
+#define MII_88E1318S_PHY_LED_TCR_FORCE_INT             BIT(15)
+#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE           BIT(7)
+#define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW                BIT(11)
 
 /* Magic Packet MAC address registers */
-#define MII_88E1318S_PHY_MAGIC_PACKET_WORD2                 0x17
-#define MII_88E1318S_PHY_MAGIC_PACKET_WORD1                 0x18
-#define MII_88E1318S_PHY_MAGIC_PACKET_WORD0                 0x19
+#define MII_88E1318S_PHY_MAGIC_PACKET_WORD2            0x17
+#define MII_88E1318S_PHY_MAGIC_PACKET_WORD1            0x18
+#define MII_88E1318S_PHY_MAGIC_PACKET_WORD0            0x19
 
-#define MII_88E1318S_PHY_WOL_CTRL                           0x10
-#define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS          BIT(12)
-#define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14)
+#define MII_88E1318S_PHY_WOL_CTRL                              0x10
+#define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS             BIT(12)
+#define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE    BIT(14)
 
 #define MII_88E1121_PHY_LED_CTRL       16
 #define MII_88E1121_PHY_LED_DEF                0x0030
 #define MII_M1011_PHY_STATUS_RESOLVED  0x0800
 #define MII_M1011_PHY_STATUS_LINK      0x0400
 
-#define MII_M1116R_CONTROL_REG_MAC     21
-
 #define MII_88E3016_PHY_SPEC_CTRL      0x10
 #define MII_88E3016_DISABLE_SCRAMBLER  0x0200
 #define MII_88E3016_AUTO_MDIX_CROSSOVER        0x0030
 #define LPA_FIBER_1000HALF     0x40
 #define LPA_FIBER_1000FULL     0x20
 
-#define LPA_PAUSE_FIBER        0x180
+#define LPA_PAUSE_FIBER                0x180
 #define LPA_PAUSE_ASYM_FIBER   0x100
 
 #define ADVERTISE_FIBER_1000HALF       0x40
@@ -274,6 +264,23 @@ static int marvell_set_polarity(struct phy_device *phydev, int polarity)
        return 0;
 }
 
+static int marvell_set_downshift(struct phy_device *phydev, bool enable,
+                                u8 retries)
+{
+       int reg;
+
+       reg = phy_read(phydev, MII_M1011_PHY_SCR);
+       if (reg < 0)
+               return reg;
+
+       reg &= MII_M1011_PHY_SRC_DOWNSHIFT_MASK;
+       reg |= ((retries - 1) << MII_M1011_PHY_SCR_DOWNSHIFT_SHIFT);
+       if (enable)
+               reg |= MII_M1011_PHY_SCR_DOWNSHIFT_EN;
+
+       return phy_write(phydev, MII_M1011_PHY_SCR, reg);
+}
+
 static int marvell_config_aneg(struct phy_device *phydev)
 {
        int err;
@@ -292,17 +299,11 @@ static int marvell_config_aneg(struct phy_device *phydev)
                return err;
 
        if (phydev->autoneg != AUTONEG_ENABLE) {
-               int bmcr;
-
                /* A write to speed/duplex bits (that is performed by
                 * genphy_config_aneg() call above) must be followed by
                 * a software reset. Otherwise, the write has no effect.
                 */
-               bmcr = phy_read(phydev, MII_BMCR);
-               if (bmcr < 0)
-                       return bmcr;
-
-               err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET);
+               err = genphy_soft_reset(phydev);
                if (err < 0)
                        return err;
        }
@@ -318,8 +319,7 @@ static int m88e1101_config_aneg(struct phy_device *phydev)
         * that certain registers get written in order
         * to restart autonegotiation
         */
-       err = phy_write(phydev, MII_BMCR, BMCR_RESET);
-
+       err = genphy_soft_reset(phydev);
        if (err < 0)
                return err;
 
@@ -354,7 +354,7 @@ static int m88e1111_config_aneg(struct phy_device *phydev)
         * that certain registers get written in order
         * to restart autonegotiation
         */
-       err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+       err = genphy_soft_reset(phydev);
 
        err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
        if (err < 0)
@@ -370,17 +370,11 @@ static int m88e1111_config_aneg(struct phy_device *phydev)
                return err;
 
        if (phydev->autoneg != AUTONEG_ENABLE) {
-               int bmcr;
-
                /* A write to speed/duplex bits (that is performed by
                 * genphy_config_aneg() call above) must be followed by
                 * a software reset. Otherwise, the write has no effect.
                 */
-               bmcr = phy_read(phydev, MII_BMCR);
-               if (bmcr < 0)
-                       return bmcr;
-
-               err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET);
+               err = genphy_soft_reset(phydev);
                if (err < 0)
                        return err;
        }
@@ -466,7 +460,7 @@ static int marvell_of_reg_init(struct phy_device *phydev)
 }
 #endif /* CONFIG_OF_MDIO */
 
-static int m88e1121_config_aneg(struct phy_device *phydev)
+static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)
 {
        int err, oldpage, mscr;
 
@@ -474,31 +468,45 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
        if (oldpage < 0)
                return oldpage;
 
-       if (phy_interface_is_rgmii(phydev)) {
-               mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
-                       MII_88E1121_PHY_MSCR_DELAY_MASK;
-
-               if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
-                       mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
-                                MII_88E1121_PHY_MSCR_TX_DELAY);
-               else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
-                       mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
-               else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
-                       mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
-
-               err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
-               if (err < 0)
-                       return err;
+       mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG);
+       if (mscr < 0) {
+               err = mscr;
+               goto out;
        }
 
+       mscr &= MII_88E1121_PHY_MSCR_DELAY_MASK;
+
+       if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+               mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
+                        MII_88E1121_PHY_MSCR_TX_DELAY);
+       else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+               mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
+       else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+               mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
+
+       err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
+
+out:
        marvell_set_page(phydev, oldpage);
 
-       err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+       return err;
+}
+
+static int m88e1121_config_aneg(struct phy_device *phydev)
+{
+       int err = 0;
+
+       if (phy_interface_is_rgmii(phydev)) {
+               err = m88e1121_config_aneg_rgmii_delays(phydev);
+               if (err)
+                       return err;
+       }
+
+       err = genphy_soft_reset(phydev);
        if (err < 0)
                return err;
 
-       err = phy_write(phydev, MII_M1011_PHY_SCR,
-                       MII_M1011_PHY_SCR_AUTO_CROSS);
+       err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
        if (err < 0)
                return err;
 
@@ -596,7 +604,7 @@ static int marvell_config_aneg_fiber(struct phy_device *phydev)
 
        if (changed == 0) {
                /* Advertisement hasn't changed, but maybe aneg was never on to
-                * begin with?  Or maybe phy was isolated?
+                * begin with?  Or maybe phy was isolated?
                 */
                int ctl = phy_read(phydev, MII_BMCR);
 
@@ -653,12 +661,9 @@ static int marvell_config_init(struct phy_device *phydev)
 
 static int m88e1116r_config_init(struct phy_device *phydev)
 {
-       int temp;
        int err;
 
-       temp = phy_read(phydev, MII_BMCR);
-       temp |= BMCR_RESET;
-       err = phy_write(phydev, MII_BMCR, temp);
+       err = genphy_soft_reset(phydev);
        if (err < 0)
                return err;
 
@@ -668,35 +673,22 @@ static int m88e1116r_config_init(struct phy_device *phydev)
        if (err < 0)
                return err;
 
-       temp = phy_read(phydev, MII_M1011_PHY_SCR);
-       temp |= (7 << 12);      /* max number of gigabit attempts */
-       temp |= (1 << 11);      /* enable downshift */
-       temp |= MII_M1011_PHY_SCR_AUTO_CROSS;
-       err = phy_write(phydev, MII_M1011_PHY_SCR, temp);
+       err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
        if (err < 0)
                return err;
 
-       err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE);
-       if (err < 0)
-               return err;
-       temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC);
-       temp |= (1 << 5);
-       temp |= (1 << 4);
-       err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp);
+       err = marvell_set_downshift(phydev, true, 8);
        if (err < 0)
                return err;
-       err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
+
+       err = m88e1121_config_aneg_rgmii_delays(phydev);
        if (err < 0)
                return err;
 
-       temp = phy_read(phydev, MII_BMCR);
-       temp |= BMCR_RESET;
-       err = phy_write(phydev, MII_BMCR, temp);
+       err = genphy_soft_reset(phydev);
        if (err < 0)
                return err;
 
-       mdelay(500);
-
        return marvell_config_init(phydev);
 }
 
@@ -719,9 +711,29 @@ static int m88e3016_config_init(struct phy_device *phydev)
        return marvell_config_init(phydev);
 }
 
-static int m88e1111_config_init_rgmii(struct phy_device *phydev)
+static int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev,
+                                          u16 mode,
+                                          int fibre_copper_auto)
+{
+       int temp;
+
+       temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+       if (temp < 0)
+               return temp;
+
+       temp &= ~(MII_M1111_HWCFG_MODE_MASK |
+                 MII_M1111_HWCFG_FIBER_COPPER_AUTO |
+                 MII_M1111_HWCFG_FIBER_COPPER_RES);
+       temp |= mode;
+
+       if (fibre_copper_auto)
+               temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
+
+       return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+}
+
+static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev)
 {
-       int err;
        int temp;
 
        temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
@@ -729,16 +741,24 @@ static int m88e1111_config_init_rgmii(struct phy_device *phydev)
                return temp;
 
        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
-               temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
+               temp |= (MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY);
        } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
-               temp &= ~MII_M1111_TX_DELAY;
-               temp |= MII_M1111_RX_DELAY;
+               temp &= ~MII_M1111_RGMII_TX_DELAY;
+               temp |= MII_M1111_RGMII_RX_DELAY;
        } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
-               temp &= ~MII_M1111_RX_DELAY;
-               temp |= MII_M1111_TX_DELAY;
+               temp &= ~MII_M1111_RGMII_RX_DELAY;
+               temp |= MII_M1111_RGMII_TX_DELAY;
        }
 
-       err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
+       return phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
+}
+
+static int m88e1111_config_init_rgmii(struct phy_device *phydev)
+{
+       int temp;
+       int err;
+
+       err = m88e1111_config_init_rgmii_delays(phydev);
        if (err < 0)
                return err;
 
@@ -759,17 +779,11 @@ static int m88e1111_config_init_rgmii(struct phy_device *phydev)
 static int m88e1111_config_init_sgmii(struct phy_device *phydev)
 {
        int err;
-       int temp;
-
-       temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
-       if (temp < 0)
-               return temp;
-
-       temp &= ~(MII_M1111_HWCFG_MODE_MASK);
-       temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
-       temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
 
-       err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+       err = m88e1111_config_init_hwcfg_mode(
+               phydev,
+               MII_M1111_HWCFG_MODE_SGMII_NO_CLK,
+               MII_M1111_HWCFG_FIBER_COPPER_AUTO);
        if (err < 0)
                return err;
 
@@ -780,48 +794,27 @@ static int m88e1111_config_init_sgmii(struct phy_device *phydev)
 static int m88e1111_config_init_rtbi(struct phy_device *phydev)
 {
        int err;
-       int temp;
 
-       temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
-       if (temp < 0)
-               return temp;
-
-       temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
-       err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
-       if (err < 0)
+       err = m88e1111_config_init_rgmii_delays(phydev);
+       if (err)
                return err;
 
-       temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
-       if (temp < 0)
-               return temp;
-
-       temp &= ~(MII_M1111_HWCFG_MODE_MASK |
-                 MII_M1111_HWCFG_FIBER_COPPER_RES);
-       temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
-
-       err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+       err = m88e1111_config_init_hwcfg_mode(
+               phydev,
+               MII_M1111_HWCFG_MODE_RTBI,
+               MII_M1111_HWCFG_FIBER_COPPER_AUTO);
        if (err < 0)
                return err;
 
        /* soft reset */
-       err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+       err = genphy_soft_reset(phydev);
        if (err < 0)
                return err;
 
-       do
-               temp = phy_read(phydev, MII_BMCR);
-       while (temp & BMCR_RESET);
-
-       temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
-       if (temp < 0)
-               return temp;
-
-       temp &= ~(MII_M1111_HWCFG_MODE_MASK |
-                 MII_M1111_HWCFG_FIBER_COPPER_RES);
-       temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI |
-               MII_M1111_HWCFG_FIBER_COPPER_AUTO;
-
-       return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+       return m88e1111_config_init_hwcfg_mode(
+               phydev,
+               MII_M1111_HWCFG_MODE_RTBI,
+               MII_M1111_HWCFG_FIBER_COPPER_AUTO);
 }
 
 static int m88e1111_config_init(struct phy_device *phydev)
@@ -850,7 +843,7 @@ static int m88e1111_config_init(struct phy_device *phydev)
        if (err < 0)
                return err;
 
-       return phy_write(phydev, MII_BMCR, BMCR_RESET);
+       return genphy_soft_reset(phydev);
 }
 
 static int m88e1121_config_init(struct phy_device *phydev)
@@ -912,12 +905,11 @@ static int m88e1118_config_aneg(struct phy_device *phydev)
 {
        int err;
 
-       err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+       err = genphy_soft_reset(phydev);
        if (err < 0)
                return err;
 
-       err = phy_write(phydev, MII_M1011_PHY_SCR,
-                       MII_M1011_PHY_SCR_AUTO_CROSS);
+       err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
        if (err < 0)
                return err;
 
@@ -961,7 +953,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
        if (err < 0)
                return err;
 
-       return phy_write(phydev, MII_BMCR, BMCR_RESET);
+       return genphy_soft_reset(phydev);
 }
 
 static int m88e1149_config_init(struct phy_device *phydev)
@@ -987,20 +979,15 @@ static int m88e1149_config_init(struct phy_device *phydev)
        if (err < 0)
                return err;
 
-       return phy_write(phydev, MII_BMCR, BMCR_RESET);
+       return genphy_soft_reset(phydev);
 }
 
 static int m88e1145_config_init_rgmii(struct phy_device *phydev)
 {
+       int temp;
        int err;
-       int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
-
-       if (temp < 0)
-               return temp;
 
-       temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
-
-       err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
+       err = m88e1111_config_init_rgmii_delays(phydev);
        if (err < 0)
                return err;
 
@@ -1032,16 +1019,9 @@ static int m88e1145_config_init_rgmii(struct phy_device *phydev)
 
 static int m88e1145_config_init_sgmii(struct phy_device *phydev)
 {
-       int temp = phy_read(phydev, MII_M1145_PHY_EXT_SR);
-
-       if (temp < 0)
-               return temp;
-
-       temp &= ~MII_M1145_HWCFG_MODE_MASK;
-       temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK;
-       temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO;
-
-       return phy_write(phydev, MII_M1145_PHY_EXT_SR, temp);
+       return m88e1111_config_init_hwcfg_mode(
+               phydev, MII_M1111_HWCFG_MODE_SGMII_NO_CLK,
+               MII_M1111_HWCFG_FIBER_COPPER_AUTO);
 }
 
 static int m88e1145_config_init(struct phy_device *phydev)
@@ -1515,7 +1495,7 @@ static void marvell_get_strings(struct phy_device *phydev, u8 *data)
 }
 
 #ifndef UINT64_MAX
-#define UINT64_MAX              (u64)(~((u64)0))
+#define UINT64_MAX             (u64)(~((u64)0))
 #endif
 static u64 marvell_get_stat(struct phy_device *phydev, int i)
 {
index 3439523..89425ca 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/of_platform.h>
 #include <linux/of_mdio.h>
 
+#include <linux/platform_data/mdio-bcm-unimac.h>
+
 #define MDIO_CMD               0x00
 #define  MDIO_START_BUSY       (1 << 29)
 #define  MDIO_READ_FAIL                (1 << 28)
@@ -41,6 +43,8 @@
 struct unimac_mdio_priv {
        struct mii_bus          *mii_bus;
        void __iomem            *base;
+       int (*wait_func)        (void *wait_func_data);
+       void                    *wait_func_data;
 };
 
 static inline void unimac_mdio_start(struct unimac_mdio_priv *priv)
@@ -57,10 +61,28 @@ 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_poll(void *wait_func_data)
+{
+       struct unimac_mdio_priv *priv = wait_func_data;
+       unsigned int timeout = 1000;
+
+       do {
+               if (!unimac_mdio_busy(priv))
+                       return 0;
+
+               usleep_range(1000, 2000);
+       } while (timeout--);
+
+       if (!timeout)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
 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;
+       int ret;
        u32 cmd;
 
        /* Prepare the read operation */
@@ -70,15 +92,9 @@ static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
        /* Start MDIO transaction */
        unimac_mdio_start(priv);
 
-       do {
-               if (!unimac_mdio_busy(priv))
-                       break;
-
-               usleep_range(1000, 2000);
-       } while (timeout--);
-
-       if (!timeout)
-               return -ETIMEDOUT;
+       ret = priv->wait_func(priv->wait_func_data);
+       if (ret)
+               return ret;
 
        cmd = __raw_readl(priv->base + MDIO_CMD);
 
@@ -97,7 +113,6 @@ 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 */
@@ -107,17 +122,7 @@ static int unimac_mdio_write(struct mii_bus *bus, int phy_id,
 
        unimac_mdio_start(priv);
 
-       do {
-               if (!unimac_mdio_busy(priv))
-                       break;
-
-               usleep_range(1000, 2000);
-       } while (timeout--);
-
-       if (!timeout)
-               return -ETIMEDOUT;
-
-       return 0;
+       return priv->wait_func(priv->wait_func_data);
 }
 
 /* Workaround for integrated BCM7xxx Gigabit PHYs which have a problem with
@@ -155,8 +160,10 @@ static int unimac_mdio_reset(struct mii_bus *bus)
        }
 
        for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
-               if (read_mask & 1 << addr)
+               if (read_mask & 1 << addr) {
+                       dev_dbg(&bus->dev, "Workaround for PHY @ %d\n", addr);
                        mdiobus_read(bus, addr, MII_BMSR);
+               }
        }
 
        return 0;
@@ -164,6 +171,7 @@ static int unimac_mdio_reset(struct mii_bus *bus)
 
 static int unimac_mdio_probe(struct platform_device *pdev)
 {
+       struct unimac_mdio_pdata *pdata = pdev->dev.platform_data;
        struct unimac_mdio_priv *priv;
        struct device_node *np;
        struct mii_bus *bus;
@@ -193,12 +201,21 @@ static int unimac_mdio_probe(struct platform_device *pdev)
 
        bus = priv->mii_bus;
        bus->priv = priv;
-       bus->name = "unimac MII bus";
+       if (pdata) {
+               bus->name = pdata->bus_name;
+               priv->wait_func = pdata->wait_func;
+               priv->wait_func_data = pdata->wait_func_data;
+               bus->phy_mask = ~pdata->phy_mask;
+       } else {
+               bus->name = "unimac MII bus";
+               priv->wait_func_data = priv;
+               priv->wait_func = unimac_mdio_poll;
+       }
        bus->parent = &pdev->dev;
        bus->read = unimac_mdio_read;
        bus->write = unimac_mdio_write;
        bus->reset = unimac_mdio_reset;
-       snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id);
 
        ret = of_mdiobus_register(bus, np);
        if (ret) {
@@ -240,7 +257,7 @@ MODULE_DEVICE_TABLE(of, unimac_mdio_ids);
 
 static struct platform_driver unimac_mdio_driver = {
        .driver = {
-               .name = "unimac-mdio",
+               .name = UNIMAC_MDIO_DRV_NAME,
                .of_match_table = unimac_mdio_ids,
        },
        .probe  = unimac_mdio_probe,
@@ -251,4 +268,4 @@ 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");
+MODULE_ALIAS("platform:" UNIMAC_MDIO_DRV_NAME);
index 6a33646..c3825c7 100644 (file)
@@ -105,7 +105,7 @@ static int mdio_mux_mmioreg_probe(struct platform_device *pdev)
        const __be32 *iprop;
        int len, ret;
 
-       dev_dbg(&pdev->dev, "probing node %s\n", np->full_name);
+       dev_dbg(&pdev->dev, "probing node %pOF\n", np);
 
        s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
        if (!s)
@@ -113,8 +113,8 @@ static int mdio_mux_mmioreg_probe(struct platform_device *pdev)
 
        ret = of_address_to_resource(np, 0, &res);
        if (ret) {
-               dev_err(&pdev->dev, "could not obtain memory map for node %s\n",
-                       np->full_name);
+               dev_err(&pdev->dev, "could not obtain memory map for node %pOF\n",
+                       np);
                return ret;
        }
        s->phys = res.start;
@@ -145,15 +145,15 @@ static int mdio_mux_mmioreg_probe(struct platform_device *pdev)
        for_each_available_child_of_node(np, np2) {
                iprop = of_get_property(np2, "reg", &len);
                if (!iprop || len != sizeof(uint32_t)) {
-                       dev_err(&pdev->dev, "mdio-mux child node %s is "
-                               "missing a 'reg' property\n", np2->full_name);
+                       dev_err(&pdev->dev, "mdio-mux child node %pOF is "
+                               "missing a 'reg' property\n", np2);
                        of_node_put(np2);
                        return -ENODEV;
                }
                if (be32_to_cpup(iprop) & ~s->mask) {
-                       dev_err(&pdev->dev, "mdio-mux child node %s has "
+                       dev_err(&pdev->dev, "mdio-mux child node %pOF has "
                                "a 'reg' value with unmasked bits\n",
-                               np2->full_name);
+                               np2);
                        of_node_put(np2);
                        return -ENODEV;
                }
@@ -162,8 +162,8 @@ static int mdio_mux_mmioreg_probe(struct platform_device *pdev)
        ret = mdio_mux_init(&pdev->dev, mdio_mux_mmioreg_switch_fn,
                            &s->mux_handle, s, NULL);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register mdio-mux bus %s\n",
-                       np->full_name);
+               dev_err(&pdev->dev, "failed to register mdio-mux bus %pOF\n",
+                       np);
                return ret;
        }
 
index 00755b6..942ceaf 100644 (file)
@@ -135,19 +135,19 @@ int mdio_mux_init(struct device *dev,
        for_each_available_child_of_node(dev->of_node, child_bus_node) {
                int v;
 
-               v = of_mdio_parse_addr(dev, child_bus_node);
-               if (v < 0) {
+               r = of_property_read_u32(child_bus_node, "reg", &v);
+               if (r) {
                        dev_err(dev,
-                               "Error: Failed to find reg for child %s\n",
-                               of_node_full_name(child_bus_node));
+                               "Error: Failed to find reg for child %pOF\n",
+                               child_bus_node);
                        continue;
                }
 
                cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL);
                if (cb == NULL) {
                        dev_err(dev,
-                               "Error: Failed to allocate memory for child %s\n",
-                               of_node_full_name(child_bus_node));
+                               "Error: Failed to allocate memory for child %pOF\n",
+                               child_bus_node);
                        ret_val = -ENOMEM;
                        continue;
                }
@@ -157,8 +157,8 @@ int mdio_mux_init(struct device *dev,
                cb->mii_bus = mdiobus_alloc();
                if (!cb->mii_bus) {
                        dev_err(dev,
-                               "Error: Failed to allocate MDIO bus for child %s\n",
-                               of_node_full_name(child_bus_node));
+                               "Error: Failed to allocate MDIO bus for child %pOF\n",
+                               child_bus_node);
                        ret_val = -ENOMEM;
                        devm_kfree(dev, cb);
                        continue;
@@ -174,8 +174,8 @@ int mdio_mux_init(struct device *dev,
                r = of_mdiobus_register(cb->mii_bus, child_bus_node);
                if (r) {
                        dev_err(dev,
-                               "Error: Failed to register MDIO bus for child %s\n",
-                               of_node_full_name(child_bus_node));
+                               "Error: Failed to register MDIO bus for child %pOF\n",
+                               child_bus_node);
                        mdiobus_free(cb->mii_bus);
                        devm_kfree(dev, cb);
                } else {
index d0626bf..b9d4922 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/ethtool.h>
 #include <linux/phy.h>
 #include <linux/phy_led_triggers.h>
-#include <linux/timer.h>
 #include <linux/workqueue.h>
 #include <linux/mdio.h>
 #include <linux/io.h>
@@ -705,8 +704,8 @@ EXPORT_SYMBOL(phy_start_aneg);
  *
  * Description: The PHY infrastructure can run a state machine
  *   which tracks whether the PHY is starting up, negotiating,
- *   etc.  This function starts the timer which tracks the state
- *   of the PHY.  If you want to maintain your own state machine,
+ *   etc.  This function starts the delayed workqueue which tracks
+ *   the state of the PHY. If you want to maintain your own state machine,
  *   do not call this function.
  */
 void phy_start_machine(struct phy_device *phydev)
@@ -737,9 +736,9 @@ void phy_trigger_machine(struct phy_device *phydev, bool sync)
  * phy_stop_machine - stop the PHY state machine tracking
  * @phydev: target phy_device struct
  *
- * Description: Stops the state machine timer, sets the state to UP
- *   (unless it wasn't up yet). This function must be called BEFORE
- *   phy_detach.
+ * Description: Stops the state machine delayed workqueue, sets the
+ *   state to UP (unless it wasn't up yet). This function must be
+ *   called BEFORE phy_detach.
  */
 void phy_stop_machine(struct phy_device *phydev)
 {
@@ -749,6 +748,9 @@ void phy_stop_machine(struct phy_device *phydev)
        if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)
                phydev->state = PHY_UP;
        mutex_unlock(&phydev->lock);
+
+       /* Now we can run the state machine synchronously */
+       phy_state_machine(&phydev->state_queue.work);
 }
 
 /**
@@ -1226,9 +1228,10 @@ void phy_state_machine(struct work_struct *work)
        if (err < 0)
                phy_error(phydev);
 
-       phydev_dbg(phydev, "PHY state change %s -> %s\n",
-                  phy_state_to_str(old_state),
-                  phy_state_to_str(phydev->state));
+       if (old_state != phydev->state)
+               phydev_dbg(phydev, "PHY state change %s -> %s\n",
+                          phy_state_to_str(old_state),
+                          phy_state_to_str(phydev->state));
 
        /* Only re-schedule a PHY state machine change if we are polling the
         * PHY, if PHY_IGNORE_INTERRUPT is set, then we will be moving
index 1302883..bd43039 100644 (file)
@@ -120,6 +120,7 @@ struct ppp {
        int             n_channels;     /* how many channels are attached 54 */
        spinlock_t      rlock;          /* lock for receive side 58 */
        spinlock_t      wlock;          /* lock for transmit side 5c */
+       int             *xmit_recursion __percpu; /* xmit recursion detect */
        int             mru;            /* max receive unit 60 */
        unsigned int    flags;          /* control bits 64 */
        unsigned int    xstate;         /* transmit state bits 68 */
@@ -1025,6 +1026,7 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
        struct ppp *ppp = netdev_priv(dev);
        int indx;
        int err;
+       int cpu;
 
        ppp->dev = dev;
        ppp->ppp_net = src_net;
@@ -1039,6 +1041,15 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
        INIT_LIST_HEAD(&ppp->channels);
        spin_lock_init(&ppp->rlock);
        spin_lock_init(&ppp->wlock);
+
+       ppp->xmit_recursion = alloc_percpu(int);
+       if (!ppp->xmit_recursion) {
+               err = -ENOMEM;
+               goto err1;
+       }
+       for_each_possible_cpu(cpu)
+               (*per_cpu_ptr(ppp->xmit_recursion, cpu)) = 0;
+
 #ifdef CONFIG_PPP_MULTILINK
        ppp->minseq = -1;
        skb_queue_head_init(&ppp->mrq);
@@ -1050,11 +1061,15 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
 
        err = ppp_unit_register(ppp, conf->unit, conf->ifname_is_set);
        if (err < 0)
-               return err;
+               goto err2;
 
        conf->file->private_data = &ppp->file;
 
        return 0;
+err2:
+       free_percpu(ppp->xmit_recursion);
+err1:
+       return err;
 }
 
 static const struct nla_policy ppp_nl_policy[IFLA_PPP_MAX + 1] = {
@@ -1400,18 +1415,16 @@ static void __ppp_xmit_process(struct ppp *ppp)
        ppp_xmit_unlock(ppp);
 }
 
-static DEFINE_PER_CPU(int, ppp_xmit_recursion);
-
 static void ppp_xmit_process(struct ppp *ppp)
 {
        local_bh_disable();
 
-       if (unlikely(__this_cpu_read(ppp_xmit_recursion)))
+       if (unlikely(*this_cpu_ptr(ppp->xmit_recursion)))
                goto err;
 
-       __this_cpu_inc(ppp_xmit_recursion);
+       (*this_cpu_ptr(ppp->xmit_recursion))++;
        __ppp_xmit_process(ppp);
-       __this_cpu_dec(ppp_xmit_recursion);
+       (*this_cpu_ptr(ppp->xmit_recursion))--;
 
        local_bh_enable();
 
@@ -1905,7 +1918,7 @@ static void __ppp_channel_push(struct channel *pch)
                read_lock(&pch->upl);
                ppp = pch->ppp;
                if (ppp)
-                       __ppp_xmit_process(ppp);
+                       ppp_xmit_process(ppp);
                read_unlock(&pch->upl);
        }
 }
@@ -1914,9 +1927,7 @@ static void ppp_channel_push(struct channel *pch)
 {
        local_bh_disable();
 
-       __this_cpu_inc(ppp_xmit_recursion);
        __ppp_channel_push(pch);
-       __this_cpu_dec(ppp_xmit_recursion);
 
        local_bh_enable();
 }
@@ -3057,6 +3068,7 @@ static void ppp_destroy_interface(struct ppp *ppp)
 #endif /* CONFIG_PPP_FILTER */
 
        kfree_skb(ppp->xmit_pending);
+       free_percpu(ppp->xmit_recursion);
 
        free_netdev(ppp->dev);
 }
index eac499c..6dde9a0 100644 (file)
@@ -131,7 +131,6 @@ static void del_chan(struct pppox_sock *sock)
        clear_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap);
        RCU_INIT_POINTER(callid_sock[sock->proto.pptp.src_addr.call_id], NULL);
        spin_unlock(&chan_lock);
-       synchronize_rcu();
 }
 
 static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
@@ -520,6 +519,7 @@ static int pptp_release(struct socket *sock)
 
        po = pppox_sk(sk);
        del_chan(po);
+       synchronize_rcu();
 
        pppox_unbind_sock(sk);
        sk->sk_state = PPPOX_DEAD;
index 4645704..ae53e89 100644 (file)
@@ -60,11 +60,11 @@ static struct team_port *team_port_get_rtnl(const struct net_device *dev)
 static int __set_port_dev_addr(struct net_device *port_dev,
                               const unsigned char *dev_addr)
 {
-       struct sockaddr addr;
+       struct sockaddr_storage addr;
 
-       memcpy(addr.sa_data, dev_addr, port_dev->addr_len);
-       addr.sa_family = port_dev->type;
-       return dev_set_mac_address(port_dev, &addr);
+       memcpy(addr.__data, dev_addr, port_dev->addr_len);
+       addr.ss_family = port_dev->type;
+       return dev_set_mac_address(port_dev, (struct sockaddr *)&addr);
 }
 
 static int team_port_set_orig_dev_addr(struct team_port *port)
index a93392d..68add55 100644 (file)
@@ -2593,8 +2593,16 @@ static int __init tun_init(void)
                goto err_misc;
        }
 
-       register_netdevice_notifier(&tun_notifier_block);
+       ret = register_netdevice_notifier(&tun_notifier_block);
+       if (ret) {
+               pr_err("Can't register netdevice notifier\n");
+               goto err_notifier;
+       }
+
        return  0;
+
+err_notifier:
+       misc_deregister(&tun_miscdev);
 err_misc:
        rtnl_link_unregister(&tun_link_ops);
 err_linkops:
index b401ba9..811b182 100644 (file)
@@ -768,8 +768,10 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
        u8 *buf;
        int len;
        int temp;
+       int err;
        u8 iface_no;
        struct usb_cdc_parsed_header hdr;
+       u16 curr_ntb_format;
 
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
@@ -874,6 +876,32 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
                goto error2;
        }
 
+       /*
+        * Some Huawei devices have been observed to come out of reset in NDP32 mode.
+        * Let's check if this is the case, and set the device to NDP16 mode again if
+        * needed.
+       */
+       if (ctx->drvflags & CDC_NCM_FLAG_RESET_NTB16) {
+               err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_FORMAT,
+                                     USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
+                                     0, iface_no, &curr_ntb_format, 2);
+               if (err < 0) {
+                       goto error2;
+               }
+
+               if (curr_ntb_format == USB_CDC_NCM_NTB32_FORMAT) {
+                       dev_info(&intf->dev, "resetting NTB format to 16-bit");
+                       err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT,
+                                              USB_TYPE_CLASS | USB_DIR_OUT
+                                              | USB_RECIP_INTERFACE,
+                                              USB_CDC_NCM_NTB16_FORMAT,
+                                              iface_no, NULL, 0);
+
+                       if (err < 0)
+                               goto error2;
+               }
+       }
+
        cdc_ncm_find_endpoints(dev, ctx->data);
        cdc_ncm_find_endpoints(dev, ctx->control);
        if (!dev->in || !dev->out || !dev->status) {
index 2680a65..63f2890 100644 (file)
@@ -80,6 +80,12 @@ static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev,
         * be at the end of the frame.
         */
        drvflags |= CDC_NCM_FLAG_NDP_TO_END;
+
+       /* Additionally, it has been reported that some Huawei E3372H devices, with
+        * firmware version 21.318.01.00.541, come out of reset in NTB32 format mode, hence
+        * needing to be set to the NTB16 one again.
+        */
+       drvflags |= CDC_NCM_FLAG_RESET_NTB16;
        ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags);
        if (ret)
                goto err;
index 2dfca96..340c134 100644 (file)
@@ -898,6 +898,7 @@ static const struct ethtool_ops smsc95xx_ethtool_ops = {
        .set_wol        = smsc95xx_ethtool_set_wol,
        .get_link_ksettings     = smsc95xx_get_link_ksettings,
        .set_link_ksettings     = smsc95xx_set_link_ksettings,
+       .get_ts_info    = ethtool_op_get_ts_info,
 };
 
 static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
index 9983016..e90de21 100644 (file)
@@ -57,6 +57,11 @@ DECLARE_EWMA(pkt_len, 0, 64)
 
 #define VIRTNET_DRIVER_VERSION "1.0.0"
 
+const unsigned long guest_offloads[] = { VIRTIO_NET_F_GUEST_TSO4,
+                                        VIRTIO_NET_F_GUEST_TSO6,
+                                        VIRTIO_NET_F_GUEST_ECN,
+                                        VIRTIO_NET_F_GUEST_UFO };
+
 struct virtnet_stats {
        struct u64_stats_sync tx_syncp;
        struct u64_stats_sync rx_syncp;
@@ -164,10 +169,13 @@ struct virtnet_info {
        u8 ctrl_promisc;
        u8 ctrl_allmulti;
        u16 ctrl_vid;
+       u64 ctrl_offloads;
 
        /* Ethtool settings */
        u8 duplex;
        u32 speed;
+
+       unsigned long guest_offloads;
 };
 
 struct padded_vnet_hdr {
@@ -270,6 +278,23 @@ static void skb_xmit_done(struct virtqueue *vq)
                netif_wake_subqueue(vi->dev, vq2txq(vq));
 }
 
+#define MRG_CTX_HEADER_SHIFT 22
+static void *mergeable_len_to_ctx(unsigned int truesize,
+                                 unsigned int headroom)
+{
+       return (void *)(unsigned long)((headroom << MRG_CTX_HEADER_SHIFT) | truesize);
+}
+
+static unsigned int mergeable_ctx_to_headroom(void *mrg_ctx)
+{
+       return (unsigned long)mrg_ctx >> MRG_CTX_HEADER_SHIFT;
+}
+
+static unsigned int mergeable_ctx_to_truesize(void *mrg_ctx)
+{
+       return (unsigned long)mrg_ctx & ((1 << MRG_CTX_HEADER_SHIFT) - 1);
+}
+
 /* Called from bottom half context */
 static struct sk_buff *page_to_skb(struct virtnet_info *vi,
                                   struct receive_queue *rq,
@@ -390,19 +415,85 @@ static unsigned int virtnet_get_headroom(struct virtnet_info *vi)
        return vi->xdp_queue_pairs ? VIRTIO_XDP_HEADROOM : 0;
 }
 
+/* We copy the packet for XDP in the following cases:
+ *
+ * 1) Packet is scattered across multiple rx buffers.
+ * 2) Headroom space is insufficient.
+ *
+ * This is inefficient but it's a temporary condition that
+ * we hit right after XDP is enabled and until queue is refilled
+ * with large buffers with sufficient headroom - so it should affect
+ * at most queue size packets.
+ * Afterwards, the conditions to enable
+ * XDP should preclude the underlying device from sending packets
+ * across multiple buffers (num_buf > 1), and we make sure buffers
+ * have enough headroom.
+ */
+static struct page *xdp_linearize_page(struct receive_queue *rq,
+                                      u16 *num_buf,
+                                      struct page *p,
+                                      int offset,
+                                      int page_off,
+                                      unsigned int *len)
+{
+       struct page *page = alloc_page(GFP_ATOMIC);
+
+       if (!page)
+               return NULL;
+
+       memcpy(page_address(page) + page_off, page_address(p) + offset, *len);
+       page_off += *len;
+
+       while (--*num_buf) {
+               unsigned int buflen;
+               void *buf;
+               int off;
+
+               buf = virtqueue_get_buf(rq->vq, &buflen);
+               if (unlikely(!buf))
+                       goto err_buf;
+
+               p = virt_to_head_page(buf);
+               off = buf - page_address(p);
+
+               /* guard against a misconfigured or uncooperative backend that
+                * is sending packet larger than the MTU.
+                */
+               if ((page_off + buflen) > PAGE_SIZE) {
+                       put_page(p);
+                       goto err_buf;
+               }
+
+               memcpy(page_address(page) + page_off,
+                      page_address(p) + off, buflen);
+               page_off += buflen;
+               put_page(p);
+       }
+
+       /* Headroom does not contribute to packet length */
+       *len = page_off - VIRTIO_XDP_HEADROOM;
+       return page;
+err_buf:
+       __free_pages(page, 0);
+       return NULL;
+}
+
 static struct sk_buff *receive_small(struct net_device *dev,
                                     struct virtnet_info *vi,
                                     struct receive_queue *rq,
-                                    void *buf, unsigned int len)
+                                    void *buf, void *ctx,
+                                    unsigned int len)
 {
        struct sk_buff *skb;
        struct bpf_prog *xdp_prog;
-       unsigned int xdp_headroom = virtnet_get_headroom(vi);
+       unsigned int xdp_headroom = (unsigned long)ctx;
        unsigned int header_offset = VIRTNET_RX_PAD + xdp_headroom;
        unsigned int headroom = vi->hdr_len + header_offset;
        unsigned int buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) +
                              SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+       struct page *page = virt_to_head_page(buf);
        unsigned int delta = 0;
+       struct page *xdp_page;
        len -= vi->hdr_len;
 
        rcu_read_lock();
@@ -416,6 +507,27 @@ static struct sk_buff *receive_small(struct net_device *dev,
                if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags))
                        goto err_xdp;
 
+               if (unlikely(xdp_headroom < virtnet_get_headroom(vi))) {
+                       int offset = buf - page_address(page) + header_offset;
+                       unsigned int tlen = len + vi->hdr_len;
+                       u16 num_buf = 1;
+
+                       xdp_headroom = virtnet_get_headroom(vi);
+                       header_offset = VIRTNET_RX_PAD + xdp_headroom;
+                       headroom = vi->hdr_len + header_offset;
+                       buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) +
+                                SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+                       xdp_page = xdp_linearize_page(rq, &num_buf, page,
+                                                     offset, header_offset,
+                                                     &tlen);
+                       if (!xdp_page)
+                               goto err_xdp;
+
+                       buf = page_address(xdp_page);
+                       put_page(page);
+                       page = xdp_page;
+               }
+
                xdp.data_hard_start = buf + VIRTNET_RX_PAD + vi->hdr_len;
                xdp.data = xdp.data_hard_start + xdp_headroom;
                xdp.data_end = xdp.data + len;
@@ -444,7 +556,7 @@ static struct sk_buff *receive_small(struct net_device *dev,
 
        skb = build_skb(buf, buflen);
        if (!skb) {
-               put_page(virt_to_head_page(buf));
+               put_page(page);
                goto err;
        }
        skb_reserve(skb, headroom - delta);
@@ -460,7 +572,7 @@ err:
 err_xdp:
        rcu_read_unlock();
        dev->stats.rx_dropped++;
-       put_page(virt_to_head_page(buf));
+       put_page(page);
 xdp_xmit:
        return NULL;
 }
@@ -485,66 +597,6 @@ err:
        return NULL;
 }
 
-/* The conditions to enable XDP should preclude the underlying device from
- * sending packets across multiple buffers (num_buf > 1). However per spec
- * it does not appear to be illegal to do so but rather just against convention.
- * So in order to avoid making a system unresponsive the packets are pushed
- * into a page and the XDP program is run. This will be extremely slow and we
- * push a warning to the user to fix this as soon as possible. Fixing this may
- * require resolving the underlying hardware to determine why multiple buffers
- * are being received or simply loading the XDP program in the ingress stack
- * after the skb is built because there is no advantage to running it here
- * anymore.
- */
-static struct page *xdp_linearize_page(struct receive_queue *rq,
-                                      u16 *num_buf,
-                                      struct page *p,
-                                      int offset,
-                                      unsigned int *len)
-{
-       struct page *page = alloc_page(GFP_ATOMIC);
-       unsigned int page_off = VIRTIO_XDP_HEADROOM;
-
-       if (!page)
-               return NULL;
-
-       memcpy(page_address(page) + page_off, page_address(p) + offset, *len);
-       page_off += *len;
-
-       while (--*num_buf) {
-               unsigned int buflen;
-               void *buf;
-               int off;
-
-               buf = virtqueue_get_buf(rq->vq, &buflen);
-               if (unlikely(!buf))
-                       goto err_buf;
-
-               p = virt_to_head_page(buf);
-               off = buf - page_address(p);
-
-               /* guard against a misconfigured or uncooperative backend that
-                * is sending packet larger than the MTU.
-                */
-               if ((page_off + buflen) > PAGE_SIZE) {
-                       put_page(p);
-                       goto err_buf;
-               }
-
-               memcpy(page_address(page) + page_off,
-                      page_address(p) + off, buflen);
-               page_off += buflen;
-               put_page(p);
-       }
-
-       /* Headroom does not contribute to packet length */
-       *len = page_off - VIRTIO_XDP_HEADROOM;
-       return page;
-err_buf:
-       __free_pages(page, 0);
-       return NULL;
-}
-
 static struct sk_buff *receive_mergeable(struct net_device *dev,
                                         struct virtnet_info *vi,
                                         struct receive_queue *rq,
@@ -559,6 +611,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
        struct sk_buff *head_skb, *curr_skb;
        struct bpf_prog *xdp_prog;
        unsigned int truesize;
+       unsigned int headroom = mergeable_ctx_to_headroom(ctx);
 
        head_skb = NULL;
 
@@ -571,10 +624,13 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
                u32 act;
 
                /* This happens when rx buffer size is underestimated */
-               if (unlikely(num_buf > 1)) {
+               if (unlikely(num_buf > 1 ||
+                            headroom < virtnet_get_headroom(vi))) {
                        /* linearize data for XDP */
                        xdp_page = xdp_linearize_page(rq, &num_buf,
-                                                     page, offset, &len);
+                                                     page, offset,
+                                                     VIRTIO_XDP_HEADROOM,
+                                                     &len);
                        if (!xdp_page)
                                goto err_xdp;
                        offset = VIRTIO_XDP_HEADROOM;
@@ -639,13 +695,14 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
        }
        rcu_read_unlock();
 
-       if (unlikely(len > (unsigned long)ctx)) {
+       truesize = mergeable_ctx_to_truesize(ctx);
+       if (unlikely(len > truesize)) {
                pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
                         dev->name, len, (unsigned long)ctx);
                dev->stats.rx_length_errors++;
                goto err_skb;
        }
-       truesize = (unsigned long)ctx;
+
        head_skb = page_to_skb(vi, rq, page, offset, len, truesize);
        curr_skb = head_skb;
 
@@ -665,13 +722,14 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
                }
 
                page = virt_to_head_page(buf);
-               if (unlikely(len > (unsigned long)ctx)) {
+
+               truesize = mergeable_ctx_to_truesize(ctx);
+               if (unlikely(len > truesize)) {
                        pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
                                 dev->name, len, (unsigned long)ctx);
                        dev->stats.rx_length_errors++;
                        goto err_skb;
                }
-               truesize = (unsigned long)ctx;
 
                num_skb_frags = skb_shinfo(curr_skb)->nr_frags;
                if (unlikely(num_skb_frags == MAX_SKB_FRAGS)) {
@@ -754,7 +812,7 @@ static int receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
        else if (vi->big_packets)
                skb = receive_big(dev, vi, rq, buf, len);
        else
-               skb = receive_small(dev, vi, rq, buf, len);
+               skb = receive_small(dev, vi, rq, buf, ctx, len);
 
        if (unlikely(!skb))
                return 0;
@@ -787,12 +845,18 @@ frame_err:
        return 0;
 }
 
+/* Unlike mergeable buffers, all buffers are allocated to the
+ * same size, except for the headroom. For this reason we do
+ * not need to use  mergeable_len_to_ctx here - it is enough
+ * to store the headroom as the context ignoring the truesize.
+ */
 static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq,
                             gfp_t gfp)
 {
        struct page_frag *alloc_frag = &rq->alloc_frag;
        char *buf;
        unsigned int xdp_headroom = virtnet_get_headroom(vi);
+       void *ctx = (void *)(unsigned long)xdp_headroom;
        int len = vi->hdr_len + VIRTNET_RX_PAD + GOOD_PACKET_LEN + xdp_headroom;
        int err;
 
@@ -806,10 +870,9 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq,
        alloc_frag->offset += len;
        sg_init_one(rq->sg, buf + VIRTNET_RX_PAD + xdp_headroom,
                    vi->hdr_len + GOOD_PACKET_LEN);
-       err = virtqueue_add_inbuf(rq->vq, rq->sg, 1, buf, gfp);
+       err = virtqueue_add_inbuf_ctx(rq->vq, rq->sg, 1, buf, ctx, gfp);
        if (err < 0)
                put_page(virt_to_head_page(buf));
-
        return err;
 }
 
@@ -889,21 +952,20 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi,
 
        buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset;
        buf += headroom; /* advance address leaving hole at front of pkt */
-       ctx = (void *)(unsigned long)len;
        get_page(alloc_frag->page);
        alloc_frag->offset += len + headroom;
        hole = alloc_frag->size - alloc_frag->offset;
        if (hole < len + headroom) {
                /* To avoid internal fragmentation, if there is very likely not
                 * enough space for another buffer, add the remaining space to
-                * the current buffer. This extra space is not included in
-                * the truesize stored in ctx.
+                * the current buffer.
                 */
                len += hole;
                alloc_frag->offset += hole;
        }
 
        sg_init_one(rq->sg, buf, len);
+       ctx = mergeable_len_to_ctx(len, headroom);
        err = virtqueue_add_inbuf_ctx(rq->vq, rq->sg, 1, buf, ctx, gfp);
        if (err < 0)
                put_page(virt_to_head_page(buf));
@@ -1015,7 +1077,7 @@ static int virtnet_receive(struct receive_queue *rq, int budget)
        void *buf;
        struct virtnet_stats *stats = this_cpu_ptr(vi->stats);
 
-       if (vi->mergeable_rx_bufs) {
+       if (!vi->big_packets || vi->mergeable_rx_bufs) {
                void *ctx;
 
                while (received < budget &&
@@ -1814,7 +1876,6 @@ static void virtnet_freeze_down(struct virtio_device *vdev)
 }
 
 static int init_vqs(struct virtnet_info *vi);
-static void _remove_vq_common(struct virtnet_info *vi);
 
 static int virtnet_restore_up(struct virtio_device *vdev)
 {
@@ -1843,37 +1904,45 @@ static int virtnet_restore_up(struct virtio_device *vdev)
        return err;
 }
 
-static int virtnet_reset(struct virtnet_info *vi, int curr_qp, int xdp_qp)
+static int virtnet_set_guest_offloads(struct virtnet_info *vi, u64 offloads)
 {
-       struct virtio_device *dev = vi->vdev;
-       int ret;
+       struct scatterlist sg;
+       vi->ctrl_offloads = cpu_to_virtio64(vi->vdev, offloads);
 
-       virtio_config_disable(dev);
-       dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
-       virtnet_freeze_down(dev);
-       _remove_vq_common(vi);
+       sg_init_one(&sg, &vi->ctrl_offloads, sizeof(vi->ctrl_offloads));
 
-       virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
-       virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER);
+       if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_GUEST_OFFLOADS,
+                                 VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, &sg)) {
+               dev_warn(&vi->dev->dev, "Fail to set guest offload. \n");
+               return -EINVAL;
+       }
 
-       ret = virtio_finalize_features(dev);
-       if (ret)
-               goto err;
+       return 0;
+}
 
-       vi->xdp_queue_pairs = xdp_qp;
-       ret = virtnet_restore_up(dev);
-       if (ret)
-               goto err;
-       ret = _virtnet_set_queues(vi, curr_qp);
-       if (ret)
-               goto err;
+static int virtnet_clear_guest_offloads(struct virtnet_info *vi)
+{
+       u64 offloads = 0;
 
-       virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
-       virtio_config_enable(dev);
-       return 0;
-err:
-       virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
-       return ret;
+       if (!vi->guest_offloads)
+               return 0;
+
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_CSUM))
+               offloads = 1ULL << VIRTIO_NET_F_GUEST_CSUM;
+
+       return virtnet_set_guest_offloads(vi, offloads);
+}
+
+static int virtnet_restore_guest_offloads(struct virtnet_info *vi)
+{
+       u64 offloads = vi->guest_offloads;
+
+       if (!vi->guest_offloads)
+               return 0;
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_CSUM))
+               offloads |= 1ULL << VIRTIO_NET_F_GUEST_CSUM;
+
+       return virtnet_set_guest_offloads(vi, offloads);
 }
 
 static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
@@ -1885,10 +1954,11 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
        u16 xdp_qp = 0, curr_qp;
        int i, err;
 
-       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) ||
-           virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6) ||
-           virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) ||
-           virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO)) {
+       if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)
+           && (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) ||
+               virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6) ||
+               virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) ||
+               virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO))) {
                NL_SET_ERR_MSG_MOD(extack, "Can't set XDP while host is implementing LRO, disable LRO first");
                return -EOPNOTSUPP;
        }
@@ -1922,35 +1992,35 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
                        return PTR_ERR(prog);
        }
 
-       /* Changing the headroom in buffers is a disruptive operation because
-        * existing buffers must be flushed and reallocated. This will happen
-        * when a xdp program is initially added or xdp is disabled by removing
-        * the xdp program resulting in number of XDP queues changing.
-        */
-       if (vi->xdp_queue_pairs != xdp_qp) {
-               err = virtnet_reset(vi, curr_qp + xdp_qp, xdp_qp);
-               if (err) {
-                       dev_warn(&dev->dev, "XDP reset failure.\n");
-                       goto virtio_reset_err;
-               }
-       }
+       /* Make sure NAPI is not using any XDP TX queues for RX. */
+       for (i = 0; i < vi->max_queue_pairs; i++)
+               napi_disable(&vi->rq[i].napi);
 
        netif_set_real_num_rx_queues(dev, curr_qp + xdp_qp);
+       err = _virtnet_set_queues(vi, curr_qp + xdp_qp);
+       if (err)
+               goto err;
+       vi->xdp_queue_pairs = xdp_qp;
 
        for (i = 0; i < vi->max_queue_pairs; i++) {
                old_prog = rtnl_dereference(vi->rq[i].xdp_prog);
                rcu_assign_pointer(vi->rq[i].xdp_prog, prog);
+               if (i == 0) {
+                       if (!old_prog)
+                               virtnet_clear_guest_offloads(vi);
+                       if (!prog)
+                               virtnet_restore_guest_offloads(vi);
+               }
                if (old_prog)
                        bpf_prog_put(old_prog);
+               virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
        }
 
        return 0;
 
-virtio_reset_err:
-       /* On reset error do our best to unwind XDP changes inflight and return
-        * error up to user space for resolution. The underlying reset hung on
-        * us so not much we can do here.
-        */
+err:
+       for (i = 0; i < vi->max_queue_pairs; i++)
+               virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
        if (prog)
                bpf_prog_sub(prog, vi->max_queue_pairs - 1);
        return err;
@@ -2183,7 +2253,7 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
        names = kmalloc(total_vqs * sizeof(*names), GFP_KERNEL);
        if (!names)
                goto err_names;
-       if (vi->mergeable_rx_bufs) {
+       if (!vi->big_packets || vi->mergeable_rx_bufs) {
                ctx = kzalloc(total_vqs * sizeof(*ctx), GFP_KERNEL);
                if (!ctx)
                        goto err_ctx;
@@ -2576,6 +2646,10 @@ static int virtnet_probe(struct virtio_device *vdev)
                netif_carrier_on(dev);
        }
 
+       for (i = 0; i < ARRAY_SIZE(guest_offloads); i++)
+               if (virtio_has_feature(vi->vdev, guest_offloads[i]))
+                       set_bit(guest_offloads[i], &vi->guest_offloads);
+
        pr_debug("virtnet: registered device %s with %d RX and TX vq's\n",
                 dev->name, max_queue_pairs);
 
@@ -2596,15 +2670,6 @@ free:
        return err;
 }
 
-static void _remove_vq_common(struct virtnet_info *vi)
-{
-       vi->vdev->config->reset(vi->vdev);
-       free_unused_bufs(vi);
-       _free_receive_bufs(vi);
-       free_receive_page_frags(vi);
-       virtnet_del_vqs(vi);
-}
-
 static void remove_vq_common(struct virtnet_info *vi)
 {
        vi->vdev->config->reset(vi->vdev);
@@ -2636,8 +2701,7 @@ static void virtnet_remove(struct virtio_device *vdev)
        free_netdev(vi->dev);
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int virtnet_freeze(struct virtio_device *vdev)
+static __maybe_unused int virtnet_freeze(struct virtio_device *vdev)
 {
        struct virtnet_info *vi = vdev->priv;
 
@@ -2648,7 +2712,7 @@ static int virtnet_freeze(struct virtio_device *vdev)
        return 0;
 }
 
-static int virtnet_restore(struct virtio_device *vdev)
+static __maybe_unused int virtnet_restore(struct virtio_device *vdev)
 {
        struct virtnet_info *vi = vdev->priv;
        int err;
@@ -2664,7 +2728,6 @@ static int virtnet_restore(struct virtio_device *vdev)
 
        return 0;
 }
-#endif
 
 static struct virtio_device_id id_table[] = {
        { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID },
@@ -2681,7 +2744,7 @@ static struct virtio_device_id id_table[] = {
        VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
        VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
        VIRTIO_NET_F_CTRL_MAC_ADDR, \
-       VIRTIO_NET_F_MTU
+       VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
 
 static unsigned int features[] = {
        VIRTNET_FEATURES,
@@ -2741,9 +2804,9 @@ module_init(virtio_net_driver_init);
 
 static __exit void virtio_net_driver_exit(void)
 {
+       unregister_virtio_driver(&virtio_net_driver);
        cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD);
        cpuhp_remove_multi_state(virtionet_online);
-       unregister_virtio_driver(&virtio_net_driver);
 }
 module_exit(virtio_net_driver_exit);
 
index ba1c9f9..9c51b8b 100644 (file)
@@ -311,7 +311,7 @@ struct vmxnet3_intr {
        u8  num_intrs;                  /* # of intr vectors */
        u8  event_intr_idx;             /* idx of the intr vector for event */
        u8  mod_levels[VMXNET3_LINUX_MAX_MSIX_VECT]; /* moderation level */
-       char    event_msi_vector_name[IFNAMSIZ+11];
+       char    event_msi_vector_name[IFNAMSIZ+17];
 #ifdef CONFIG_PCI_MSI
        struct msix_entry msix_entries[VMXNET3_LINUX_MAX_MSIX_VECT];
 #endif
index 96aa7e6..dbca067 100644 (file)
@@ -2608,7 +2608,7 @@ static struct device_type vxlan_type = {
  * supply the listening VXLAN udp ports. Callers are expected
  * to implement the ndo_udp_tunnel_add.
  */
-static void vxlan_push_rx_ports(struct net_device *dev)
+static void vxlan_offload_rx_ports(struct net_device *dev, bool push)
 {
        struct vxlan_sock *vs;
        struct net *net = dev_net(dev);
@@ -2617,11 +2617,19 @@ static void vxlan_push_rx_ports(struct net_device *dev)
 
        spin_lock(&vn->sock_lock);
        for (i = 0; i < PORT_HASH_SIZE; ++i) {
-               hlist_for_each_entry_rcu(vs, &vn->sock_list[i], hlist)
-                       udp_tunnel_push_rx_port(dev, vs->sock,
-                                               (vs->flags & VXLAN_F_GPE) ?
-                                               UDP_TUNNEL_TYPE_VXLAN_GPE :
-                                               UDP_TUNNEL_TYPE_VXLAN);
+               hlist_for_each_entry_rcu(vs, &vn->sock_list[i], hlist) {
+                       unsigned short type;
+
+                       if (vs->flags & VXLAN_F_GPE)
+                               type = UDP_TUNNEL_TYPE_VXLAN_GPE;
+                       else
+                               type = UDP_TUNNEL_TYPE_VXLAN;
+
+                       if (push)
+                               udp_tunnel_push_rx_port(dev, vs->sock, type);
+                       else
+                               udp_tunnel_drop_rx_port(dev, vs->sock, type);
+               }
        }
        spin_unlock(&vn->sock_lock);
 }
@@ -3630,10 +3638,15 @@ static int vxlan_netdevice_event(struct notifier_block *unused,
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
 
-       if (event == NETDEV_UNREGISTER)
+       if (event == NETDEV_UNREGISTER) {
+               vxlan_offload_rx_ports(dev, false);
                vxlan_handle_lowerdev_unregister(vn, dev);
-       else if (event == NETDEV_UDP_TUNNEL_PUSH_INFO)
-               vxlan_push_rx_ports(dev);
+       } else if (event == NETDEV_REGISTER) {
+               vxlan_offload_rx_ports(dev, true);
+       } else if (event == NETDEV_UDP_TUNNEL_PUSH_INFO ||
+                  event == NETDEV_UDP_TUNNEL_DROP_INFO) {
+               vxlan_offload_rx_ports(dev, event == NETDEV_UDP_TUNNEL_PUSH_INFO);
+       }
 
        return NOTIFY_DONE;
 }
index 2153e80..5cc3a07 100644 (file)
@@ -214,7 +214,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
 
        /* Make sure there's enough writeable headroom */
        if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) {
-               head_delta = drvr->hdrlen - skb_headroom(skb);
+               head_delta = max_t(int, drvr->hdrlen - skb_headroom(skb), 0);
 
                brcmf_dbg(INFO, "%s: insufficient headroom (%d)\n",
                          brcmf_ifname(ifp), head_delta);
index 1447a83..2d3e5e2 100644 (file)
@@ -78,10 +78,7 @@ int brcmf_debug_attach(struct brcmf_pub *drvr)
                return -ENODEV;
 
        drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
-       if (IS_ERR(drvr->dbgfs_dir))
-               return PTR_ERR(drvr->dbgfs_dir);
-
-       return 0;
+       return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
 }
 
 void brcmf_debug_detach(struct brcmf_pub *drvr)
index fbcbb43..f355612 100644 (file)
@@ -2053,12 +2053,13 @@ static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt)
                                atomic_inc(&stats->pktcow_failed);
                                return -ENOMEM;
                        }
+                       head_pad = 0;
                }
                skb_push(pkt, head_pad);
                dat_buf = (u8 *)(pkt->data);
        }
        memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
-       return 0;
+       return head_pad;
 }
 
 /**
@@ -4174,11 +4175,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
                goto fail;
        }
 
-       /* allocate scatter-gather table. sg support
-        * will be disabled upon allocation failure.
-        */
-       brcmf_sdiod_sgtable_alloc(bus->sdiodev);
-
        /* Query the F2 block size, set roundup accordingly */
        bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
        bus->roundup = min(max_roundup, bus->blocksize);
index adaa2f0..fb40ddf 100644 (file)
@@ -1189,11 +1189,11 @@ void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb)
                                next_reclaimed;
                        IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n",
                                                  next_reclaimed);
+                       iwlagn_check_ratid_empty(priv, sta_id, tid);
                }
 
                iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs);
 
-               iwlagn_check_ratid_empty(priv, sta_id, tid);
                freed = 0;
 
                /* process frames */
index 545d14b..f5c1127 100644 (file)
@@ -55,8 +55,8 @@ static inline bool iwl_trace_data(struct sk_buff *skb)
        /* also account for the RFC 1042 header, of course */
        offs += 6;
 
-       return skb->len > offs + 2 &&
-              *(__be16 *)(skb->data + offs) == cpu_to_be16(ETH_P_PAE);
+       return skb->len <= offs + 2 ||
+               *(__be16 *)(skb->data + offs) != cpu_to_be16(ETH_P_PAE);
 }
 
 static inline size_t iwl_rx_trace_len(const struct iwl_trans *trans,
index bcde1ba..c7b1e58 100644 (file)
@@ -1084,7 +1084,13 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
 
        lockdep_assert_held(&mvm->mutex);
 
-       if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+       if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status)) {
+               /*
+                * Now convert the HW_RESTART_REQUESTED flag to IN_HW_RESTART
+                * so later code will - from now on - see that we're doing it.
+                */
+               set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+               clear_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status);
                /* Clean up some internal and mac80211 state on restart */
                iwl_mvm_restart_cleanup(mvm);
        } else {
index eaacfaf..ddd8719 100644 (file)
@@ -1090,6 +1090,7 @@ struct iwl_mvm {
  * @IWL_MVM_STATUS_HW_RFKILL: HW RF-kill is asserted
  * @IWL_MVM_STATUS_HW_CTKILL: CT-kill is active
  * @IWL_MVM_STATUS_ROC_RUNNING: remain-on-channel is running
+ * @IWL_MVM_STATUS_HW_RESTART_REQUESTED: HW restart was requested
  * @IWL_MVM_STATUS_IN_HW_RESTART: HW restart is active
  * @IWL_MVM_STATUS_IN_D0I3: NIC is in D0i3
  * @IWL_MVM_STATUS_ROC_AUX_RUNNING: AUX remain-on-channel is running
@@ -1101,6 +1102,7 @@ enum iwl_mvm_status {
        IWL_MVM_STATUS_HW_RFKILL,
        IWL_MVM_STATUS_HW_CTKILL,
        IWL_MVM_STATUS_ROC_RUNNING,
+       IWL_MVM_STATUS_HW_RESTART_REQUESTED,
        IWL_MVM_STATUS_IN_HW_RESTART,
        IWL_MVM_STATUS_IN_D0I3,
        IWL_MVM_STATUS_ROC_AUX_RUNNING,
index 4d1188b..9c175d5 100644 (file)
@@ -1235,9 +1235,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
         */
        if (!mvm->fw_restart && fw_error) {
                iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert,
-                                           NULL);
-       } else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART,
-                                   &mvm->status)) {
+                                       NULL);
+       } else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
                struct iwl_mvm_reprobe *reprobe;
 
                IWL_ERR(mvm,
@@ -1268,6 +1267,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
 
                if (fw_error && mvm->fw_restart > 0)
                        mvm->fw_restart--;
+               set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status);
                ieee80211_restart_hw(mvm->hw);
        }
 }
index 4df5f13..ab66b43 100644 (file)
@@ -277,6 +277,18 @@ static void iwl_mvm_rx_agg_session_expired(unsigned long data)
 
        /* Timer expired */
        sta = rcu_dereference(ba_data->mvm->fw_id_to_mac_id[ba_data->sta_id]);
+
+       /*
+        * sta should be valid unless the following happens:
+        * The firmware asserts which triggers a reconfig flow, but
+        * the reconfig fails before we set the pointer to sta into
+        * the fw_id_to_mac_id pointer table. Mac80211 can't stop
+        * A-MDPU and hence the timer continues to run. Then, the
+        * timer expires and sta is NULL.
+        */
+       if (!sta)
+               goto unlock;
+
        mvm_sta = iwl_mvm_sta_from_mac80211(sta);
        ieee80211_stop_rx_ba_session_offl(mvm_sta->vif,
                                          sta->addr, ba_data->tid);
@@ -2015,7 +2027,8 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                                                IWL_MAX_TID_COUNT,
                                                wdg_timeout);
 
-               if (vif->type == NL80211_IFTYPE_AP)
+               if (vif->type == NL80211_IFTYPE_AP ||
+                   vif->type == NL80211_IFTYPE_ADHOC)
                        mvm->probe_queue = queue;
                else if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
                        mvm->p2p_dev_queue = queue;
index 92b3a55..f95eec5 100644 (file)
@@ -3150,7 +3150,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        init_waitqueue_head(&trans_pcie->d0i3_waitq);
 
        if (trans_pcie->msix_enabled) {
-               if (iwl_pcie_init_msix_handler(pdev, trans_pcie))
+               ret = iwl_pcie_init_msix_handler(pdev, trans_pcie);
+               if (ret)
                        goto out_no_pci;
         } else {
                ret = iwl_pcie_alloc_ict(trans);
index de50418..034bdb4 100644 (file)
@@ -298,6 +298,9 @@ void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans)
        for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
                struct iwl_txq *txq = trans_pcie->txq[i];
 
+               if (!test_bit(i, trans_pcie->queue_used))
+                       continue;
+
                spin_lock_bh(&txq->lock);
                if (txq->need_update) {
                        iwl_pcie_txq_inc_wr_ptr(trans, txq);
index 6e2e760..0b75def 100644 (file)
@@ -5704,7 +5704,7 @@ static void rt2800_init_freq_calibration(struct rt2x00_dev *rt2x00dev)
 
 static void rt2800_init_bbp_5592_glrt(struct rt2x00_dev *rt2x00dev)
 {
-       const u8 glrt_table[] = {
+       static const u8 glrt_table[] = {
                0xE0, 0x1F, 0X38, 0x32, 0x08, 0x28, 0x19, 0x0A, 0xFF, 0x00, /* 128 ~ 137 */
                0x16, 0x10, 0x10, 0x0B, 0x36, 0x2C, 0x26, 0x24, 0x42, 0x36, /* 138 ~ 147 */
                0x30, 0x2D, 0x4C, 0x46, 0x3D, 0x40, 0x3E, 0x42, 0x3D, 0x40, /* 148 ~ 157 */
index 2a7ad5f..cd5dc6d 100644 (file)
@@ -846,9 +846,6 @@ static bool _rtl8723be_init_mac(struct ieee80211_hw *hw)
                return false;
        }
 
-       if (rtlpriv->cfg->ops->get_btc_status())
-               rtlpriv->btcoexist.btc_ops->btc_power_on_setting(rtlpriv);
-
        bytetmp = rtl_read_byte(rtlpriv, REG_MULTI_FUNC_CTRL);
        rtl_write_byte(rtlpriv, REG_MULTI_FUNC_CTRL, bytetmp | BIT(3));
 
index fb1ebb0..70723e6 100644 (file)
@@ -2547,7 +2547,6 @@ struct bt_coexist_info {
 struct rtl_btc_ops {
        void (*btc_init_variables) (struct rtl_priv *rtlpriv);
        void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv);
-       void (*btc_power_on_setting)(struct rtl_priv *rtlpriv);
        void (*btc_init_hw_config) (struct rtl_priv *rtlpriv);
        void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type);
        void (*btc_lps_notify)(struct rtl_priv *rtlpriv, u8 type);
index 7116472..a89243c 100644 (file)
@@ -1,2 +1,3 @@
 source "drivers/ntb/hw/amd/Kconfig"
+source "drivers/ntb/hw/idt/Kconfig"
 source "drivers/ntb/hw/intel/Kconfig"
index 532e085..87332c3 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_NTB_AMD)  += amd/
+obj-$(CONFIG_NTB_IDT)  += idt/
 obj-$(CONFIG_NTB_INTEL)        += intel/
index 019a158..f0788aa 100644 (file)
@@ -5,6 +5,7 @@
  *   GPL LICENSE SUMMARY
  *
  *   Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of version 2 of the GNU General Public License as
@@ -13,6 +14,7 @@
  *   BSD LICENSE
  *
  *   Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
+ *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
  *   modification, are permitted provided that the following conditions
@@ -79,40 +81,42 @@ static int ndev_mw_to_bar(struct amd_ntb_dev *ndev, int idx)
        return 1 << idx;
 }
 
-static int amd_ntb_mw_count(struct ntb_dev *ntb)
+static int amd_ntb_mw_count(struct ntb_dev *ntb, int pidx)
 {
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
        return ntb_ndev(ntb)->mw_count;
 }
 
-static int amd_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
-                               phys_addr_t *base,
-                               resource_size_t *size,
-                               resource_size_t *align,
-                               resource_size_t *align_size)
+static int amd_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int idx,
+                               resource_size_t *addr_align,
+                               resource_size_t *size_align,
+                               resource_size_t *size_max)
 {
        struct amd_ntb_dev *ndev = ntb_ndev(ntb);
        int bar;
 
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
        bar = ndev_mw_to_bar(ndev, idx);
        if (bar < 0)
                return bar;
 
-       if (base)
-               *base = pci_resource_start(ndev->ntb.pdev, bar);
-
-       if (size)
-               *size = pci_resource_len(ndev->ntb.pdev, bar);
+       if (addr_align)
+               *addr_align = SZ_4K;
 
-       if (align)
-               *align = SZ_4K;
+       if (size_align)
+               *size_align = 1;
 
-       if (align_size)
-               *align_size = 1;
+       if (size_max)
+               *size_max = pci_resource_len(ndev->ntb.pdev, bar);
 
        return 0;
 }
 
-static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
                                dma_addr_t addr, resource_size_t size)
 {
        struct amd_ntb_dev *ndev = ntb_ndev(ntb);
@@ -122,11 +126,14 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
        u64 base_addr, limit, reg_val;
        int bar;
 
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
        bar = ndev_mw_to_bar(ndev, idx);
        if (bar < 0)
                return bar;
 
-       mw_size = pci_resource_len(ndev->ntb.pdev, bar);
+       mw_size = pci_resource_len(ntb->pdev, bar);
 
        /* make sure the range fits in the usable mw size */
        if (size > mw_size)
@@ -135,7 +142,7 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
        mmio = ndev->self_mmio;
        peer_mmio = ndev->peer_mmio;
 
-       base_addr = pci_resource_start(ndev->ntb.pdev, bar);
+       base_addr = pci_resource_start(ntb->pdev, bar);
 
        if (bar != 1) {
                xlat_reg = AMD_BAR23XLAT_OFFSET + ((bar - 2) << 2);
@@ -212,7 +219,7 @@ static int amd_link_is_up(struct amd_ntb_dev *ndev)
        return 0;
 }
 
-static int amd_ntb_link_is_up(struct ntb_dev *ntb,
+static u64 amd_ntb_link_is_up(struct ntb_dev *ntb,
                              enum ntb_speed *speed,
                              enum ntb_width *width)
 {
@@ -225,7 +232,7 @@ static int amd_ntb_link_is_up(struct ntb_dev *ntb,
                if (width)
                        *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
 
-               dev_dbg(ndev_dev(ndev), "link is up.\n");
+               dev_dbg(&ntb->pdev->dev, "link is up.\n");
 
                ret = 1;
        } else {
@@ -234,7 +241,7 @@ static int amd_ntb_link_is_up(struct ntb_dev *ntb,
                if (width)
                        *width = NTB_WIDTH_NONE;
 
-               dev_dbg(ndev_dev(ndev), "link is down.\n");
+               dev_dbg(&ntb->pdev->dev, "link is down.\n");
        }
 
        return ret;
@@ -254,7 +261,7 @@ static int amd_ntb_link_enable(struct ntb_dev *ntb,
 
        if (ndev->ntb.topo == NTB_TOPO_SEC)
                return -EINVAL;
-       dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
+       dev_dbg(&ntb->pdev->dev, "Enabling Link.\n");
 
        ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
        ntb_ctl |= (PMM_REG_CTL | SMM_REG_CTL);
@@ -275,7 +282,7 @@ static int amd_ntb_link_disable(struct ntb_dev *ntb)
 
        if (ndev->ntb.topo == NTB_TOPO_SEC)
                return -EINVAL;
-       dev_dbg(ndev_dev(ndev), "Enabling Link.\n");
+       dev_dbg(&ntb->pdev->dev, "Enabling Link.\n");
 
        ntb_ctl = readl(mmio + AMD_CNTL_OFFSET);
        ntb_ctl &= ~(PMM_REG_CTL | SMM_REG_CTL);
@@ -284,6 +291,31 @@ static int amd_ntb_link_disable(struct ntb_dev *ntb)
        return 0;
 }
 
+static int amd_ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+       /* The same as for inbound MWs */
+       return ntb_ndev(ntb)->mw_count;
+}
+
+static int amd_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
+                                   phys_addr_t *base, resource_size_t *size)
+{
+       struct amd_ntb_dev *ndev = ntb_ndev(ntb);
+       int bar;
+
+       bar = ndev_mw_to_bar(ndev, idx);
+       if (bar < 0)
+               return bar;
+
+       if (base)
+               *base = pci_resource_start(ndev->ntb.pdev, bar);
+
+       if (size)
+               *size = pci_resource_len(ndev->ntb.pdev, bar);
+
+       return 0;
+}
+
 static u64 amd_ntb_db_valid_mask(struct ntb_dev *ntb)
 {
        return ntb_ndev(ntb)->db_valid_mask;
@@ -400,30 +432,30 @@ static int amd_ntb_spad_write(struct ntb_dev *ntb,
        return 0;
 }
 
-static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+static u32 amd_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
 {
        struct amd_ntb_dev *ndev = ntb_ndev(ntb);
        void __iomem *mmio = ndev->self_mmio;
        u32 offset;
 
-       if (idx < 0 || idx >= ndev->spad_count)
+       if (sidx < 0 || sidx >= ndev->spad_count)
                return -EINVAL;
 
-       offset = ndev->peer_spad + (idx << 2);
+       offset = ndev->peer_spad + (sidx << 2);
        return readl(mmio + AMD_SPAD_OFFSET + offset);
 }
 
-static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
-                                  int idx, u32 val)
+static int amd_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
+                                  int sidx, u32 val)
 {
        struct amd_ntb_dev *ndev = ntb_ndev(ntb);
        void __iomem *mmio = ndev->self_mmio;
        u32 offset;
 
-       if (idx < 0 || idx >= ndev->spad_count)
+       if (sidx < 0 || sidx >= ndev->spad_count)
                return -EINVAL;
 
-       offset = ndev->peer_spad + (idx << 2);
+       offset = ndev->peer_spad + (sidx << 2);
        writel(val, mmio + AMD_SPAD_OFFSET + offset);
 
        return 0;
@@ -431,8 +463,10 @@ static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
 
 static const struct ntb_dev_ops amd_ntb_ops = {
        .mw_count               = amd_ntb_mw_count,
-       .mw_get_range           = amd_ntb_mw_get_range,
+       .mw_get_align           = amd_ntb_mw_get_align,
        .mw_set_trans           = amd_ntb_mw_set_trans,
+       .peer_mw_count          = amd_ntb_peer_mw_count,
+       .peer_mw_get_addr       = amd_ntb_peer_mw_get_addr,
        .link_is_up             = amd_ntb_link_is_up,
        .link_enable            = amd_ntb_link_enable,
        .link_disable           = amd_ntb_link_disable,
@@ -466,18 +500,19 @@ static void amd_ack_smu(struct amd_ntb_dev *ndev, u32 bit)
 static void amd_handle_event(struct amd_ntb_dev *ndev, int vec)
 {
        void __iomem *mmio = ndev->self_mmio;
+       struct device *dev = &ndev->ntb.pdev->dev;
        u32 status;
 
        status = readl(mmio + AMD_INTSTAT_OFFSET);
        if (!(status & AMD_EVENT_INTMASK))
                return;
 
-       dev_dbg(ndev_dev(ndev), "status = 0x%x and vec = %d\n", status, vec);
+       dev_dbg(dev, "status = 0x%x and vec = %d\n", status, vec);
 
        status &= AMD_EVENT_INTMASK;
        switch (status) {
        case AMD_PEER_FLUSH_EVENT:
-               dev_info(ndev_dev(ndev), "Flush is done.\n");
+               dev_info(dev, "Flush is done.\n");
                break;
        case AMD_PEER_RESET_EVENT:
                amd_ack_smu(ndev, AMD_PEER_RESET_EVENT);
@@ -503,7 +538,7 @@ static void amd_handle_event(struct amd_ntb_dev *ndev, int vec)
                status = readl(mmio + AMD_PMESTAT_OFFSET);
                /* check if this is WAKEUP event */
                if (status & 0x1)
-                       dev_info(ndev_dev(ndev), "Wakeup is done.\n");
+                       dev_info(dev, "Wakeup is done.\n");
 
                amd_ack_smu(ndev, AMD_PEER_D0_EVENT);
 
@@ -512,14 +547,14 @@ static void amd_handle_event(struct amd_ntb_dev *ndev, int vec)
                                      AMD_LINK_HB_TIMEOUT);
                break;
        default:
-               dev_info(ndev_dev(ndev), "event status = 0x%x.\n", status);
+               dev_info(dev, "event status = 0x%x.\n", status);
                break;
        }
 }
 
 static irqreturn_t ndev_interrupt(struct amd_ntb_dev *ndev, int vec)
 {
-       dev_dbg(ndev_dev(ndev), "vec %d\n", vec);
+       dev_dbg(&ndev->ntb.pdev->dev, "vec %d\n", vec);
 
        if (vec > (AMD_DB_CNT - 1) || (ndev->msix_vec_count == 1))
                amd_handle_event(ndev, vec);
@@ -541,7 +576,7 @@ static irqreturn_t ndev_irq_isr(int irq, void *dev)
 {
        struct amd_ntb_dev *ndev = dev;
 
-       return ndev_interrupt(ndev, irq - ndev_pdev(ndev)->irq);
+       return ndev_interrupt(ndev, irq - ndev->ntb.pdev->irq);
 }
 
 static int ndev_init_isr(struct amd_ntb_dev *ndev,
@@ -550,7 +585,7 @@ static int ndev_init_isr(struct amd_ntb_dev *ndev,
        struct pci_dev *pdev;
        int rc, i, msix_count, node;
 
-       pdev = ndev_pdev(ndev);
+       pdev = ndev->ntb.pdev;
 
        node = dev_to_node(&pdev->dev);
 
@@ -592,7 +627,7 @@ static int ndev_init_isr(struct amd_ntb_dev *ndev,
                        goto err_msix_request;
        }
 
-       dev_dbg(ndev_dev(ndev), "Using msix interrupts\n");
+       dev_dbg(&pdev->dev, "Using msix interrupts\n");
        ndev->db_count = msix_min;
        ndev->msix_vec_count = msix_max;
        return 0;
@@ -619,7 +654,7 @@ err_msix_vec_alloc:
        if (rc)
                goto err_msi_request;
 
-       dev_dbg(ndev_dev(ndev), "Using msi interrupts\n");
+       dev_dbg(&pdev->dev, "Using msi interrupts\n");
        ndev->db_count = 1;
        ndev->msix_vec_count = 1;
        return 0;
@@ -636,7 +671,7 @@ err_msi_enable:
        if (rc)
                goto err_intx_request;
 
-       dev_dbg(ndev_dev(ndev), "Using intx interrupts\n");
+       dev_dbg(&pdev->dev, "Using intx interrupts\n");
        ndev->db_count = 1;
        ndev->msix_vec_count = 1;
        return 0;
@@ -651,7 +686,7 @@ static void ndev_deinit_isr(struct amd_ntb_dev *ndev)
        void __iomem *mmio = ndev->self_mmio;
        int i;
 
-       pdev = ndev_pdev(ndev);
+       pdev = ndev->ntb.pdev;
 
        /* Mask all doorbell interrupts */
        ndev->db_mask = ndev->db_valid_mask;
@@ -777,7 +812,8 @@ static void ndev_init_debugfs(struct amd_ntb_dev *ndev)
                ndev->debugfs_info = NULL;
        } else {
                ndev->debugfs_dir =
-                       debugfs_create_dir(ndev_name(ndev), debugfs_dir);
+                       debugfs_create_dir(pci_name(ndev->ntb.pdev),
+                                          debugfs_dir);
                if (!ndev->debugfs_dir)
                        ndev->debugfs_info = NULL;
                else
@@ -812,7 +848,7 @@ static int amd_poll_link(struct amd_ntb_dev *ndev)
        reg = readl(mmio + AMD_SIDEINFO_OFFSET);
        reg &= NTB_LIN_STA_ACTIVE_BIT;
 
-       dev_dbg(ndev_dev(ndev), "%s: reg_val = 0x%x.\n", __func__, reg);
+       dev_dbg(&ndev->ntb.pdev->dev, "%s: reg_val = 0x%x.\n", __func__, reg);
 
        if (reg == ndev->cntl_sta)
                return 0;
@@ -894,7 +930,8 @@ static int amd_init_ntb(struct amd_ntb_dev *ndev)
 
                break;
        default:
-               dev_err(ndev_dev(ndev), "AMD NTB does not support B2B mode.\n");
+               dev_err(&ndev->ntb.pdev->dev,
+                       "AMD NTB does not support B2B mode.\n");
                return -EINVAL;
        }
 
@@ -923,10 +960,10 @@ static int amd_init_dev(struct amd_ntb_dev *ndev)
        struct pci_dev *pdev;
        int rc = 0;
 
-       pdev = ndev_pdev(ndev);
+       pdev = ndev->ntb.pdev;
 
        ndev->ntb.topo = amd_get_topo(ndev);
-       dev_dbg(ndev_dev(ndev), "AMD NTB topo is %s\n",
+       dev_dbg(&pdev->dev, "AMD NTB topo is %s\n",
                ntb_topo_string(ndev->ntb.topo));
 
        rc = amd_init_ntb(ndev);
@@ -935,7 +972,7 @@ static int amd_init_dev(struct amd_ntb_dev *ndev)
 
        rc = amd_init_isr(ndev);
        if (rc) {
-               dev_err(ndev_dev(ndev), "fail to init isr.\n");
+               dev_err(&pdev->dev, "fail to init isr.\n");
                return rc;
        }
 
@@ -973,7 +1010,7 @@ static int amd_ntb_init_pci(struct amd_ntb_dev *ndev,
                rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
                if (rc)
                        goto err_dma_mask;
-               dev_warn(ndev_dev(ndev), "Cannot DMA highmem\n");
+               dev_warn(&pdev->dev, "Cannot DMA highmem\n");
        }
 
        rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -981,7 +1018,7 @@ static int amd_ntb_init_pci(struct amd_ntb_dev *ndev,
                rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
                if (rc)
                        goto err_dma_mask;
-               dev_warn(ndev_dev(ndev), "Cannot DMA consistent highmem\n");
+               dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n");
        }
 
        ndev->self_mmio = pci_iomap(pdev, 0, 0);
@@ -1004,7 +1041,7 @@ err_pci_enable:
 
 static void amd_ntb_deinit_pci(struct amd_ntb_dev *ndev)
 {
-       struct pci_dev *pdev = ndev_pdev(ndev);
+       struct pci_dev *pdev = ndev->ntb.pdev;
 
        pci_iounmap(pdev, ndev->self_mmio);
 
index 13d73ed..8f3617a 100644 (file)
@@ -211,9 +211,6 @@ struct amd_ntb_dev {
        struct dentry *debugfs_info;
 };
 
-#define ndev_pdev(ndev) ((ndev)->ntb.pdev)
-#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
-#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
 #define ntb_ndev(__ntb) container_of(__ntb, struct amd_ntb_dev, ntb)
 #define hb_ndev(__work) container_of(__work, struct amd_ntb_dev, hb_timer.work)
 
diff --git a/drivers/ntb/hw/idt/Kconfig b/drivers/ntb/hw/idt/Kconfig
new file mode 100644 (file)
index 0000000..b360e56
--- /dev/null
@@ -0,0 +1,31 @@
+config NTB_IDT
+       tristate "IDT PCIe-switch Non-Transparent Bridge support"
+       depends on PCI
+       help
+        This driver supports NTB of cappable IDT PCIe-switches.
+
+        Some of the pre-initializations must be made before IDT PCIe-switch
+        exposes it NT-functions correctly. It should be done by either proper
+        initialisation of EEPROM connected to master smbus of the switch or
+        by BIOS using slave-SMBus interface changing corresponding registers
+        value. Evidently it must be done before PCI bus enumeration is
+        finished in Linux kernel.
+
+        First of all partitions must be activated and properly assigned to all
+        the ports with NT-functions intended to be activated (see SWPARTxCTL
+        and SWPORTxCTL registers). Then all NT-function BARs must be enabled
+        with chosen valid aperture. For memory windows related BARs the
+        aperture settings shall determine the maximum size of memory windows
+        accepted by a BAR. Note that BAR0 must map PCI configuration space
+        registers.
+
+        It's worth to note, that since a part of this driver relies on the
+        BAR settings of peer NT-functions, the BAR setups can't be done over
+        kernel PCI fixups. That's why the alternative pre-initialization
+        techniques like BIOS using SMBus interface or EEPROM should be
+        utilized. Additionally if one needs to have temperature sensor
+        information printed to system log, the corresponding registers must
+        be initialized within BIOS/EEPROM as well.
+
+        If unsure, say N.
+
diff --git a/drivers/ntb/hw/idt/Makefile b/drivers/ntb/hw/idt/Makefile
new file mode 100644 (file)
index 0000000..a102cf1
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_NTB_IDT) += ntb_hw_idt.o
diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c
new file mode 100644 (file)
index 0000000..d44d7ef
--- /dev/null
@@ -0,0 +1,2712 @@
+/*
+ *   This file is provided under a GPLv2 license.  When using or
+ *   redistributing this file, you may do so under that license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright (C) 2016 T-Platforms All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify it
+ *   under the terms and conditions of the GNU General Public License,
+ *   version 2, as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope 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, one can be found http://www.gnu.org/licenses/.
+ *
+ *   The full GNU General Public License is included in this distribution in
+ *   the file called "COPYING".
+ *
+ *   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.
+ *
+ * IDT PCIe-switch NTB Linux driver
+ *
+ * Contact Information:
+ * Serge Semin <fancer.lancer@gmail.com>, <Sergey.Semin@t-platforms.ru>
+ */
+
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/sizes.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/aer.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/debugfs.h>
+#include <linux/ntb.h>
+
+#include "ntb_hw_idt.h"
+
+#define NTB_NAME       "ntb_hw_idt"
+#define NTB_DESC       "IDT PCI-E Non-Transparent Bridge Driver"
+#define NTB_VER                "2.0"
+#define NTB_IRQNAME    "ntb_irq_idt"
+
+MODULE_DESCRIPTION(NTB_DESC);
+MODULE_VERSION(NTB_VER);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("T-platforms");
+
+/*
+ * NT Endpoint registers table simplifying a loop access to the functionally
+ * related registers
+ */
+static const struct idt_ntb_regs ntdata_tbl = {
+       { {IDT_NT_BARSETUP0,    IDT_NT_BARLIMIT0,
+          IDT_NT_BARLTBASE0,   IDT_NT_BARUTBASE0},
+         {IDT_NT_BARSETUP1,    IDT_NT_BARLIMIT1,
+          IDT_NT_BARLTBASE1,   IDT_NT_BARUTBASE1},
+         {IDT_NT_BARSETUP2,    IDT_NT_BARLIMIT2,
+          IDT_NT_BARLTBASE2,   IDT_NT_BARUTBASE2},
+         {IDT_NT_BARSETUP3,    IDT_NT_BARLIMIT3,
+          IDT_NT_BARLTBASE3,   IDT_NT_BARUTBASE3},
+         {IDT_NT_BARSETUP4,    IDT_NT_BARLIMIT4,
+          IDT_NT_BARLTBASE4,   IDT_NT_BARUTBASE4},
+         {IDT_NT_BARSETUP5,    IDT_NT_BARLIMIT5,
+          IDT_NT_BARLTBASE5,   IDT_NT_BARUTBASE5} },
+       { {IDT_NT_INMSG0,       IDT_NT_OUTMSG0, IDT_NT_INMSGSRC0},
+         {IDT_NT_INMSG1,       IDT_NT_OUTMSG1, IDT_NT_INMSGSRC1},
+         {IDT_NT_INMSG2,       IDT_NT_OUTMSG2, IDT_NT_INMSGSRC2},
+         {IDT_NT_INMSG3,       IDT_NT_OUTMSG3, IDT_NT_INMSGSRC3} }
+};
+
+/*
+ * NT Endpoint ports data table with the corresponding pcie command, link
+ * status, control and BAR-related registers
+ */
+static const struct idt_ntb_port portdata_tbl[IDT_MAX_NR_PORTS] = {
+/*0*/  { IDT_SW_NTP0_PCIECMDSTS,       IDT_SW_NTP0_PCIELCTLSTS,
+         IDT_SW_NTP0_NTCTL,
+         IDT_SW_SWPORT0CTL,            IDT_SW_SWPORT0STS,
+         { {IDT_SW_NTP0_BARSETUP0,     IDT_SW_NTP0_BARLIMIT0,
+            IDT_SW_NTP0_BARLTBASE0,    IDT_SW_NTP0_BARUTBASE0},
+           {IDT_SW_NTP0_BARSETUP1,     IDT_SW_NTP0_BARLIMIT1,
+            IDT_SW_NTP0_BARLTBASE1,    IDT_SW_NTP0_BARUTBASE1},
+           {IDT_SW_NTP0_BARSETUP2,     IDT_SW_NTP0_BARLIMIT2,
+            IDT_SW_NTP0_BARLTBASE2,    IDT_SW_NTP0_BARUTBASE2},
+           {IDT_SW_NTP0_BARSETUP3,     IDT_SW_NTP0_BARLIMIT3,
+            IDT_SW_NTP0_BARLTBASE3,    IDT_SW_NTP0_BARUTBASE3},
+           {IDT_SW_NTP0_BARSETUP4,     IDT_SW_NTP0_BARLIMIT4,
+            IDT_SW_NTP0_BARLTBASE4,    IDT_SW_NTP0_BARUTBASE4},
+           {IDT_SW_NTP0_BARSETUP5,     IDT_SW_NTP0_BARLIMIT5,
+            IDT_SW_NTP0_BARLTBASE5,    IDT_SW_NTP0_BARUTBASE5} } },
+/*1*/  {0},
+/*2*/  { IDT_SW_NTP2_PCIECMDSTS,       IDT_SW_NTP2_PCIELCTLSTS,
+         IDT_SW_NTP2_NTCTL,
+         IDT_SW_SWPORT2CTL,            IDT_SW_SWPORT2STS,
+         { {IDT_SW_NTP2_BARSETUP0,     IDT_SW_NTP2_BARLIMIT0,
+            IDT_SW_NTP2_BARLTBASE0,    IDT_SW_NTP2_BARUTBASE0},
+           {IDT_SW_NTP2_BARSETUP1,     IDT_SW_NTP2_BARLIMIT1,
+            IDT_SW_NTP2_BARLTBASE1,    IDT_SW_NTP2_BARUTBASE1},
+           {IDT_SW_NTP2_BARSETUP2,     IDT_SW_NTP2_BARLIMIT2,
+            IDT_SW_NTP2_BARLTBASE2,    IDT_SW_NTP2_BARUTBASE2},
+           {IDT_SW_NTP2_BARSETUP3,     IDT_SW_NTP2_BARLIMIT3,
+            IDT_SW_NTP2_BARLTBASE3,    IDT_SW_NTP2_BARUTBASE3},
+           {IDT_SW_NTP2_BARSETUP4,     IDT_SW_NTP2_BARLIMIT4,
+            IDT_SW_NTP2_BARLTBASE4,    IDT_SW_NTP2_BARUTBASE4},
+           {IDT_SW_NTP2_BARSETUP5,     IDT_SW_NTP2_BARLIMIT5,
+            IDT_SW_NTP2_BARLTBASE5,    IDT_SW_NTP2_BARUTBASE5} } },
+/*3*/  {0},
+/*4*/  { IDT_SW_NTP4_PCIECMDSTS,       IDT_SW_NTP4_PCIELCTLSTS,
+         IDT_SW_NTP4_NTCTL,
+         IDT_SW_SWPORT4CTL,            IDT_SW_SWPORT4STS,
+         { {IDT_SW_NTP4_BARSETUP0,     IDT_SW_NTP4_BARLIMIT0,
+            IDT_SW_NTP4_BARLTBASE0,    IDT_SW_NTP4_BARUTBASE0},
+           {IDT_SW_NTP4_BARSETUP1,     IDT_SW_NTP4_BARLIMIT1,
+            IDT_SW_NTP4_BARLTBASE1,    IDT_SW_NTP4_BARUTBASE1},
+           {IDT_SW_NTP4_BARSETUP2,     IDT_SW_NTP4_BARLIMIT2,
+            IDT_SW_NTP4_BARLTBASE2,    IDT_SW_NTP4_BARUTBASE2},
+           {IDT_SW_NTP4_BARSETUP3,     IDT_SW_NTP4_BARLIMIT3,
+            IDT_SW_NTP4_BARLTBASE3,    IDT_SW_NTP4_BARUTBASE3},
+           {IDT_SW_NTP4_BARSETUP4,     IDT_SW_NTP4_BARLIMIT4,
+            IDT_SW_NTP4_BARLTBASE4,    IDT_SW_NTP4_BARUTBASE4},
+           {IDT_SW_NTP4_BARSETUP5,     IDT_SW_NTP4_BARLIMIT5,
+            IDT_SW_NTP4_BARLTBASE5,    IDT_SW_NTP4_BARUTBASE5} } },
+/*5*/  {0},
+/*6*/  { IDT_SW_NTP6_PCIECMDSTS,       IDT_SW_NTP6_PCIELCTLSTS,
+         IDT_SW_NTP6_NTCTL,
+         IDT_SW_SWPORT6CTL,            IDT_SW_SWPORT6STS,
+         { {IDT_SW_NTP6_BARSETUP0,     IDT_SW_NTP6_BARLIMIT0,
+            IDT_SW_NTP6_BARLTBASE0,    IDT_SW_NTP6_BARUTBASE0},
+           {IDT_SW_NTP6_BARSETUP1,     IDT_SW_NTP6_BARLIMIT1,
+            IDT_SW_NTP6_BARLTBASE1,    IDT_SW_NTP6_BARUTBASE1},
+           {IDT_SW_NTP6_BARSETUP2,     IDT_SW_NTP6_BARLIMIT2,
+            IDT_SW_NTP6_BARLTBASE2,    IDT_SW_NTP6_BARUTBASE2},
+           {IDT_SW_NTP6_BARSETUP3,     IDT_SW_NTP6_BARLIMIT3,
+            IDT_SW_NTP6_BARLTBASE3,    IDT_SW_NTP6_BARUTBASE3},
+           {IDT_SW_NTP6_BARSETUP4,     IDT_SW_NTP6_BARLIMIT4,
+            IDT_SW_NTP6_BARLTBASE4,    IDT_SW_NTP6_BARUTBASE4},
+           {IDT_SW_NTP6_BARSETUP5,     IDT_SW_NTP6_BARLIMIT5,
+            IDT_SW_NTP6_BARLTBASE5,    IDT_SW_NTP6_BARUTBASE5} } },
+/*7*/  {0},
+/*8*/  { IDT_SW_NTP8_PCIECMDSTS,       IDT_SW_NTP8_PCIELCTLSTS,
+         IDT_SW_NTP8_NTCTL,
+         IDT_SW_SWPORT8CTL,            IDT_SW_SWPORT8STS,
+         { {IDT_SW_NTP8_BARSETUP0,     IDT_SW_NTP8_BARLIMIT0,
+            IDT_SW_NTP8_BARLTBASE0,    IDT_SW_NTP8_BARUTBASE0},
+           {IDT_SW_NTP8_BARSETUP1,     IDT_SW_NTP8_BARLIMIT1,
+            IDT_SW_NTP8_BARLTBASE1,    IDT_SW_NTP8_BARUTBASE1},
+           {IDT_SW_NTP8_BARSETUP2,     IDT_SW_NTP8_BARLIMIT2,
+            IDT_SW_NTP8_BARLTBASE2,    IDT_SW_NTP8_BARUTBASE2},
+           {IDT_SW_NTP8_BARSETUP3,     IDT_SW_NTP8_BARLIMIT3,
+            IDT_SW_NTP8_BARLTBASE3,    IDT_SW_NTP8_BARUTBASE3},
+           {IDT_SW_NTP8_BARSETUP4,     IDT_SW_NTP8_BARLIMIT4,
+            IDT_SW_NTP8_BARLTBASE4,    IDT_SW_NTP8_BARUTBASE4},
+           {IDT_SW_NTP8_BARSETUP5,     IDT_SW_NTP8_BARLIMIT5,
+            IDT_SW_NTP8_BARLTBASE5,    IDT_SW_NTP8_BARUTBASE5} } },
+/*9*/  {0},
+/*10*/ {0},
+/*11*/ {0},
+/*12*/ { IDT_SW_NTP12_PCIECMDSTS,      IDT_SW_NTP12_PCIELCTLSTS,
+         IDT_SW_NTP12_NTCTL,
+         IDT_SW_SWPORT12CTL,           IDT_SW_SWPORT12STS,
+         { {IDT_SW_NTP12_BARSETUP0,    IDT_SW_NTP12_BARLIMIT0,
+            IDT_SW_NTP12_BARLTBASE0,   IDT_SW_NTP12_BARUTBASE0},
+           {IDT_SW_NTP12_BARSETUP1,    IDT_SW_NTP12_BARLIMIT1,
+            IDT_SW_NTP12_BARLTBASE1,   IDT_SW_NTP12_BARUTBASE1},
+           {IDT_SW_NTP12_BARSETUP2,    IDT_SW_NTP12_BARLIMIT2,
+            IDT_SW_NTP12_BARLTBASE2,   IDT_SW_NTP12_BARUTBASE2},
+           {IDT_SW_NTP12_BARSETUP3,    IDT_SW_NTP12_BARLIMIT3,
+            IDT_SW_NTP12_BARLTBASE3,   IDT_SW_NTP12_BARUTBASE3},
+           {IDT_SW_NTP12_BARSETUP4,    IDT_SW_NTP12_BARLIMIT4,
+            IDT_SW_NTP12_BARLTBASE4,   IDT_SW_NTP12_BARUTBASE4},
+           {IDT_SW_NTP12_BARSETUP5,    IDT_SW_NTP12_BARLIMIT5,
+            IDT_SW_NTP12_BARLTBASE5,   IDT_SW_NTP12_BARUTBASE5} } },
+/*13*/ {0},
+/*14*/ {0},
+/*15*/ {0},
+/*16*/ { IDT_SW_NTP16_PCIECMDSTS,      IDT_SW_NTP16_PCIELCTLSTS,
+         IDT_SW_NTP16_NTCTL,
+         IDT_SW_SWPORT16CTL,           IDT_SW_SWPORT16STS,
+         { {IDT_SW_NTP16_BARSETUP0,    IDT_SW_NTP16_BARLIMIT0,
+            IDT_SW_NTP16_BARLTBASE0,   IDT_SW_NTP16_BARUTBASE0},
+           {IDT_SW_NTP16_BARSETUP1,    IDT_SW_NTP16_BARLIMIT1,
+            IDT_SW_NTP16_BARLTBASE1,   IDT_SW_NTP16_BARUTBASE1},
+           {IDT_SW_NTP16_BARSETUP2,    IDT_SW_NTP16_BARLIMIT2,
+            IDT_SW_NTP16_BARLTBASE2,   IDT_SW_NTP16_BARUTBASE2},
+           {IDT_SW_NTP16_BARSETUP3,    IDT_SW_NTP16_BARLIMIT3,
+            IDT_SW_NTP16_BARLTBASE3,   IDT_SW_NTP16_BARUTBASE3},
+           {IDT_SW_NTP16_BARSETUP4,    IDT_SW_NTP16_BARLIMIT4,
+            IDT_SW_NTP16_BARLTBASE4,   IDT_SW_NTP16_BARUTBASE4},
+           {IDT_SW_NTP16_BARSETUP5,    IDT_SW_NTP16_BARLIMIT5,
+            IDT_SW_NTP16_BARLTBASE5,   IDT_SW_NTP16_BARUTBASE5} } },
+/*17*/ {0},
+/*18*/ {0},
+/*19*/ {0},
+/*20*/ { IDT_SW_NTP20_PCIECMDSTS,      IDT_SW_NTP20_PCIELCTLSTS,
+         IDT_SW_NTP20_NTCTL,
+         IDT_SW_SWPORT20CTL,           IDT_SW_SWPORT20STS,
+         { {IDT_SW_NTP20_BARSETUP0,    IDT_SW_NTP20_BARLIMIT0,
+            IDT_SW_NTP20_BARLTBASE0,   IDT_SW_NTP20_BARUTBASE0},
+           {IDT_SW_NTP20_BARSETUP1,    IDT_SW_NTP20_BARLIMIT1,
+            IDT_SW_NTP20_BARLTBASE1,   IDT_SW_NTP20_BARUTBASE1},
+           {IDT_SW_NTP20_BARSETUP2,    IDT_SW_NTP20_BARLIMIT2,
+            IDT_SW_NTP20_BARLTBASE2,   IDT_SW_NTP20_BARUTBASE2},
+           {IDT_SW_NTP20_BARSETUP3,    IDT_SW_NTP20_BARLIMIT3,
+            IDT_SW_NTP20_BARLTBASE3,   IDT_SW_NTP20_BARUTBASE3},
+           {IDT_SW_NTP20_BARSETUP4,    IDT_SW_NTP20_BARLIMIT4,
+            IDT_SW_NTP20_BARLTBASE4,   IDT_SW_NTP20_BARUTBASE4},
+           {IDT_SW_NTP20_BARSETUP5,    IDT_SW_NTP20_BARLIMIT5,
+            IDT_SW_NTP20_BARLTBASE5,   IDT_SW_NTP20_BARUTBASE5} } },
+/*21*/ {0},
+/*22*/ {0},
+/*23*/ {0}
+};
+
+/*
+ * IDT PCIe-switch partitions table with the corresponding control, status
+ * and messages control registers
+ */
+static const struct idt_ntb_part partdata_tbl[IDT_MAX_NR_PARTS] = {
+/*0*/  { IDT_SW_SWPART0CTL,    IDT_SW_SWPART0STS,
+         {IDT_SW_SWP0MSGCTL0,  IDT_SW_SWP0MSGCTL1,
+          IDT_SW_SWP0MSGCTL2,  IDT_SW_SWP0MSGCTL3} },
+/*1*/  { IDT_SW_SWPART1CTL,    IDT_SW_SWPART1STS,
+         {IDT_SW_SWP1MSGCTL0,  IDT_SW_SWP1MSGCTL1,
+          IDT_SW_SWP1MSGCTL2,  IDT_SW_SWP1MSGCTL3} },
+/*2*/  { IDT_SW_SWPART2CTL,    IDT_SW_SWPART2STS,
+         {IDT_SW_SWP2MSGCTL0,  IDT_SW_SWP2MSGCTL1,
+          IDT_SW_SWP2MSGCTL2,  IDT_SW_SWP2MSGCTL3} },
+/*3*/  { IDT_SW_SWPART3CTL,    IDT_SW_SWPART3STS,
+         {IDT_SW_SWP3MSGCTL0,  IDT_SW_SWP3MSGCTL1,
+          IDT_SW_SWP3MSGCTL2,  IDT_SW_SWP3MSGCTL3} },
+/*4*/  { IDT_SW_SWPART4CTL,    IDT_SW_SWPART4STS,
+         {IDT_SW_SWP4MSGCTL0,  IDT_SW_SWP4MSGCTL1,
+          IDT_SW_SWP4MSGCTL2,  IDT_SW_SWP4MSGCTL3} },
+/*5*/  { IDT_SW_SWPART5CTL,    IDT_SW_SWPART5STS,
+         {IDT_SW_SWP5MSGCTL0,  IDT_SW_SWP5MSGCTL1,
+          IDT_SW_SWP5MSGCTL2,  IDT_SW_SWP5MSGCTL3} },
+/*6*/  { IDT_SW_SWPART6CTL,    IDT_SW_SWPART6STS,
+         {IDT_SW_SWP6MSGCTL0,  IDT_SW_SWP6MSGCTL1,
+          IDT_SW_SWP6MSGCTL2,  IDT_SW_SWP6MSGCTL3} },
+/*7*/  { IDT_SW_SWPART7CTL,    IDT_SW_SWPART7STS,
+         {IDT_SW_SWP7MSGCTL0,  IDT_SW_SWP7MSGCTL1,
+          IDT_SW_SWP7MSGCTL2,  IDT_SW_SWP7MSGCTL3} }
+};
+
+/*
+ * DebugFS directory to place the driver debug file
+ */
+static struct dentry *dbgfs_topdir;
+
+/*=============================================================================
+ *                1. IDT PCIe-switch registers IO-functions
+ *
+ *    Beside ordinary configuration space registers IDT PCIe-switch expose
+ * global configuration registers, which are used to determine state of other
+ * device ports as well as being notified of some switch-related events.
+ * Additionally all the configuration space registers of all the IDT
+ * PCIe-switch functions are mapped to the Global Address space, so each
+ * function can determine a configuration of any other PCI-function.
+ *    Functions declared in this chapter are created to encapsulate access
+ * to configuration and global registers, so the driver code just need to
+ * provide IDT NTB hardware descriptor and a register address.
+ *=============================================================================
+ */
+
+/*
+ * idt_nt_write() - PCI configuration space registers write method
+ * @ndev:      IDT NTB hardware driver descriptor
+ * @reg:       Register to write data to
+ * @data:      Value to write to the register
+ *
+ * IDT PCIe-switch registers are all Little endian.
+ */
+static void idt_nt_write(struct idt_ntb_dev *ndev,
+                        const unsigned int reg, const u32 data)
+{
+       /*
+        * It's obvious bug to request a register exceeding the maximum possible
+        * value as well as to have it unaligned.
+        */
+       if (WARN_ON(reg > IDT_REG_PCI_MAX || !IS_ALIGNED(reg, IDT_REG_ALIGN)))
+               return;
+
+       /* Just write the value to the specified register */
+       iowrite32(data, ndev->cfgspc + (ptrdiff_t)reg);
+}
+
+/*
+ * idt_nt_read() - PCI configuration space registers read method
+ * @ndev:      IDT NTB hardware driver descriptor
+ * @reg:       Register to write data to
+ *
+ * IDT PCIe-switch Global configuration registers are all Little endian.
+ *
+ * Return: register value
+ */
+static u32 idt_nt_read(struct idt_ntb_dev *ndev, const unsigned int reg)
+{
+       /*
+        * It's obvious bug to request a register exceeding the maximum possible
+        * value as well as to have it unaligned.
+        */
+       if (WARN_ON(reg > IDT_REG_PCI_MAX || !IS_ALIGNED(reg, IDT_REG_ALIGN)))
+               return ~0;
+
+       /* Just read the value from the specified register */
+       return ioread32(ndev->cfgspc + (ptrdiff_t)reg);
+}
+
+/*
+ * idt_sw_write() - Global registers write method
+ * @ndev:      IDT NTB hardware driver descriptor
+ * @reg:       Register to write data to
+ * @data:      Value to write to the register
+ *
+ * IDT PCIe-switch Global configuration registers are all Little endian.
+ */
+static void idt_sw_write(struct idt_ntb_dev *ndev,
+                        const unsigned int reg, const u32 data)
+{
+       unsigned long irqflags;
+
+       /*
+        * It's obvious bug to request a register exceeding the maximum possible
+        * value as well as to have it unaligned.
+        */
+       if (WARN_ON(reg > IDT_REG_SW_MAX || !IS_ALIGNED(reg, IDT_REG_ALIGN)))
+               return;
+
+       /* Lock GASA registers operations */
+       spin_lock_irqsave(&ndev->gasa_lock, irqflags);
+       /* Set the global register address */
+       iowrite32((u32)reg, ndev->cfgspc + (ptrdiff_t)IDT_NT_GASAADDR);
+       /* Put the new value of the register */
+       iowrite32(data, ndev->cfgspc + (ptrdiff_t)IDT_NT_GASADATA);
+       /* Make sure the PCIe transactions are executed */
+       mmiowb();
+       /* Unlock GASA registers operations */
+       spin_unlock_irqrestore(&ndev->gasa_lock, irqflags);
+}
+
+/*
+ * idt_sw_read() - Global registers read method
+ * @ndev:      IDT NTB hardware driver descriptor
+ * @reg:       Register to write data to
+ *
+ * IDT PCIe-switch Global configuration registers are all Little endian.
+ *
+ * Return: register value
+ */
+static u32 idt_sw_read(struct idt_ntb_dev *ndev, const unsigned int reg)
+{
+       unsigned long irqflags;
+       u32 data;
+
+       /*
+        * It's obvious bug to request a register exceeding the maximum possible
+        * value as well as to have it unaligned.
+        */
+       if (WARN_ON(reg > IDT_REG_SW_MAX || !IS_ALIGNED(reg, IDT_REG_ALIGN)))
+               return ~0;
+
+       /* Lock GASA registers operations */
+       spin_lock_irqsave(&ndev->gasa_lock, irqflags);
+       /* Set the global register address */
+       iowrite32((u32)reg, ndev->cfgspc + (ptrdiff_t)IDT_NT_GASAADDR);
+       /* Get the data of the register (read ops acts as MMIO barrier) */
+       data = ioread32(ndev->cfgspc + (ptrdiff_t)IDT_NT_GASADATA);
+       /* Unlock GASA registers operations */
+       spin_unlock_irqrestore(&ndev->gasa_lock, irqflags);
+
+       return data;
+}
+
+/*
+ * idt_reg_set_bits() - set bits of a passed register
+ * @ndev:      IDT NTB hardware driver descriptor
+ * @reg:       Register to change bits of
+ * @reg_lock:  Register access spin lock
+ * @valid_mask:        Mask of valid bits
+ * @set_bits:  Bitmask to set
+ *
+ * Helper method to check whether a passed bitfield is valid and set
+ * corresponding bits of a register.
+ *
+ * WARNING! Make sure the passed register isn't accessed over plane
+ * idt_nt_write() method (read method is ok to be used concurrently).
+ *
+ * Return: zero on success, negative error on invalid bitmask.
+ */
+static inline int idt_reg_set_bits(struct idt_ntb_dev *ndev, unsigned int reg,
+                                  spinlock_t *reg_lock,
+                                  u64 valid_mask, u64 set_bits)
+{
+       unsigned long irqflags;
+       u32 data;
+
+       if (set_bits & ~(u64)valid_mask)
+               return -EINVAL;
+
+       /* Lock access to the register unless the change is written back */
+       spin_lock_irqsave(reg_lock, irqflags);
+       data = idt_nt_read(ndev, reg) | (u32)set_bits;
+       idt_nt_write(ndev, reg, data);
+       /* Unlock the register */
+       spin_unlock_irqrestore(reg_lock, irqflags);
+
+       return 0;
+}
+
+/*
+ * idt_reg_clear_bits() - clear bits of a passed register
+ * @ndev:      IDT NTB hardware driver descriptor
+ * @reg:       Register to change bits of
+ * @reg_lock:  Register access spin lock
+ * @set_bits:  Bitmask to clear
+ *
+ * Helper method to check whether a passed bitfield is valid and clear
+ * corresponding bits of a register.
+ *
+ * NOTE! Invalid bits are always considered cleared so it's not an error
+ * to clear them over.
+ *
+ * WARNING! Make sure the passed register isn't accessed over plane
+ * idt_nt_write() method (read method is ok to use concurrently).
+ */
+static inline void idt_reg_clear_bits(struct idt_ntb_dev *ndev,
+                                    unsigned int reg, spinlock_t *reg_lock,
+                                    u64 clear_bits)
+{
+       unsigned long irqflags;
+       u32 data;
+
+       /* Lock access to the register unless the change is written back */
+       spin_lock_irqsave(reg_lock, irqflags);
+       data = idt_nt_read(ndev, reg) & ~(u32)clear_bits;
+       idt_nt_write(ndev, reg, data);
+       /* Unlock the register */
+       spin_unlock_irqrestore(reg_lock, irqflags);
+}
+
+/*===========================================================================
+ *                           2. Ports operations
+ *
+ *    IDT PCIe-switches can have from 3 up to 8 ports with possible
+ * NT-functions enabled. So all the possible ports need to be scanned looking
+ * for NTB activated. NTB API will have enumerated only the ports with NTB.
+ *===========================================================================
+ */
+
+/*
+ * idt_scan_ports() - scan IDT PCIe-switch ports collecting info in the tables
+ * @ndev:      Pointer to the PCI device descriptor
+ *
+ * Return: zero on success, otherwise a negative error number.
+ */
+static int idt_scan_ports(struct idt_ntb_dev *ndev)
+{
+       unsigned char pidx, port, part;
+       u32 data, portsts, partsts;
+
+       /* Retrieve the local port number */
+       data = idt_nt_read(ndev, IDT_NT_PCIELCAP);
+       ndev->port = GET_FIELD(PCIELCAP_PORTNUM, data);
+
+       /* Retrieve the local partition number */
+       portsts = idt_sw_read(ndev, portdata_tbl[ndev->port].sts);
+       ndev->part = GET_FIELD(SWPORTxSTS_SWPART, portsts);
+
+       /* Initialize port/partition -> index tables with invalid values */
+       memset(ndev->port_idx_map, -EINVAL, sizeof(ndev->port_idx_map));
+       memset(ndev->part_idx_map, -EINVAL, sizeof(ndev->part_idx_map));
+
+       /*
+        * Walk over all the possible ports checking whether any of them has
+        * NT-function activated
+        */
+       ndev->peer_cnt = 0;
+       for (pidx = 0; pidx < ndev->swcfg->port_cnt; pidx++) {
+               port = ndev->swcfg->ports[pidx];
+               /* Skip local port */
+               if (port == ndev->port)
+                       continue;
+
+               /* Read the port status register to get it partition */
+               portsts = idt_sw_read(ndev, portdata_tbl[port].sts);
+               part = GET_FIELD(SWPORTxSTS_SWPART, portsts);
+
+               /* Retrieve the partition status */
+               partsts = idt_sw_read(ndev, partdata_tbl[part].sts);
+               /* Check if partition state is active and port has NTB */
+               if (IS_FLD_SET(SWPARTxSTS_STATE, partsts, ACT) &&
+                   (IS_FLD_SET(SWPORTxSTS_MODE, portsts, NT) ||
+                    IS_FLD_SET(SWPORTxSTS_MODE, portsts, USNT) ||
+                    IS_FLD_SET(SWPORTxSTS_MODE, portsts, USNTDMA) ||
+                    IS_FLD_SET(SWPORTxSTS_MODE, portsts, NTDMA))) {
+                       /* Save the port and partition numbers */
+                       ndev->peers[ndev->peer_cnt].port = port;
+                       ndev->peers[ndev->peer_cnt].part = part;
+                       /* Fill in the port/partition -> index tables */
+                       ndev->port_idx_map[port] = ndev->peer_cnt;
+                       ndev->part_idx_map[part] = ndev->peer_cnt;
+                       ndev->peer_cnt++;
+               }
+       }
+
+       dev_dbg(&ndev->ntb.pdev->dev, "Local port: %hhu, num of peers: %hhu\n",
+               ndev->port, ndev->peer_cnt);
+
+       /* It's useless to have this driver loaded if there is no any peer */
+       if (ndev->peer_cnt == 0) {
+               dev_warn(&ndev->ntb.pdev->dev, "No active peer found\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+/*
+ * idt_ntb_port_number() - get the local port number
+ * @ntb:       NTB device context.
+ *
+ * Return: the local port number
+ */
+static int idt_ntb_port_number(struct ntb_dev *ntb)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       return ndev->port;
+}
+
+/*
+ * idt_ntb_peer_port_count() - get the number of peer ports
+ * @ntb:       NTB device context.
+ *
+ * Return the count of detected peer NT-functions.
+ *
+ * Return: number of peer ports
+ */
+static int idt_ntb_peer_port_count(struct ntb_dev *ntb)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       return ndev->peer_cnt;
+}
+
+/*
+ * idt_ntb_peer_port_number() - get peer port by given index
+ * @ntb:       NTB device context.
+ * @pidx:      Peer port index.
+ *
+ * Return: peer port or negative error
+ */
+static int idt_ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       if (pidx < 0 || ndev->peer_cnt <= pidx)
+               return -EINVAL;
+
+       /* Return the detected NT-function port number */
+       return ndev->peers[pidx].port;
+}
+
+/*
+ * idt_ntb_peer_port_idx() - get peer port index by given port number
+ * @ntb:       NTB device context.
+ * @port:      Peer port number.
+ *
+ * Internal port -> index table is pre-initialized with -EINVAL values,
+ * so we just need to return it value
+ *
+ * Return: peer NT-function port index or negative error
+ */
+static int idt_ntb_peer_port_idx(struct ntb_dev *ntb, int port)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       if (port < 0 || IDT_MAX_NR_PORTS <= port)
+               return -EINVAL;
+
+       return ndev->port_idx_map[port];
+}
+
+/*===========================================================================
+ *                         3. Link status operations
+ *    There is no any ready-to-use method to have peer ports notified if NTB
+ * link is set up or got down. Instead global signal can be used instead.
+ * In case if any one of ports changes local NTB link state, it sends
+ * global signal and clears corresponding global state bit. Then all the ports
+ * receive a notification of that, so to make client driver being aware of
+ * possible NTB link change.
+ *    Additionally each of active NT-functions is subscribed to PCIe-link
+ * state changes of peer ports.
+ *===========================================================================
+ */
+
+static void idt_ntb_local_link_disable(struct idt_ntb_dev *ndev);
+
+/*
+ * idt_init_link() - Initialize NTB link state notification subsystem
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * Function performs the basic initialization of some global registers
+ * needed to enable IRQ-based notifications of PCIe Link Up/Down and
+ * Global Signal events.
+ * NOTE Since it's not possible to determine when all the NTB peer drivers are
+ * unloaded as well as have those registers accessed concurrently, we must
+ * preinitialize them with the same value and leave it uncleared on local
+ * driver unload.
+ */
+static void idt_init_link(struct idt_ntb_dev *ndev)
+{
+       u32 part_mask, port_mask, se_mask;
+       unsigned char pidx;
+
+       /* Initialize spin locker of Mapping Table access registers */
+       spin_lock_init(&ndev->mtbl_lock);
+
+       /* Walk over all detected peers collecting port and partition masks */
+       port_mask = ~BIT(ndev->port);
+       part_mask = ~BIT(ndev->part);
+       for (pidx = 0; pidx < ndev->peer_cnt; pidx++) {
+               port_mask &= ~BIT(ndev->peers[pidx].port);
+               part_mask &= ~BIT(ndev->peers[pidx].part);
+       }
+
+       /* Clean the Link Up/Down and GLobal Signal status registers */
+       idt_sw_write(ndev, IDT_SW_SELINKUPSTS, (u32)-1);
+       idt_sw_write(ndev, IDT_SW_SELINKDNSTS, (u32)-1);
+       idt_sw_write(ndev, IDT_SW_SEGSIGSTS, (u32)-1);
+
+       /* Unmask NT-activated partitions to receive Global Switch events */
+       idt_sw_write(ndev, IDT_SW_SEPMSK, part_mask);
+
+       /* Enable PCIe Link Up events of NT-activated ports */
+       idt_sw_write(ndev, IDT_SW_SELINKUPMSK, port_mask);
+
+       /* Enable PCIe Link Down events of NT-activated ports */
+       idt_sw_write(ndev, IDT_SW_SELINKDNMSK, port_mask);
+
+       /* Unmask NT-activated partitions to receive Global Signal events */
+       idt_sw_write(ndev, IDT_SW_SEGSIGMSK, part_mask);
+
+       /* Unmask Link Up/Down and Global Switch Events */
+       se_mask = ~(IDT_SEMSK_LINKUP | IDT_SEMSK_LINKDN | IDT_SEMSK_GSIGNAL);
+       idt_sw_write(ndev, IDT_SW_SEMSK, se_mask);
+
+       dev_dbg(&ndev->ntb.pdev->dev, "NTB link status events initialized");
+}
+
+/*
+ * idt_deinit_link() - deinitialize link subsystem
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * Just disable the link back.
+ */
+static void idt_deinit_link(struct idt_ntb_dev *ndev)
+{
+       /* Disable the link */
+       idt_ntb_local_link_disable(ndev);
+
+       dev_dbg(&ndev->ntb.pdev->dev, "NTB link status events deinitialized");
+}
+
+/*
+ * idt_se_isr() - switch events ISR
+ * @ndev:      IDT NTB hardware driver descriptor
+ * @ntint_sts: NT-function interrupt status
+ *
+ * This driver doesn't support IDT PCIe-switch dynamic reconfigurations,
+ * Failover capability, etc, so switch events are utilized to notify of
+ * PCIe and NTB link events.
+ * The method is called from PCIe ISR bottom-half routine.
+ */
+static void idt_se_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
+{
+       u32 sests;
+
+       /* Read Switch Events status */
+       sests = idt_sw_read(ndev, IDT_SW_SESTS);
+
+       /* Clean the Link Up/Down and Global Signal status registers */
+       idt_sw_write(ndev, IDT_SW_SELINKUPSTS, (u32)-1);
+       idt_sw_write(ndev, IDT_SW_SELINKDNSTS, (u32)-1);
+       idt_sw_write(ndev, IDT_SW_SEGSIGSTS, (u32)-1);
+
+       /* Clean the corresponding interrupt bit */
+       idt_nt_write(ndev, IDT_NT_NTINTSTS, IDT_NTINTSTS_SEVENT);
+
+       dev_dbg(&ndev->ntb.pdev->dev, "SE IRQ detected %#08x (SESTS %#08x)",
+                         ntint_sts, sests);
+
+       /* Notify the client driver of possible link state change */
+       ntb_link_event(&ndev->ntb);
+}
+
+/*
+ * idt_ntb_local_link_enable() - enable the local NTB link.
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * In order to enable the NTB link we need:
+ * - enable Completion TLPs translation
+ * - initialize mapping table to enable the Request ID translation
+ * - notify peers of NTB link state change
+ */
+static void idt_ntb_local_link_enable(struct idt_ntb_dev *ndev)
+{
+       u32 reqid, mtbldata = 0;
+       unsigned long irqflags;
+
+       /* Enable the ID protection and Completion TLPs translation */
+       idt_nt_write(ndev, IDT_NT_NTCTL, IDT_NTCTL_CPEN);
+
+       /* Retrieve the current Requester ID (Bus:Device:Function) */
+       reqid = idt_nt_read(ndev, IDT_NT_REQIDCAP);
+
+       /*
+        * Set the corresponding NT Mapping table entry of port partition index
+        * with the data to perform the Request ID translation
+        */
+       mtbldata = SET_FIELD(NTMTBLDATA_REQID, 0, reqid) |
+                  SET_FIELD(NTMTBLDATA_PART, 0, ndev->part) |
+                  IDT_NTMTBLDATA_VALID;
+       spin_lock_irqsave(&ndev->mtbl_lock, irqflags);
+       idt_nt_write(ndev, IDT_NT_NTMTBLADDR, ndev->part);
+       idt_nt_write(ndev, IDT_NT_NTMTBLDATA, mtbldata);
+       mmiowb();
+       spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags);
+
+       /* Notify the peers by setting and clearing the global signal bit */
+       idt_nt_write(ndev, IDT_NT_NTGSIGNAL, IDT_NTGSIGNAL_SET);
+       idt_sw_write(ndev, IDT_SW_SEGSIGSTS, (u32)1 << ndev->part);
+}
+
+/*
+ * idt_ntb_local_link_disable() - disable the local NTB link.
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * In order to enable the NTB link we need:
+ * - disable Completion TLPs translation
+ * - clear corresponding mapping table entry
+ * - notify peers of NTB link state change
+ */
+static void idt_ntb_local_link_disable(struct idt_ntb_dev *ndev)
+{
+       unsigned long irqflags;
+
+       /* Disable Completion TLPs translation */
+       idt_nt_write(ndev, IDT_NT_NTCTL, 0);
+
+       /* Clear the corresponding NT Mapping table entry */
+       spin_lock_irqsave(&ndev->mtbl_lock, irqflags);
+       idt_nt_write(ndev, IDT_NT_NTMTBLADDR, ndev->part);
+       idt_nt_write(ndev, IDT_NT_NTMTBLDATA, 0);
+       mmiowb();
+       spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags);
+
+       /* Notify the peers by setting and clearing the global signal bit */
+       idt_nt_write(ndev, IDT_NT_NTGSIGNAL, IDT_NTGSIGNAL_SET);
+       idt_sw_write(ndev, IDT_SW_SEGSIGSTS, (u32)1 << ndev->part);
+}
+
+/*
+ * idt_ntb_local_link_is_up() - test wethter local NTB link is up
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * Local link is up under the following conditions:
+ * - Bus mastering is enabled
+ * - NTCTL has Completion TLPs translation enabled
+ * - Mapping table permits Request TLPs translation
+ * NOTE: We don't need to check PCIe link state since it's obviously
+ * up while we are able to communicate with IDT PCIe-switch
+ *
+ * Return: true if link is up, otherwise false
+ */
+static bool idt_ntb_local_link_is_up(struct idt_ntb_dev *ndev)
+{
+       unsigned long irqflags;
+       u32 data;
+
+       /* Read the local Bus Master Enable status */
+       data = idt_nt_read(ndev, IDT_NT_PCICMDSTS);
+       if (!(data & IDT_PCICMDSTS_BME))
+               return false;
+
+       /* Read the local Completion TLPs translation enable status */
+       data = idt_nt_read(ndev, IDT_NT_NTCTL);
+       if (!(data & IDT_NTCTL_CPEN))
+               return false;
+
+       /* Read Mapping table entry corresponding to the local partition */
+       spin_lock_irqsave(&ndev->mtbl_lock, irqflags);
+       idt_nt_write(ndev, IDT_NT_NTMTBLADDR, ndev->part);
+       data = idt_nt_read(ndev, IDT_NT_NTMTBLDATA);
+       spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags);
+
+       return !!(data & IDT_NTMTBLDATA_VALID);
+}
+
+/*
+ * idt_ntb_peer_link_is_up() - test whether peer NTB link is up
+ * @ndev:      IDT NTB hardware driver descriptor
+ * @pidx:      Peer port index
+ *
+ * Peer link is up under the following conditions:
+ * - PCIe link is up
+ * - Bus mastering is enabled
+ * - NTCTL has Completion TLPs translation enabled
+ * - Mapping table permits Request TLPs translation
+ *
+ * Return: true if link is up, otherwise false
+ */
+static bool idt_ntb_peer_link_is_up(struct idt_ntb_dev *ndev, int pidx)
+{
+       unsigned long irqflags;
+       unsigned char port;
+       u32 data;
+
+       /* Retrieve the device port number */
+       port = ndev->peers[pidx].port;
+
+       /* Check whether PCIe link is up */
+       data = idt_sw_read(ndev, portdata_tbl[port].sts);
+       if (!(data & IDT_SWPORTxSTS_LINKUP))
+               return false;
+
+       /* Check whether bus mastering is enabled on the peer port */
+       data = idt_sw_read(ndev, portdata_tbl[port].pcicmdsts);
+       if (!(data & IDT_PCICMDSTS_BME))
+               return false;
+
+       /* Check if Completion TLPs translation is enabled on the peer port */
+       data = idt_sw_read(ndev, portdata_tbl[port].ntctl);
+       if (!(data & IDT_NTCTL_CPEN))
+               return false;
+
+       /* Read Mapping table entry corresponding to the peer partition */
+       spin_lock_irqsave(&ndev->mtbl_lock, irqflags);
+       idt_nt_write(ndev, IDT_NT_NTMTBLADDR, ndev->peers[pidx].part);
+       data = idt_nt_read(ndev, IDT_NT_NTMTBLDATA);
+       spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags);
+
+       return !!(data & IDT_NTMTBLDATA_VALID);
+}
+
+/*
+ * idt_ntb_link_is_up() - get the current ntb link state (NTB API callback)
+ * @ntb:       NTB device context.
+ * @speed:     OUT - The link speed expressed as PCIe generation number.
+ * @width:     OUT - The link width expressed as the number of PCIe lanes.
+ *
+ * Get the bitfield of NTB link states for all peer ports
+ *
+ * Return: bitfield of indexed ports link state: bit is set/cleared if the
+ *         link is up/down respectively.
+ */
+static u64 idt_ntb_link_is_up(struct ntb_dev *ntb,
+                             enum ntb_speed *speed, enum ntb_width *width)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+       unsigned char pidx;
+       u64 status;
+       u32 data;
+
+       /* Retrieve the local link speed and width */
+       if (speed != NULL || width != NULL) {
+               data = idt_nt_read(ndev, IDT_NT_PCIELCTLSTS);
+               if (speed != NULL)
+                       *speed = GET_FIELD(PCIELCTLSTS_CLS, data);
+               if (width != NULL)
+                       *width = GET_FIELD(PCIELCTLSTS_NLW, data);
+       }
+
+       /* If local NTB link isn't up then all the links are considered down */
+       if (!idt_ntb_local_link_is_up(ndev))
+               return 0;
+
+       /* Collect all the peer ports link states into the bitfield */
+       status = 0;
+       for (pidx = 0; pidx < ndev->peer_cnt; pidx++) {
+               if (idt_ntb_peer_link_is_up(ndev, pidx))
+                       status |= ((u64)1 << pidx);
+       }
+
+       return status;
+}
+
+/*
+ * idt_ntb_link_enable() - enable local port ntb link (NTB API callback)
+ * @ntb:       NTB device context.
+ * @max_speed: The maximum link speed expressed as PCIe generation number.
+ * @max_width: The maximum link width expressed as the number of PCIe lanes.
+ *
+ * Enable just local NTB link. PCIe link parameters are ignored.
+ *
+ * Return: always zero.
+ */
+static int idt_ntb_link_enable(struct ntb_dev *ntb, enum ntb_speed speed,
+                              enum ntb_width width)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       /* Just enable the local NTB link */
+       idt_ntb_local_link_enable(ndev);
+
+       dev_dbg(&ndev->ntb.pdev->dev, "Local NTB link enabled");
+
+       return 0;
+}
+
+/*
+ * idt_ntb_link_disable() - disable local port ntb link (NTB API callback)
+ * @ntb:       NTB device context.
+ *
+ * Disable just local NTB link.
+ *
+ * Return: always zero.
+ */
+static int idt_ntb_link_disable(struct ntb_dev *ntb)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       /* Just disable the local NTB link */
+       idt_ntb_local_link_disable(ndev);
+
+       dev_dbg(&ndev->ntb.pdev->dev, "Local NTB link disabled");
+
+       return 0;
+}
+
+/*=============================================================================
+ *                         4. Memory Window operations
+ *
+ *    IDT PCIe-switches have two types of memory windows: MWs with direct
+ * address translation and MWs with LUT based translation. The first type of
+ * MWs is simple map of corresponding BAR address space to a memory space
+ * of specified target port. So it implemets just ont-to-one mapping. Lookup
+ * table in its turn can map one BAR address space to up to 24 different
+ * memory spaces of different ports.
+ *    NT-functions BARs can be turned on to implement either direct or lookup
+ * table based address translations, so:
+ * BAR0 - NT configuration registers space/direct address translation
+ * BAR1 - direct address translation/upper address of BAR0x64
+ * BAR2 - direct address translation/Lookup table with either 12 or 24 entries
+ * BAR3 - direct address translation/upper address of BAR2x64
+ * BAR4 - direct address translation/Lookup table with either 12 or 24 entries
+ * BAR5 - direct address translation/upper address of BAR4x64
+ *    Additionally BAR2 and BAR4 can't have 24-entries LUT enabled at the same
+ * time. Since the BARs setup can be rather complicated this driver implements
+ * a scanning algorithm to have all the possible memory windows configuration
+ * covered.
+ *
+ * NOTE 1 BAR setup must be done before Linux kernel enumerated NT-function
+ * of any port, so this driver would have memory windows configurations fixed.
+ * In this way all initializations must be performed either by platform BIOS
+ * or using EEPROM connected to IDT PCIe-switch master SMBus.
+ *
+ * NOTE 2 This driver expects BAR0 mapping NT-function configuration space.
+ * Easy calculation can give us an upper boundary of 29 possible memory windows
+ * per each NT-function if all the BARs are of 32bit type.
+ *=============================================================================
+ */
+
+/*
+ * idt_get_mw_count() - get memory window count
+ * @mw_type:   Memory window type
+ *
+ * Return: number of memory windows with respect to the BAR type
+ */
+static inline unsigned char idt_get_mw_count(enum idt_mw_type mw_type)
+{
+       switch (mw_type) {
+       case IDT_MW_DIR:
+               return 1;
+       case IDT_MW_LUT12:
+               return 12;
+       case IDT_MW_LUT24:
+               return 24;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * idt_get_mw_name() - get memory window name
+ * @mw_type:   Memory window type
+ *
+ * Return: pointer to a string with name
+ */
+static inline char *idt_get_mw_name(enum idt_mw_type mw_type)
+{
+       switch (mw_type) {
+       case IDT_MW_DIR:
+               return "DIR  ";
+       case IDT_MW_LUT12:
+               return "LUT12";
+       case IDT_MW_LUT24:
+               return "LUT24";
+       default:
+               break;
+       }
+
+       return "unknown";
+}
+
+/*
+ * idt_scan_mws() - scan memory windows of the port
+ * @ndev:      IDT NTB hardware driver descriptor
+ * @port:      Port to get number of memory windows for
+ * @mw_cnt:    Out - number of memory windows
+ *
+ * It walks over BAR setup registers of the specified port and determines
+ * the memory windows parameters if any activated.
+ *
+ * Return: array of memory windows
+ */
+static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port,
+                                      unsigned char *mw_cnt)
+{
+       struct idt_mw_cfg mws[IDT_MAX_NR_MWS], *ret_mws;
+       const struct idt_ntb_bar *bars;
+       enum idt_mw_type mw_type;
+       unsigned char widx, bidx, en_cnt;
+       bool bar_64bit = false;
+       int aprt_size;
+       u32 data;
+
+       /* Retrieve the array of the BARs registers */
+       bars = portdata_tbl[port].bars;
+
+       /* Scan all the BARs belonging to the port */
+       *mw_cnt = 0;
+       for (bidx = 0; bidx < IDT_BAR_CNT; bidx += 1 + bar_64bit) {
+               /* Read BARSETUP register value */
+               data = idt_sw_read(ndev, bars[bidx].setup);
+
+               /* Skip disabled BARs */
+               if (!(data & IDT_BARSETUP_EN)) {
+                       bar_64bit = false;
+                       continue;
+               }
+
+               /* Skip next BARSETUP if current one has 64bit addressing */
+               bar_64bit = IS_FLD_SET(BARSETUP_TYPE, data, 64);
+
+               /* Skip configuration space mapping BARs */
+               if (data & IDT_BARSETUP_MODE_CFG)
+                       continue;
+
+               /* Retrieve MW type/entries count and aperture size */
+               mw_type = GET_FIELD(BARSETUP_ATRAN, data);
+               en_cnt = idt_get_mw_count(mw_type);
+               aprt_size = (u64)1 << GET_FIELD(BARSETUP_SIZE, data);
+
+               /* Save configurations of all available memory windows */
+               for (widx = 0; widx < en_cnt; widx++, (*mw_cnt)++) {
+                       /*
+                        * IDT can expose a limited number of MWs, so it's bug
+                        * to have more than the driver expects
+                        */
+                       if (*mw_cnt >= IDT_MAX_NR_MWS)
+                               return ERR_PTR(-EINVAL);
+
+                       /* Save basic MW info */
+                       mws[*mw_cnt].type = mw_type;
+                       mws[*mw_cnt].bar = bidx;
+                       mws[*mw_cnt].idx = widx;
+                       /* It's always DWORD aligned */
+                       mws[*mw_cnt].addr_align = IDT_TRANS_ALIGN;
+                       /* DIR and LUT approachs differently configure MWs */
+                       if (mw_type == IDT_MW_DIR)
+                               mws[*mw_cnt].size_max = aprt_size;
+                       else if (mw_type == IDT_MW_LUT12)
+                               mws[*mw_cnt].size_max = aprt_size / 16;
+                       else
+                               mws[*mw_cnt].size_max = aprt_size / 32;
+                       mws[*mw_cnt].size_align = (mw_type == IDT_MW_DIR) ?
+                               IDT_DIR_SIZE_ALIGN : mws[*mw_cnt].size_max;
+               }
+       }
+
+       /* Allocate memory for memory window descriptors */
+       ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt,
+                               sizeof(*ret_mws), GFP_KERNEL);
+       if (IS_ERR_OR_NULL(ret_mws))
+               return ERR_PTR(-ENOMEM);
+
+       /* Copy the info of detected memory windows */
+       memcpy(ret_mws, mws, (*mw_cnt)*sizeof(*ret_mws));
+
+       return ret_mws;
+}
+
+/*
+ * idt_init_mws() - initialize memory windows subsystem
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * Scan BAR setup registers of local and peer ports to determine the
+ * outbound and inbound memory windows parameters
+ *
+ * Return: zero on success, otherwise a negative error number
+ */
+static int idt_init_mws(struct idt_ntb_dev *ndev)
+{
+       struct idt_ntb_peer *peer;
+       unsigned char pidx;
+
+       /* Scan memory windows of the local port */
+       ndev->mws = idt_scan_mws(ndev, ndev->port, &ndev->mw_cnt);
+       if (IS_ERR(ndev->mws)) {
+               dev_err(&ndev->ntb.pdev->dev,
+                       "Failed to scan mws of local port %hhu", ndev->port);
+               return PTR_ERR(ndev->mws);
+       }
+
+       /* Scan memory windows of the peer ports */
+       for (pidx = 0; pidx < ndev->peer_cnt; pidx++) {
+               peer = &ndev->peers[pidx];
+               peer->mws = idt_scan_mws(ndev, peer->port, &peer->mw_cnt);
+               if (IS_ERR(peer->mws)) {
+                       dev_err(&ndev->ntb.pdev->dev,
+                               "Failed to scan mws of port %hhu", peer->port);
+                       return PTR_ERR(peer->mws);
+               }
+       }
+
+       /* Initialize spin locker of the LUT registers */
+       spin_lock_init(&ndev->lut_lock);
+
+       dev_dbg(&ndev->ntb.pdev->dev, "Outbound and inbound MWs initialized");
+
+       return 0;
+}
+
+/*
+ * idt_ntb_mw_count() - number of inbound memory windows (NTB API callback)
+ * @ntb:       NTB device context.
+ * @pidx:      Port index of peer device.
+ *
+ * The value is returned for the specified peer, so generally speaking it can
+ * be different for different port depending on the IDT PCIe-switch
+ * initialization.
+ *
+ * Return: the number of memory windows.
+ */
+static int idt_ntb_mw_count(struct ntb_dev *ntb, int pidx)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       if (pidx < 0 || ndev->peer_cnt <= pidx)
+               return -EINVAL;
+
+       return ndev->peers[pidx].mw_cnt;
+}
+
+/*
+ * idt_ntb_mw_get_align() - inbound memory window parameters (NTB API callback)
+ * @ntb:       NTB device context.
+ * @pidx:      Port index of peer device.
+ * @widx:      Memory window index.
+ * @addr_align:        OUT - the base alignment for translating the memory window
+ * @size_align:        OUT - the size alignment for translating the memory window
+ * @size_max:  OUT - the maximum size of the memory window
+ *
+ * The peer memory window parameters have already been determined, so just
+ * return the corresponding values, which mustn't change within session.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static int idt_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int widx,
+                               resource_size_t *addr_align,
+                               resource_size_t *size_align,
+                               resource_size_t *size_max)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+       struct idt_ntb_peer *peer;
+
+       if (pidx < 0 || ndev->peer_cnt <= pidx)
+               return -EINVAL;
+
+       peer = &ndev->peers[pidx];
+
+       if (widx < 0 || peer->mw_cnt <= widx)
+               return -EINVAL;
+
+       if (addr_align != NULL)
+               *addr_align = peer->mws[widx].addr_align;
+
+       if (size_align != NULL)
+               *size_align = peer->mws[widx].size_align;
+
+       if (size_max != NULL)
+               *size_max = peer->mws[widx].size_max;
+
+       return 0;
+}
+
+/*
+ * idt_ntb_peer_mw_count() - number of outbound memory windows
+ *                          (NTB API callback)
+ * @ntb:       NTB device context.
+ *
+ * Outbound memory windows parameters have been determined based on the
+ * BAR setup registers value, which are mostly constants within one session.
+ *
+ * Return: the number of memory windows.
+ */
+static int idt_ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       return ndev->mw_cnt;
+}
+
+/*
+ * idt_ntb_peer_mw_get_addr() - get map address of an outbound memory window
+ *                             (NTB API callback)
+ * @ntb:       NTB device context.
+ * @widx:      Memory window index (within ntb_peer_mw_count() return value).
+ * @base:      OUT - the base address of mapping region.
+ * @size:      OUT - the size of mapping region.
+ *
+ * Return just parameters of BAR resources mapping. Size reflects just the size
+ * of the resource
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static int idt_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int widx,
+                                   phys_addr_t *base, resource_size_t *size)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       if (widx < 0 || ndev->mw_cnt <= widx)
+               return -EINVAL;
+
+       /* Mapping address is just properly shifted BAR resource start */
+       if (base != NULL)
+               *base = pci_resource_start(ntb->pdev, ndev->mws[widx].bar) +
+                       ndev->mws[widx].idx * ndev->mws[widx].size_max;
+
+       /* Mapping size has already been calculated at MWs scanning */
+       if (size != NULL)
+               *size = ndev->mws[widx].size_max;
+
+       return 0;
+}
+
+/*
+ * idt_ntb_peer_mw_set_trans() - set a translation address of a memory window
+ *                              (NTB API callback)
+ * @ntb:       NTB device context.
+ * @pidx:      Port index of peer device the translation address received from.
+ * @widx:      Memory window index.
+ * @addr:      The dma address of the shared memory to access.
+ * @size:      The size of the shared memory to access.
+ *
+ * The Direct address translation and LUT base translation is initialized a
+ * bit differenet. Although the parameters restriction are now determined by
+ * the same code.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static int idt_ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
+                                    u64 addr, resource_size_t size)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+       struct idt_mw_cfg *mw_cfg;
+       u32 data = 0, lutoff = 0;
+
+       if (pidx < 0 || ndev->peer_cnt <= pidx)
+               return -EINVAL;
+
+       if (widx < 0 || ndev->mw_cnt <= widx)
+               return -EINVAL;
+
+       /*
+        * Retrieve the memory window config to make sure the passed arguments
+        * fit it restrictions
+        */
+       mw_cfg = &ndev->mws[widx];
+       if (!IS_ALIGNED(addr, mw_cfg->addr_align))
+               return -EINVAL;
+       if (!IS_ALIGNED(size, mw_cfg->size_align) || size > mw_cfg->size_max)
+               return -EINVAL;
+
+       /* DIR and LUT based translations are initialized differently */
+       if (mw_cfg->type == IDT_MW_DIR) {
+               const struct idt_ntb_bar *bar = &ntdata_tbl.bars[mw_cfg->bar];
+               u64 limit;
+               /* Set destination partition of translation */
+               data = idt_nt_read(ndev, bar->setup);
+               data = SET_FIELD(BARSETUP_TPART, data, ndev->peers[pidx].part);
+               idt_nt_write(ndev, bar->setup, data);
+               /* Set translation base address */
+               idt_nt_write(ndev, bar->ltbase, (u32)addr);
+               idt_nt_write(ndev, bar->utbase, (u32)(addr >> 32));
+               /* Set the custom BAR aperture limit */
+               limit = pci_resource_start(ntb->pdev, mw_cfg->bar) + size;
+               idt_nt_write(ndev, bar->limit, (u32)limit);
+               if (IS_FLD_SET(BARSETUP_TYPE, data, 64))
+                       idt_nt_write(ndev, (bar + 1)->limit, (limit >> 32));
+       } else {
+               unsigned long irqflags;
+               /* Initialize corresponding LUT entry */
+               lutoff = SET_FIELD(LUTOFFSET_INDEX, 0, mw_cfg->idx) |
+                        SET_FIELD(LUTOFFSET_BAR, 0, mw_cfg->bar);
+               data = SET_FIELD(LUTUDATA_PART, 0, ndev->peers[pidx].part) |
+                       IDT_LUTUDATA_VALID;
+               spin_lock_irqsave(&ndev->lut_lock, irqflags);
+               idt_nt_write(ndev, IDT_NT_LUTOFFSET, lutoff);
+               idt_nt_write(ndev, IDT_NT_LUTLDATA, (u32)addr);
+               idt_nt_write(ndev, IDT_NT_LUTMDATA, (u32)(addr >> 32));
+               idt_nt_write(ndev, IDT_NT_LUTUDATA, data);
+               mmiowb();
+               spin_unlock_irqrestore(&ndev->lut_lock, irqflags);
+               /* Limit address isn't specified since size is fixed for LUT */
+       }
+
+       return 0;
+}
+
+/*
+ * idt_ntb_peer_mw_clear_trans() - clear the outbound MW translation address
+ *                                (NTB API callback)
+ * @ntb:       NTB device context.
+ * @pidx:      Port index of peer device.
+ * @widx:      Memory window index.
+ *
+ * It effectively disables the translation over the specified outbound MW.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static int idt_ntb_peer_mw_clear_trans(struct ntb_dev *ntb, int pidx,
+                                       int widx)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+       struct idt_mw_cfg *mw_cfg;
+
+       if (pidx < 0 || ndev->peer_cnt <= pidx)
+               return -EINVAL;
+
+       if (widx < 0 || ndev->mw_cnt <= widx)
+               return -EINVAL;
+
+       mw_cfg = &ndev->mws[widx];
+
+       /* DIR and LUT based translations are initialized differently */
+       if (mw_cfg->type == IDT_MW_DIR) {
+               const struct idt_ntb_bar *bar = &ntdata_tbl.bars[mw_cfg->bar];
+               u32 data;
+               /* Read BARSETUP to check BAR type */
+               data = idt_nt_read(ndev, bar->setup);
+               /* Disable translation by specifying zero BAR limit */
+               idt_nt_write(ndev, bar->limit, 0);
+               if (IS_FLD_SET(BARSETUP_TYPE, data, 64))
+                       idt_nt_write(ndev, (bar + 1)->limit, 0);
+       } else {
+               unsigned long irqflags;
+               u32 lutoff;
+               /* Clear the corresponding LUT entry up */
+               lutoff = SET_FIELD(LUTOFFSET_INDEX, 0, mw_cfg->idx) |
+                        SET_FIELD(LUTOFFSET_BAR, 0, mw_cfg->bar);
+               spin_lock_irqsave(&ndev->lut_lock, irqflags);
+               idt_nt_write(ndev, IDT_NT_LUTOFFSET, lutoff);
+               idt_nt_write(ndev, IDT_NT_LUTLDATA, 0);
+               idt_nt_write(ndev, IDT_NT_LUTMDATA, 0);
+               idt_nt_write(ndev, IDT_NT_LUTUDATA, 0);
+               mmiowb();
+               spin_unlock_irqrestore(&ndev->lut_lock, irqflags);
+       }
+
+       return 0;
+}
+
+/*=============================================================================
+ *                          5. Doorbell operations
+ *
+ *    Doorbell functionality of IDT PCIe-switches is pretty unusual. First of
+ * all there is global doorbell register which state can by changed by any
+ * NT-function of the IDT device in accordance with global permissions. These
+ * permissions configs are not supported by NTB API, so it must be done by
+ * either BIOS or EEPROM settings. In the same way the state of the global
+ * doorbell is reflected to the NT-functions local inbound doorbell registers.
+ * It can lead to situations when client driver sets some peer doorbell bits
+ * and get them bounced back to local inbound doorbell if permissions are
+ * granted.
+ *    Secondly there is just one IRQ vector for Doorbell, Message, Temperature
+ * and Switch events, so if client driver left any of Doorbell bits set and
+ * some other event occurred, the driver will be notified of Doorbell event
+ * again.
+ *=============================================================================
+ */
+
+/*
+ * idt_db_isr() - doorbell event ISR
+ * @ndev:      IDT NTB hardware driver descriptor
+ * @ntint_sts: NT-function interrupt status
+ *
+ * Doorbell event happans when DBELL bit of NTINTSTS switches from 0 to 1.
+ * It happens only when unmasked doorbell bits are set to ones on completely
+ * zeroed doorbell register.
+ * The method is called from PCIe ISR bottom-half routine.
+ */
+static void idt_db_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
+{
+       /*
+        * Doorbell IRQ status will be cleaned only when client
+        * driver unsets all the doorbell bits.
+        */
+       dev_dbg(&ndev->ntb.pdev->dev, "DB IRQ detected %#08x", ntint_sts);
+
+       /* Notify the client driver of possible doorbell state change */
+       ntb_db_event(&ndev->ntb, 0);
+}
+
+/*
+ * idt_ntb_db_valid_mask() - get a mask of doorbell bits supported by the ntb
+ *                          (NTB API callback)
+ * @ntb:       NTB device context.
+ *
+ * IDT PCIe-switches expose just one Doorbell register of DWORD size.
+ *
+ * Return: A mask of doorbell bits supported by the ntb.
+ */
+static u64 idt_ntb_db_valid_mask(struct ntb_dev *ntb)
+{
+       return IDT_DBELL_MASK;
+}
+
+/*
+ * idt_ntb_db_read() - read the local doorbell register (NTB API callback)
+ * @ntb:       NTB device context.
+ *
+ * There is just on inbound doorbell register of each NT-function, so
+ * this method return it value.
+ *
+ * Return: The bits currently set in the local doorbell register.
+ */
+static u64 idt_ntb_db_read(struct ntb_dev *ntb)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       return idt_nt_read(ndev, IDT_NT_INDBELLSTS);
+}
+
+/*
+ * idt_ntb_db_clear() - clear bits in the local doorbell register
+ *                     (NTB API callback)
+ * @ntb:       NTB device context.
+ * @db_bits:   Doorbell bits to clear.
+ *
+ * Clear bits of inbound doorbell register by writing ones to it.
+ *
+ * NOTE! Invalid bits are always considered cleared so it's not an error
+ * to clear them over.
+ *
+ * Return: always zero as success.
+ */
+static int idt_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       idt_nt_write(ndev, IDT_NT_INDBELLSTS, (u32)db_bits);
+
+       return 0;
+}
+
+/*
+ * idt_ntb_db_read_mask() - read the local doorbell mask (NTB API callback)
+ * @ntb:       NTB device context.
+ *
+ * Each inbound doorbell bit can be masked from generating IRQ by setting
+ * the corresponding bit in inbound doorbell mask. So this method returns
+ * the value of the register.
+ *
+ * Return: The bits currently set in the local doorbell mask register.
+ */
+static u64 idt_ntb_db_read_mask(struct ntb_dev *ntb)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       return idt_nt_read(ndev, IDT_NT_INDBELLMSK);
+}
+
+/*
+ * idt_ntb_db_set_mask() - set bits in the local doorbell mask
+ *                        (NTB API callback)
+ * @ntb:       NTB device context.
+ * @db_bits:   Doorbell mask bits to set.
+ *
+ * The inbound doorbell register mask value must be read, then OR'ed with
+ * passed field and only then set back.
+ *
+ * Return: zero on success, negative error if invalid argument passed.
+ */
+static int idt_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       return idt_reg_set_bits(ndev, IDT_NT_INDBELLMSK, &ndev->db_mask_lock,
+                               IDT_DBELL_MASK, db_bits);
+}
+
+/*
+ * idt_ntb_db_clear_mask() - clear bits in the local doorbell mask
+ *                          (NTB API callback)
+ * @ntb:       NTB device context.
+ * @db_bits:   Doorbell bits to clear.
+ *
+ * The method just clears the set bits up in accordance with the passed
+ * bitfield. IDT PCIe-switch shall generate an interrupt if there hasn't
+ * been any unmasked bit set before current unmasking. Otherwise IRQ won't
+ * be generated since there is only one IRQ vector for all doorbells.
+ *
+ * Return: always zero as success
+ */
+static int idt_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       idt_reg_clear_bits(ndev, IDT_NT_INDBELLMSK, &ndev->db_mask_lock,
+                          db_bits);
+
+       return 0;
+}
+
+/*
+ * idt_ntb_peer_db_set() - set bits in the peer doorbell register
+ *                        (NTB API callback)
+ * @ntb:       NTB device context.
+ * @db_bits:   Doorbell bits to set.
+ *
+ * IDT PCIe-switches exposes local outbound doorbell register to change peer
+ * inbound doorbell register state.
+ *
+ * Return: zero on success, negative error if invalid argument passed.
+ */
+static int idt_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       if (db_bits & ~(u64)IDT_DBELL_MASK)
+               return -EINVAL;
+
+       idt_nt_write(ndev, IDT_NT_OUTDBELLSET, (u32)db_bits);
+       return 0;
+}
+
+/*=============================================================================
+ *                          6. Messaging operations
+ *
+ *    Each NT-function of IDT PCIe-switch has four inbound and four outbound
+ * message registers. Each outbound message register can be connected to one or
+ * even more than one peer inbound message registers by setting global
+ * configurations. Since NTB API permits one-on-one message registers mapping
+ * only, the driver acts in according with that restriction.
+ *=============================================================================
+ */
+
+/*
+ * idt_init_msg() - initialize messaging interface
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * Just initialize the message registers routing tables locker.
+ */
+static void idt_init_msg(struct idt_ntb_dev *ndev)
+{
+       unsigned char midx;
+
+       /* Init the messages routing table lockers */
+       for (midx = 0; midx < IDT_MSG_CNT; midx++)
+               spin_lock_init(&ndev->msg_locks[midx]);
+
+       dev_dbg(&ndev->ntb.pdev->dev, "NTB Messaging initialized");
+}
+
+/*
+ * idt_msg_isr() - message event ISR
+ * @ndev:      IDT NTB hardware driver descriptor
+ * @ntint_sts: NT-function interrupt status
+ *
+ * Message event happens when MSG bit of NTINTSTS switches from 0 to 1.
+ * It happens only when unmasked message status bits are set to ones on
+ * completely zeroed message status register.
+ * The method is called from PCIe ISR bottom-half routine.
+ */
+static void idt_msg_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
+{
+       /*
+        * Message IRQ status will be cleaned only when client
+        * driver unsets all the message status bits.
+        */
+       dev_dbg(&ndev->ntb.pdev->dev, "Message IRQ detected %#08x", ntint_sts);
+
+       /* Notify the client driver of possible message status change */
+       ntb_msg_event(&ndev->ntb);
+}
+
+/*
+ * idt_ntb_msg_count() - get the number of message registers (NTB API callback)
+ * @ntb:       NTB device context.
+ *
+ * IDT PCIe-switches support four message registers.
+ *
+ * Return: the number of message registers.
+ */
+static int idt_ntb_msg_count(struct ntb_dev *ntb)
+{
+       return IDT_MSG_CNT;
+}
+
+/*
+ * idt_ntb_msg_inbits() - get a bitfield of inbound message registers status
+ *                       (NTB API callback)
+ * @ntb:       NTB device context.
+ *
+ * NT message status register is shared between inbound and outbound message
+ * registers status
+ *
+ * Return: bitfield of inbound message registers.
+ */
+static u64 idt_ntb_msg_inbits(struct ntb_dev *ntb)
+{
+       return (u64)IDT_INMSG_MASK;
+}
+
+/*
+ * idt_ntb_msg_outbits() - get a bitfield of outbound message registers status
+ *                       (NTB API callback)
+ * @ntb:       NTB device context.
+ *
+ * NT message status register is shared between inbound and outbound message
+ * registers status
+ *
+ * Return: bitfield of outbound message registers.
+ */
+static u64 idt_ntb_msg_outbits(struct ntb_dev *ntb)
+{
+       return (u64)IDT_OUTMSG_MASK;
+}
+
+/*
+ * idt_ntb_msg_read_sts() - read the message registers status (NTB API callback)
+ * @ntb:       NTB device context.
+ *
+ * IDT PCIe-switches expose message status registers to notify drivers of
+ * incoming data and failures in case if peer message register isn't freed.
+ *
+ * Return: status bits of message registers
+ */
+static u64 idt_ntb_msg_read_sts(struct ntb_dev *ntb)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       return idt_nt_read(ndev, IDT_NT_MSGSTS);
+}
+
+/*
+ * idt_ntb_msg_clear_sts() - clear status bits of message registers
+ *                          (NTB API callback)
+ * @ntb:       NTB device context.
+ * @sts_bits:  Status bits to clear.
+ *
+ * Clear bits in the status register by writing ones.
+ *
+ * NOTE! Invalid bits are always considered cleared so it's not an error
+ * to clear them over.
+ *
+ * Return: always zero as success.
+ */
+static int idt_ntb_msg_clear_sts(struct ntb_dev *ntb, u64 sts_bits)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       idt_nt_write(ndev, IDT_NT_MSGSTS, sts_bits);
+
+       return 0;
+}
+
+/*
+ * idt_ntb_msg_set_mask() - set mask of message register status bits
+ *                         (NTB API callback)
+ * @ntb:       NTB device context.
+ * @mask_bits: Mask bits.
+ *
+ * Mask the message status bits from raising an IRQ.
+ *
+ * Return: zero on success, negative error if invalid argument passed.
+ */
+static int idt_ntb_msg_set_mask(struct ntb_dev *ntb, u64 mask_bits)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       return idt_reg_set_bits(ndev, IDT_NT_MSGSTSMSK, &ndev->msg_mask_lock,
+                               IDT_MSG_MASK, mask_bits);
+}
+
+/*
+ * idt_ntb_msg_clear_mask() - clear message registers mask
+ *                           (NTB API callback)
+ * @ntb:       NTB device context.
+ * @mask_bits: Mask bits.
+ *
+ * Clear mask of message status bits IRQs.
+ *
+ * Return: always zero as success.
+ */
+static int idt_ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       idt_reg_clear_bits(ndev, IDT_NT_MSGSTSMSK, &ndev->msg_mask_lock,
+                          mask_bits);
+
+       return 0;
+}
+
+/*
+ * idt_ntb_msg_read() - read message register with specified index
+ *                     (NTB API callback)
+ * @ntb:       NTB device context.
+ * @midx:      Message register index
+ * @pidx:      OUT - Port index of peer device a message retrieved from
+ * @msg:       OUT - Data
+ *
+ * Read data from the specified message register and source register.
+ *
+ * Return: zero on success, negative error if invalid argument passed.
+ */
+static int idt_ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+
+       if (midx < 0 || IDT_MSG_CNT <= midx)
+               return -EINVAL;
+
+       /* Retrieve source port index of the message */
+       if (pidx != NULL) {
+               u32 srcpart;
+
+               srcpart = idt_nt_read(ndev, ntdata_tbl.msgs[midx].src);
+               *pidx = ndev->part_idx_map[srcpart];
+
+               /* Sanity check partition index (for initial case) */
+               if (*pidx == -EINVAL)
+                       *pidx = 0;
+       }
+
+       /* Retrieve data of the corresponding message register */
+       if (msg != NULL)
+               *msg = idt_nt_read(ndev, ntdata_tbl.msgs[midx].in);
+
+       return 0;
+}
+
+/*
+ * idt_ntb_msg_write() - write data to the specified message register
+ *                      (NTB API callback)
+ * @ntb:       NTB device context.
+ * @midx:      Message register index
+ * @pidx:      Port index of peer device a message being sent to
+ * @msg:       Data to send
+ *
+ * Just try to send data to a peer. Message status register should be
+ * checked by client driver.
+ *
+ * Return: zero on success, negative error if invalid argument passed.
+ */
+static int idt_ntb_msg_write(struct ntb_dev *ntb, int midx, int pidx, u32 msg)
+{
+       struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
+       unsigned long irqflags;
+       u32 swpmsgctl = 0;
+
+       if (midx < 0 || IDT_MSG_CNT <= midx)
+               return -EINVAL;
+
+       if (pidx < 0 || ndev->peer_cnt <= pidx)
+               return -EINVAL;
+
+       /* Collect the routing information */
+       swpmsgctl = SET_FIELD(SWPxMSGCTL_REG, 0, midx) |
+                   SET_FIELD(SWPxMSGCTL_PART, 0, ndev->peers[pidx].part);
+
+       /* Lock the messages routing table of the specified register */
+       spin_lock_irqsave(&ndev->msg_locks[midx], irqflags);
+       /* Set the route and send the data */
+       idt_sw_write(ndev, partdata_tbl[ndev->part].msgctl[midx], swpmsgctl);
+       idt_nt_write(ndev, ntdata_tbl.msgs[midx].out, msg);
+       mmiowb();
+       /* Unlock the messages routing table */
+       spin_unlock_irqrestore(&ndev->msg_locks[midx], irqflags);
+
+       /* Client driver shall check the status register */
+       return 0;
+}
+
+/*=============================================================================
+ *                      7. Temperature sensor operations
+ *
+ *    IDT PCIe-switch has an embedded temperature sensor, which can be used to
+ * warn a user-space of possible chip overheating. Since workload temperature
+ * can be different on different platforms, temperature thresholds as well as
+ * general sensor settings must be setup in the framework of BIOS/EEPROM
+ * initializations. It includes the actual sensor enabling as well.
+ *=============================================================================
+ */
+
+/*
+ * idt_read_temp() - read temperature from chip sensor
+ * @ntb:       NTB device context.
+ * @val:       OUT - integer value of temperature
+ * @frac:      OUT - fraction
+ */
+static void idt_read_temp(struct idt_ntb_dev *ndev, unsigned char *val,
+                         unsigned char *frac)
+{
+       u32 data;
+
+       /* Read the data from TEMP field of the TMPSTS register */
+       data = idt_sw_read(ndev, IDT_SW_TMPSTS);
+       data = GET_FIELD(TMPSTS_TEMP, data);
+       /* TEMP field has one fractional bit and seven integer bits */
+       *val = data >> 1;
+       *frac = ((data & 0x1) ? 5 : 0);
+}
+
+/*
+ * idt_temp_isr() - temperature sensor alarm events ISR
+ * @ndev:      IDT NTB hardware driver descriptor
+ * @ntint_sts: NT-function interrupt status
+ *
+ * It handles events of temperature crossing alarm thresholds. Since reading
+ * of TMPALARM register clears it up, the function doesn't analyze the
+ * read value, instead the current temperature value just warningly printed to
+ * log.
+ * The method is called from PCIe ISR bottom-half routine.
+ */
+static void idt_temp_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
+{
+       unsigned char val, frac;
+
+       /* Read the current temperature value */
+       idt_read_temp(ndev, &val, &frac);
+
+       /* Read the temperature alarm to clean the alarm status out */
+       /*(void)idt_sw_read(ndev, IDT_SW_TMPALARM);*/
+
+       /* Clean the corresponding interrupt bit */
+       idt_nt_write(ndev, IDT_NT_NTINTSTS, IDT_NTINTSTS_TMPSENSOR);
+
+       dev_dbg(&ndev->ntb.pdev->dev,
+               "Temp sensor IRQ detected %#08x", ntint_sts);
+
+       /* Print temperature value to log */
+       dev_warn(&ndev->ntb.pdev->dev, "Temperature %hhu.%hhu", val, frac);
+}
+
+/*=============================================================================
+ *                           8. ISRs related operations
+ *
+ *    IDT PCIe-switch has strangely developed IRQ system. There is just one
+ * interrupt vector for doorbell and message registers. So the hardware driver
+ * can't determine actual source of IRQ if, for example, message event happened
+ * while any of unmasked doorbell is still set. The similar situation may be if
+ * switch or temperature sensor events pop up. The difference is that SEVENT
+ * and TMPSENSOR bits of NT interrupt status register can be cleaned by
+ * IRQ handler so a next interrupt request won't have false handling of
+ * corresponding events.
+ *    The hardware driver has only bottom-half handler of the IRQ, since if any
+ * of events happened the device won't raise it again before the last one is
+ * handled by clearing of corresponding NTINTSTS bit.
+ *=============================================================================
+ */
+
+static irqreturn_t idt_thread_isr(int irq, void *devid);
+
+/*
+ * idt_init_isr() - initialize PCIe interrupt handler
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * Return: zero on success, otherwise a negative error number.
+ */
+static int idt_init_isr(struct idt_ntb_dev *ndev)
+{
+       struct pci_dev *pdev = ndev->ntb.pdev;
+       u32 ntint_mask;
+       int ret;
+
+       /* Allocate just one interrupt vector for the ISR */
+       ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_LEGACY);
+       if (ret != 1) {
+               dev_err(&pdev->dev, "Failed to allocate IRQ vector");
+               return ret;
+       }
+
+       /* Retrieve the IRQ vector */
+       ret = pci_irq_vector(pdev, 0);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to get IRQ vector");
+               goto err_free_vectors;
+       }
+
+       /* Set the IRQ handler */
+       ret = devm_request_threaded_irq(&pdev->dev, ret, NULL, idt_thread_isr,
+                                       IRQF_ONESHOT, NTB_IRQNAME, ndev);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to set MSI IRQ handler, %d", ret);
+               goto err_free_vectors;
+       }
+
+       /* Unmask Message/Doorbell/SE/Temperature interrupts */
+       ntint_mask = idt_nt_read(ndev, IDT_NT_NTINTMSK) & ~IDT_NTINTMSK_ALL;
+       idt_nt_write(ndev, IDT_NT_NTINTMSK, ntint_mask);
+
+       /* From now on the interrupts are enabled */
+       dev_dbg(&pdev->dev, "NTB interrupts initialized");
+
+       return 0;
+
+err_free_vectors:
+       pci_free_irq_vectors(pdev);
+
+       return ret;
+}
+
+
+/*
+ * idt_deinit_ist() - deinitialize PCIe interrupt handler
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * Disable corresponding interrupts and free allocated IRQ vectors.
+ */
+static void idt_deinit_isr(struct idt_ntb_dev *ndev)
+{
+       struct pci_dev *pdev = ndev->ntb.pdev;
+       u32 ntint_mask;
+
+       /* Mask interrupts back */
+       ntint_mask = idt_nt_read(ndev, IDT_NT_NTINTMSK) | IDT_NTINTMSK_ALL;
+       idt_nt_write(ndev, IDT_NT_NTINTMSK, ntint_mask);
+
+       /* Manually free IRQ otherwise PCI free irq vectors will fail */
+       devm_free_irq(&pdev->dev, pci_irq_vector(pdev, 0), ndev);
+
+       /* Free allocated IRQ vectors */
+       pci_free_irq_vectors(pdev);
+
+       dev_dbg(&pdev->dev, "NTB interrupts deinitialized");
+}
+
+/*
+ * idt_thread_isr() - NT function interrupts handler
+ * @irq:       IRQ number
+ * @devid:     Custom buffer
+ *
+ * It reads current NT interrupts state register and handles all the event
+ * it declares.
+ * The method is bottom-half routine of actual default PCIe IRQ handler.
+ */
+static irqreturn_t idt_thread_isr(int irq, void *devid)
+{
+       struct idt_ntb_dev *ndev = devid;
+       bool handled = false;
+       u32 ntint_sts;
+
+       /* Read the NT interrupts status register */
+       ntint_sts = idt_nt_read(ndev, IDT_NT_NTINTSTS);
+
+       /* Handle messaging interrupts */
+       if (ntint_sts & IDT_NTINTSTS_MSG) {
+               idt_msg_isr(ndev, ntint_sts);
+               handled = true;
+       }
+
+       /* Handle doorbell interrupts */
+       if (ntint_sts & IDT_NTINTSTS_DBELL) {
+               idt_db_isr(ndev, ntint_sts);
+               handled = true;
+       }
+
+       /* Handle switch event interrupts */
+       if (ntint_sts & IDT_NTINTSTS_SEVENT) {
+               idt_se_isr(ndev, ntint_sts);
+               handled = true;
+       }
+
+       /* Handle temperature sensor interrupt */
+       if (ntint_sts & IDT_NTINTSTS_TMPSENSOR) {
+               idt_temp_isr(ndev, ntint_sts);
+               handled = true;
+       }
+
+       dev_dbg(&ndev->ntb.pdev->dev, "IDT IRQs 0x%08x handled", ntint_sts);
+
+       return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*===========================================================================
+ *                     9. NTB hardware driver initialization
+ *===========================================================================
+ */
+
+/*
+ * NTB API operations
+ */
+static const struct ntb_dev_ops idt_ntb_ops = {
+       .port_number            = idt_ntb_port_number,
+       .peer_port_count        = idt_ntb_peer_port_count,
+       .peer_port_number       = idt_ntb_peer_port_number,
+       .peer_port_idx          = idt_ntb_peer_port_idx,
+       .link_is_up             = idt_ntb_link_is_up,
+       .link_enable            = idt_ntb_link_enable,
+       .link_disable           = idt_ntb_link_disable,
+       .mw_count               = idt_ntb_mw_count,
+       .mw_get_align           = idt_ntb_mw_get_align,
+       .peer_mw_count          = idt_ntb_peer_mw_count,
+       .peer_mw_get_addr       = idt_ntb_peer_mw_get_addr,
+       .peer_mw_set_trans      = idt_ntb_peer_mw_set_trans,
+       .peer_mw_clear_trans    = idt_ntb_peer_mw_clear_trans,
+       .db_valid_mask          = idt_ntb_db_valid_mask,
+       .db_read                = idt_ntb_db_read,
+       .db_clear               = idt_ntb_db_clear,
+       .db_read_mask           = idt_ntb_db_read_mask,
+       .db_set_mask            = idt_ntb_db_set_mask,
+       .db_clear_mask          = idt_ntb_db_clear_mask,
+       .peer_db_set            = idt_ntb_peer_db_set,
+       .msg_count              = idt_ntb_msg_count,
+       .msg_inbits             = idt_ntb_msg_inbits,
+       .msg_outbits            = idt_ntb_msg_outbits,
+       .msg_read_sts           = idt_ntb_msg_read_sts,
+       .msg_clear_sts          = idt_ntb_msg_clear_sts,
+       .msg_set_mask           = idt_ntb_msg_set_mask,
+       .msg_clear_mask         = idt_ntb_msg_clear_mask,
+       .msg_read               = idt_ntb_msg_read,
+       .msg_write              = idt_ntb_msg_write
+};
+
+/*
+ * idt_register_device() - register IDT NTB device
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * Return: zero on success, otherwise a negative error number.
+ */
+static int idt_register_device(struct idt_ntb_dev *ndev)
+{
+       int ret;
+
+       /* Initialize the rest of NTB device structure and register it */
+       ndev->ntb.ops = &idt_ntb_ops;
+       ndev->ntb.topo = NTB_TOPO_PRI;
+
+       ret = ntb_register_device(&ndev->ntb);
+       if (ret != 0) {
+               dev_err(&ndev->ntb.pdev->dev, "Failed to register NTB device");
+               return ret;
+       }
+
+       dev_dbg(&ndev->ntb.pdev->dev, "NTB device successfully registered");
+
+       return 0;
+}
+
+/*
+ * idt_unregister_device() - unregister IDT NTB device
+ * @ndev:      IDT NTB hardware driver descriptor
+ */
+static void idt_unregister_device(struct idt_ntb_dev *ndev)
+{
+       /* Just unregister the NTB device */
+       ntb_unregister_device(&ndev->ntb);
+
+       dev_dbg(&ndev->ntb.pdev->dev, "NTB device unregistered");
+}
+
+/*=============================================================================
+ *                        10. DebugFS node initialization
+ *=============================================================================
+ */
+
+static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
+                                  size_t count, loff_t *offp);
+
+/*
+ * Driver DebugFS info file operations
+ */
+static const struct file_operations idt_dbgfs_info_ops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .read = idt_dbgfs_info_read
+};
+
+/*
+ * idt_dbgfs_info_read() - DebugFS read info node callback
+ * @file:      File node descriptor.
+ * @ubuf:      User-space buffer to put data to
+ * @count:     Size of the buffer
+ * @offp:      Offset within the buffer
+ */
+static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
+                                  size_t count, loff_t *offp)
+{
+       struct idt_ntb_dev *ndev = filp->private_data;
+       unsigned char temp, frac, idx, pidx, cnt;
+       ssize_t ret = 0, off = 0;
+       unsigned long irqflags;
+       enum ntb_speed speed;
+       enum ntb_width width;
+       char *strbuf;
+       size_t size;
+       u32 data;
+
+       /* Lets limit the buffer size the way the Intel/AMD drivers do */
+       size = min_t(size_t, count, 0x1000U);
+
+       /* Allocate the memory for the buffer */
+       strbuf = kmalloc(size, GFP_KERNEL);
+       if (strbuf == NULL)
+               return -ENOMEM;
+
+       /* Put the data into the string buffer */
+       off += scnprintf(strbuf + off, size - off,
+               "\n\t\tIDT NTB device Information:\n\n");
+
+       /* General local device configurations */
+       off += scnprintf(strbuf + off, size - off,
+               "Local Port %hhu, Partition %hhu\n", ndev->port, ndev->part);
+
+       /* Peer ports information */
+       off += scnprintf(strbuf + off, size - off, "Peers:\n");
+       for (idx = 0; idx < ndev->peer_cnt; idx++) {
+               off += scnprintf(strbuf + off, size - off,
+                       "\t%hhu. Port %hhu, Partition %hhu\n",
+                       idx, ndev->peers[idx].port, ndev->peers[idx].part);
+       }
+
+       /* Links status */
+       data = idt_ntb_link_is_up(&ndev->ntb, &speed, &width);
+       off += scnprintf(strbuf + off, size - off,
+               "NTB link status\t- 0x%08x, ", data);
+       off += scnprintf(strbuf + off, size - off, "PCIe Gen %d x%d lanes\n",
+               speed, width);
+
+       /* Mapping table entries */
+       off += scnprintf(strbuf + off, size - off, "NTB Mapping Table:\n");
+       for (idx = 0; idx < IDT_MTBL_ENTRY_CNT; idx++) {
+               spin_lock_irqsave(&ndev->mtbl_lock, irqflags);
+               idt_nt_write(ndev, IDT_NT_NTMTBLADDR, idx);
+               data = idt_nt_read(ndev, IDT_NT_NTMTBLDATA);
+               spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags);
+
+               /* Print valid entries only */
+               if (data & IDT_NTMTBLDATA_VALID) {
+                       off += scnprintf(strbuf + off, size - off,
+                               "\t%hhu. Partition %d, Requester ID 0x%04x\n",
+                               idx, GET_FIELD(NTMTBLDATA_PART, data),
+                               GET_FIELD(NTMTBLDATA_REQID, data));
+               }
+       }
+       off += scnprintf(strbuf + off, size - off, "\n");
+
+       /* Outbound memory windows information */
+       off += scnprintf(strbuf + off, size - off,
+               "Outbound Memory Windows:\n");
+       for (idx = 0; idx < ndev->mw_cnt; idx += cnt) {
+               data = ndev->mws[idx].type;
+               cnt = idt_get_mw_count(data);
+
+               /* Print Memory Window information */
+               if (data == IDT_MW_DIR)
+                       off += scnprintf(strbuf + off, size - off,
+                               "\t%hhu.\t", idx);
+               else
+                       off += scnprintf(strbuf + off, size - off,
+                               "\t%hhu-%hhu.\t", idx, idx + cnt - 1);
+
+               off += scnprintf(strbuf + off, size - off, "%s BAR%hhu, ",
+                       idt_get_mw_name(data), ndev->mws[idx].bar);
+
+               off += scnprintf(strbuf + off, size - off,
+                       "Address align 0x%08llx, ", ndev->mws[idx].addr_align);
+
+               off += scnprintf(strbuf + off, size - off,
+                       "Size align 0x%08llx, Size max %llu\n",
+                       ndev->mws[idx].size_align, ndev->mws[idx].size_max);
+       }
+
+       /* Inbound memory windows information */
+       for (pidx = 0; pidx < ndev->peer_cnt; pidx++) {
+               off += scnprintf(strbuf + off, size - off,
+                       "Inbound Memory Windows for peer %hhu (Port %hhu):\n",
+                       pidx, ndev->peers[pidx].port);
+
+               /* Print Memory Windows information */
+               for (idx = 0; idx < ndev->peers[pidx].mw_cnt; idx += cnt) {
+                       data = ndev->peers[pidx].mws[idx].type;
+                       cnt = idt_get_mw_count(data);
+
+                       if (data == IDT_MW_DIR)
+                               off += scnprintf(strbuf + off, size - off,
+                                       "\t%hhu.\t", idx);
+                       else
+                               off += scnprintf(strbuf + off, size - off,
+                                       "\t%hhu-%hhu.\t", idx, idx + cnt - 1);
+
+                       off += scnprintf(strbuf + off, size - off,
+                               "%s BAR%hhu, ", idt_get_mw_name(data),
+                               ndev->peers[pidx].mws[idx].bar);
+
+                       off += scnprintf(strbuf + off, size - off,
+                               "Address align 0x%08llx, ",
+                               ndev->peers[pidx].mws[idx].addr_align);
+
+                       off += scnprintf(strbuf + off, size - off,
+                               "Size align 0x%08llx, Size max %llu\n",
+                               ndev->peers[pidx].mws[idx].size_align,
+                               ndev->peers[pidx].mws[idx].size_max);
+               }
+       }
+       off += scnprintf(strbuf + off, size - off, "\n");
+
+       /* Doorbell information */
+       data = idt_sw_read(ndev, IDT_SW_GDBELLSTS);
+       off += scnprintf(strbuf + off, size - off,
+                "Global Doorbell state\t- 0x%08x\n", data);
+       data = idt_ntb_db_read(&ndev->ntb);
+       off += scnprintf(strbuf + off, size - off,
+                "Local  Doorbell state\t- 0x%08x\n", data);
+       data = idt_nt_read(ndev, IDT_NT_INDBELLMSK);
+       off += scnprintf(strbuf + off, size - off,
+                "Local  Doorbell mask\t- 0x%08x\n", data);
+       off += scnprintf(strbuf + off, size - off, "\n");
+
+       /* Messaging information */
+       off += scnprintf(strbuf + off, size - off,
+                "Message event valid\t- 0x%08x\n", IDT_MSG_MASK);
+       data = idt_ntb_msg_read_sts(&ndev->ntb);
+       off += scnprintf(strbuf + off, size - off,
+                "Message event status\t- 0x%08x\n", data);
+       data = idt_nt_read(ndev, IDT_NT_MSGSTSMSK);
+       off += scnprintf(strbuf + off, size - off,
+                "Message event mask\t- 0x%08x\n", data);
+       off += scnprintf(strbuf + off, size - off,
+                "Message data:\n");
+       for (idx = 0; idx < IDT_MSG_CNT; idx++) {
+               int src;
+               (void)idt_ntb_msg_read(&ndev->ntb, idx, &src, &data);
+               off += scnprintf(strbuf + off, size - off,
+                       "\t%hhu. 0x%08x from peer %hhu (Port %hhu)\n",
+                       idx, data, src, ndev->peers[src].port);
+       }
+       off += scnprintf(strbuf + off, size - off, "\n");
+
+       /* Current temperature */
+       idt_read_temp(ndev, &temp, &frac);
+       off += scnprintf(strbuf + off, size - off,
+               "Switch temperature\t\t- %hhu.%hhuC\n", temp, frac);
+
+       /* Copy the buffer to the User Space */
+       ret = simple_read_from_buffer(ubuf, count, offp, strbuf, off);
+       kfree(strbuf);
+
+       return ret;
+}
+
+/*
+ * idt_init_dbgfs() - initialize DebugFS node
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * Return: zero on success, otherwise a negative error number.
+ */
+static int idt_init_dbgfs(struct idt_ntb_dev *ndev)
+{
+       char devname[64];
+
+       /* If the top directory is not created then do nothing */
+       if (IS_ERR_OR_NULL(dbgfs_topdir)) {
+               dev_info(&ndev->ntb.pdev->dev, "Top DebugFS directory absent");
+               return PTR_ERR(dbgfs_topdir);
+       }
+
+       /* Create the info file node */
+       snprintf(devname, 64, "info:%s", pci_name(ndev->ntb.pdev));
+       ndev->dbgfs_info = debugfs_create_file(devname, 0400, dbgfs_topdir,
+               ndev, &idt_dbgfs_info_ops);
+       if (IS_ERR(ndev->dbgfs_info)) {
+               dev_dbg(&ndev->ntb.pdev->dev, "Failed to create DebugFS node");
+               return PTR_ERR(ndev->dbgfs_info);
+       }
+
+       dev_dbg(&ndev->ntb.pdev->dev, "NTB device DebugFS node created");
+
+       return 0;
+}
+
+/*
+ * idt_deinit_dbgfs() - deinitialize DebugFS node
+ * @ndev:      IDT NTB hardware driver descriptor
+ *
+ * Just discard the info node from DebugFS
+ */
+static void idt_deinit_dbgfs(struct idt_ntb_dev *ndev)
+{
+       debugfs_remove(ndev->dbgfs_info);
+
+       dev_dbg(&ndev->ntb.pdev->dev, "NTB device DebugFS node discarded");
+}
+
+/*=============================================================================
+ *                     11. Basic PCIe device initialization
+ *=============================================================================
+ */
+
+/*
+ * idt_check_setup() - Check whether the IDT PCIe-swtich is properly
+ *                    pre-initialized
+ * @pdev:      Pointer to the PCI device descriptor
+ *
+ * Return: zero on success, otherwise a negative error number.
+ */
+static int idt_check_setup(struct pci_dev *pdev)
+{
+       u32 data;
+       int ret;
+
+       /* Read the BARSETUP0 */
+       ret = pci_read_config_dword(pdev, IDT_NT_BARSETUP0, &data);
+       if (ret != 0) {
+               dev_err(&pdev->dev,
+                       "Failed to read BARSETUP0 config register");
+               return ret;
+       }
+
+       /* Check whether the BAR0 register is enabled to be of config space */
+       if (!(data & IDT_BARSETUP_EN) || !(data & IDT_BARSETUP_MODE_CFG)) {
+               dev_err(&pdev->dev, "BAR0 doesn't map config space");
+               return -EINVAL;
+       }
+
+       /* Configuration space BAR0 must have certain size */
+       if ((data & IDT_BARSETUP_SIZE_MASK) != IDT_BARSETUP_SIZE_CFG) {
+               dev_err(&pdev->dev, "Invalid size of config space");
+               return -EINVAL;
+       }
+
+       dev_dbg(&pdev->dev, "NTB device pre-initialized correctly");
+
+       return 0;
+}
+
+/*
+ * Create the IDT PCIe-switch driver descriptor
+ * @pdev:      Pointer to the PCI device descriptor
+ * @id:                IDT PCIe-device configuration
+ *
+ * It just allocates a memory for IDT PCIe-switch device structure and
+ * initializes some commonly used fields.
+ *
+ * No need of release method, since managed device resource is used for
+ * memory allocation.
+ *
+ * Return: pointer to the descriptor, otherwise a negative error number.
+ */
+static struct idt_ntb_dev *idt_create_dev(struct pci_dev *pdev,
+                                         const struct pci_device_id *id)
+{
+       struct idt_ntb_dev *ndev;
+
+       /* Allocate memory for the IDT PCIe-device descriptor */
+       ndev = devm_kzalloc(&pdev->dev, sizeof(*ndev), GFP_KERNEL);
+       if (IS_ERR_OR_NULL(ndev)) {
+               dev_err(&pdev->dev, "Memory allocation failed for descriptor");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       /* Save the IDT PCIe-switch ports configuration */
+       ndev->swcfg = (struct idt_89hpes_cfg *)id->driver_data;
+       /* Save the PCI-device pointer inside the NTB device structure */
+       ndev->ntb.pdev = pdev;
+
+       /* Initialize spin locker of Doorbell, Message and GASA registers */
+       spin_lock_init(&ndev->db_mask_lock);
+       spin_lock_init(&ndev->msg_mask_lock);
+       spin_lock_init(&ndev->gasa_lock);
+
+       dev_info(&pdev->dev, "IDT %s discovered", ndev->swcfg->name);
+
+       dev_dbg(&pdev->dev, "NTB device descriptor created");
+
+       return ndev;
+}
+
+/*
+ * idt_init_pci() - initialize the basic PCI-related subsystem
+ * @ndev:      Pointer to the IDT PCIe-switch driver descriptor
+ *
+ * Managed device resources will be freed automatically in case of failure or
+ * driver detachment.
+ *
+ * Return: zero on success, otherwise negative error number.
+ */
+static int idt_init_pci(struct idt_ntb_dev *ndev)
+{
+       struct pci_dev *pdev = ndev->ntb.pdev;
+       int ret;
+
+       /* Initialize the bit mask of DMA */
+       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       if (ret != 0) {
+               ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (ret != 0) {
+                       dev_err(&pdev->dev, "Failed to set DMA bit mask\n");
+                       return ret;
+               }
+               dev_warn(&pdev->dev, "Cannot set DMA highmem bit mask\n");
+       }
+       ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+       if (ret != 0) {
+               ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (ret != 0) {
+                       dev_err(&pdev->dev,
+                               "Failed to set consistent DMA bit mask\n");
+                       return ret;
+               }
+               dev_warn(&pdev->dev,
+                       "Cannot set consistent DMA highmem bit mask\n");
+       }
+
+       /*
+        * Enable the device advanced error reporting. It's not critical to
+        * have AER disabled in the kernel.
+        */
+       ret = pci_enable_pcie_error_reporting(pdev);
+       if (ret != 0)
+               dev_warn(&pdev->dev, "PCIe AER capability disabled\n");
+       else /* Cleanup uncorrectable error status before getting to init */
+               pci_cleanup_aer_uncorrect_error_status(pdev);
+
+       /* First enable the PCI device */
+       ret = pcim_enable_device(pdev);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to enable PCIe device\n");
+               goto err_disable_aer;
+       }
+
+       /*
+        * Enable the bus mastering, which effectively enables MSI IRQs and
+        * Request TLPs translation
+        */
+       pci_set_master(pdev);
+
+       /* Request all BARs resources and map BAR0 only */
+       ret = pcim_iomap_regions_request_all(pdev, 1, NTB_NAME);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to request resources\n");
+               goto err_clear_master;
+       }
+
+       /* Retrieve virtual address of BAR0 - PCI configuration space */
+       ndev->cfgspc = pcim_iomap_table(pdev)[0];
+
+       /* Put the IDT driver data pointer to the PCI-device private pointer */
+       pci_set_drvdata(pdev, ndev);
+
+       dev_dbg(&pdev->dev, "NT-function PCIe interface initialized");
+
+       return 0;
+
+err_clear_master:
+       pci_clear_master(pdev);
+err_disable_aer:
+       (void)pci_disable_pcie_error_reporting(pdev);
+
+       return ret;
+}
+
+/*
+ * idt_deinit_pci() - deinitialize the basic PCI-related subsystem
+ * @ndev:      Pointer to the IDT PCIe-switch driver descriptor
+ *
+ * Managed resources will be freed on the driver detachment
+ */
+static void idt_deinit_pci(struct idt_ntb_dev *ndev)
+{
+       struct pci_dev *pdev = ndev->ntb.pdev;
+
+       /* Clean up the PCI-device private data pointer */
+       pci_set_drvdata(pdev, NULL);
+
+       /* Clear the bus master disabling the Request TLPs translation */
+       pci_clear_master(pdev);
+
+       /* Disable the AER capability */
+       (void)pci_disable_pcie_error_reporting(pdev);
+
+       dev_dbg(&pdev->dev, "NT-function PCIe interface cleared");
+}
+
+/*===========================================================================
+ *                       12. PCI bus callback functions
+ *===========================================================================
+ */
+
+/*
+ * idt_pci_probe() - PCI device probe callback
+ * @pdev:      Pointer to PCI device structure
+ * @id:                PCIe device custom descriptor
+ *
+ * Return: zero on success, otherwise negative error number
+ */
+static int idt_pci_probe(struct pci_dev *pdev,
+                        const struct pci_device_id *id)
+{
+       struct idt_ntb_dev *ndev;
+       int ret;
+
+       /* Check whether IDT PCIe-switch is properly pre-initialized */
+       ret = idt_check_setup(pdev);
+       if (ret != 0)
+               return ret;
+
+       /* Allocate the memory for IDT NTB device data */
+       ndev = idt_create_dev(pdev, id);
+       if (IS_ERR_OR_NULL(ndev))
+               return PTR_ERR(ndev);
+
+       /* Initialize the basic PCI subsystem of the device */
+       ret = idt_init_pci(ndev);
+       if (ret != 0)
+               return ret;
+
+       /* Scan ports of the IDT PCIe-switch */
+       (void)idt_scan_ports(ndev);
+
+       /* Initialize NTB link events subsystem */
+       idt_init_link(ndev);
+
+       /* Initialize MWs subsystem */
+       ret = idt_init_mws(ndev);
+       if (ret != 0)
+               goto err_deinit_link;
+
+       /* Initialize Messaging subsystem */
+       idt_init_msg(ndev);
+
+       /* Initialize IDT interrupts handler */
+       ret = idt_init_isr(ndev);
+       if (ret != 0)
+               goto err_deinit_link;
+
+       /* Register IDT NTB devices on the NTB bus */
+       ret = idt_register_device(ndev);
+       if (ret != 0)
+               goto err_deinit_isr;
+
+       /* Initialize DebugFS info node */
+       (void)idt_init_dbgfs(ndev);
+
+       /* IDT PCIe-switch NTB driver is finally initialized */
+       dev_info(&pdev->dev, "IDT NTB device is ready");
+
+       /* May the force be with us... */
+       return 0;
+
+err_deinit_isr:
+       idt_deinit_isr(ndev);
+err_deinit_link:
+       idt_deinit_link(ndev);
+       idt_deinit_pci(ndev);
+
+       return ret;
+}
+
+/*
+ * idt_pci_probe() - PCI device remove callback
+ * @pdev:      Pointer to PCI device structure
+ */
+static void idt_pci_remove(struct pci_dev *pdev)
+{
+       struct idt_ntb_dev *ndev = pci_get_drvdata(pdev);
+
+       /* Deinit the DebugFS node */
+       idt_deinit_dbgfs(ndev);
+
+       /* Unregister NTB device */
+       idt_unregister_device(ndev);
+
+       /* Stop the interrupts handling */
+       idt_deinit_isr(ndev);
+
+       /* Deinitialize link event subsystem */
+       idt_deinit_link(ndev);
+
+       /* Deinit basic PCI subsystem */
+       idt_deinit_pci(ndev);
+
+       /* IDT PCIe-switch NTB driver is finally initialized */
+       dev_info(&pdev->dev, "IDT NTB device is removed");
+
+       /* Sayonara... */
+}
+
+/*
+ * IDT PCIe-switch models ports configuration structures
+ */
+static struct idt_89hpes_cfg idt_89hpes24nt6ag2_config = {
+       .name = "89HPES24NT6AG2",
+       .port_cnt = 6, .ports = {0, 2, 4, 6, 8, 12}
+};
+static struct idt_89hpes_cfg idt_89hpes32nt8ag2_config = {
+       .name = "89HPES32NT8AG2",
+       .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
+};
+static struct idt_89hpes_cfg idt_89hpes32nt8bg2_config = {
+       .name = "89HPES32NT8BG2",
+       .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
+};
+static struct idt_89hpes_cfg idt_89hpes12nt12g2_config = {
+       .name = "89HPES12NT12G2",
+       .port_cnt = 3, .ports = {0, 8, 16}
+};
+static struct idt_89hpes_cfg idt_89hpes16nt16g2_config = {
+       .name = "89HPES16NT16G2",
+       .port_cnt = 4, .ports = {0, 8, 12, 16}
+};
+static struct idt_89hpes_cfg idt_89hpes24nt24g2_config = {
+       .name = "89HPES24NT24G2",
+       .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
+};
+static struct idt_89hpes_cfg idt_89hpes32nt24ag2_config = {
+       .name = "89HPES32NT24AG2",
+       .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
+};
+static struct idt_89hpes_cfg idt_89hpes32nt24bg2_config = {
+       .name = "89HPES32NT24BG2",
+       .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
+};
+
+/*
+ * PCI-ids table of the supported IDT PCIe-switch devices
+ */
+static const struct pci_device_id idt_pci_tbl[] = {
+       {IDT_PCI_DEVICE_IDS(89HPES24NT6AG2,  idt_89hpes24nt6ag2_config)},
+       {IDT_PCI_DEVICE_IDS(89HPES32NT8AG2,  idt_89hpes32nt8ag2_config)},
+       {IDT_PCI_DEVICE_IDS(89HPES32NT8BG2,  idt_89hpes32nt8bg2_config)},
+       {IDT_PCI_DEVICE_IDS(89HPES12NT12G2,  idt_89hpes12nt12g2_config)},
+       {IDT_PCI_DEVICE_IDS(89HPES16NT16G2,  idt_89hpes16nt16g2_config)},
+       {IDT_PCI_DEVICE_IDS(89HPES24NT24G2,  idt_89hpes24nt24g2_config)},
+       {IDT_PCI_DEVICE_IDS(89HPES32NT24AG2, idt_89hpes32nt24ag2_config)},
+       {IDT_PCI_DEVICE_IDS(89HPES32NT24BG2, idt_89hpes32nt24bg2_config)},
+       {0}
+};
+MODULE_DEVICE_TABLE(pci, idt_pci_tbl);
+
+/*
+ * IDT PCIe-switch NT-function device driver structure definition
+ */
+static struct pci_driver idt_pci_driver = {
+       .name           = KBUILD_MODNAME,
+       .probe          = idt_pci_probe,
+       .remove         = idt_pci_remove,
+       .id_table       = idt_pci_tbl,
+};
+
+static int __init idt_pci_driver_init(void)
+{
+       pr_info("%s %s\n", NTB_DESC, NTB_VER);
+
+       /* Create the top DebugFS directory if the FS is initialized */
+       if (debugfs_initialized())
+               dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+       /* Register the NTB hardware driver to handle the PCI device */
+       return pci_register_driver(&idt_pci_driver);
+}
+module_init(idt_pci_driver_init);
+
+static void __exit idt_pci_driver_exit(void)
+{
+       /* Unregister the NTB hardware driver */
+       pci_unregister_driver(&idt_pci_driver);
+
+       /* Discard the top DebugFS directory */
+       debugfs_remove_recursive(dbgfs_topdir);
+}
+module_exit(idt_pci_driver_exit);
+
diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.h b/drivers/ntb/hw/idt/ntb_hw_idt.h
new file mode 100644 (file)
index 0000000..856fd18
--- /dev/null
@@ -0,0 +1,1149 @@
+/*
+ *   This file is provided under a GPLv2 license.  When using or
+ *   redistributing this file, you may do so under that license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright (C) 2016 T-Platforms All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify it
+ *   under the terms and conditions of the GNU General Public License,
+ *   version 2, as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope 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, one can be found http://www.gnu.org/licenses/.
+ *
+ *   The full GNU General Public License is included in this distribution in
+ *   the file called "COPYING".
+ *
+ *   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.
+ *
+ * IDT PCIe-switch NTB Linux driver
+ *
+ * Contact Information:
+ * Serge Semin <fancer.lancer@gmail.com>, <Sergey.Semin@t-platforms.ru>
+ */
+
+#ifndef NTB_HW_IDT_H
+#define NTB_HW_IDT_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/ntb.h>
+
+
+/*
+ * Macro is used to create the struct pci_device_id that matches
+ * the supported IDT PCIe-switches
+ * @devname: Capitalized name of the particular device
+ * @data: Variable passed to the driver of the particular device
+ */
+#define IDT_PCI_DEVICE_IDS(devname, data) \
+       .vendor = PCI_VENDOR_ID_IDT, .device = PCI_DEVICE_ID_IDT_##devname, \
+       .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \
+       .class = (PCI_CLASS_BRIDGE_OTHER << 8), .class_mask = (0xFFFF00), \
+       .driver_data = (kernel_ulong_t)&data
+
+/*
+ * IDT PCIe-switches device IDs
+ */
+#define PCI_DEVICE_ID_IDT_89HPES24NT6AG2  0x8091
+#define PCI_DEVICE_ID_IDT_89HPES32NT8AG2  0x808F
+#define PCI_DEVICE_ID_IDT_89HPES32NT8BG2  0x8088
+#define PCI_DEVICE_ID_IDT_89HPES12NT12G2  0x8092
+#define PCI_DEVICE_ID_IDT_89HPES16NT16G2  0x8090
+#define PCI_DEVICE_ID_IDT_89HPES24NT24G2  0x808E
+#define PCI_DEVICE_ID_IDT_89HPES32NT24AG2 0x808C
+#define PCI_DEVICE_ID_IDT_89HPES32NT24BG2 0x808A
+
+/*
+ * NT-function Configuration Space registers
+ * NOTE 1) The IDT PCIe-switch internal data is little-endian
+ *      so it must be taken into account in the driver
+ *      internals.
+ *      2) Additionally the registers should be accessed either
+ *      with byte-enables corresponding to their native size or
+ *      the size of one DWORD
+ *
+ * So to simplify the driver code, there is only DWORD-sized read/write
+ * operations utilized.
+ */
+/* PCI Express Configuration Space */
+/* PCI Express command/status register (DWORD) */
+#define IDT_NT_PCICMDSTS               0x00004U
+/* PCI Express Device Capabilities     (DWORD) */
+#define IDT_NT_PCIEDCAP                        0x00044U
+/* PCI Express Device Control/Status   (WORD+WORD) */
+#define IDT_NT_PCIEDCTLSTS             0x00048U
+/* PCI Express Link Capabilities       (DWORD) */
+#define IDT_NT_PCIELCAP                        0x0004CU
+/* PCI Express Link Control/Status     (WORD+WORD) */
+#define IDT_NT_PCIELCTLSTS             0x00050U
+/* PCI Express Device Capabilities 2   (DWORD) */
+#define IDT_NT_PCIEDCAP2               0x00064U
+/* PCI Express Device Control 2                (WORD+WORD) */
+#define IDT_NT_PCIEDCTL2               0x00068U
+/* PCI Power Management Control and Status (DWORD) */
+#define IDT_NT_PMCSR                   0x000C4U
+/*==========================================*/
+/* IDT Proprietary NT-port-specific registers */
+/* NT-function main control registers */
+/* NT Endpoint Control                 (DWORD) */
+#define IDT_NT_NTCTL                   0x00400U
+/* NT Endpoint Interrupt Status/Mask   (DWORD) */
+#define IDT_NT_NTINTSTS                        0x00404U
+#define IDT_NT_NTINTMSK                        0x00408U
+/* NT Endpoint Signal Data             (DWORD) */
+#define IDT_NT_NTSDATA                 0x0040CU
+/* NT Endpoint Global Signal           (DWORD) */
+#define IDT_NT_NTGSIGNAL               0x00410U
+/* Internal Error Reporting Mask 0/1   (DWORD) */
+#define IDT_NT_NTIERRORMSK0            0x00414U
+#define IDT_NT_NTIERRORMSK1            0x00418U
+/* Doorbel registers */
+/* NT Outbound Doorbell Set            (DWORD) */
+#define IDT_NT_OUTDBELLSET             0x00420U
+/* NT Inbound Doorbell Status/Mask     (DWORD) */
+#define IDT_NT_INDBELLSTS              0x00428U
+#define IDT_NT_INDBELLMSK              0x0042CU
+/* Message registers */
+/* Outbound Message N                  (DWORD) */
+#define IDT_NT_OUTMSG0                 0x00430U
+#define IDT_NT_OUTMSG1                 0x00434U
+#define IDT_NT_OUTMSG2                 0x00438U
+#define IDT_NT_OUTMSG3                 0x0043CU
+/* Inbound Message N                   (DWORD) */
+#define IDT_NT_INMSG0                  0x00440U
+#define IDT_NT_INMSG1                  0x00444U
+#define IDT_NT_INMSG2                  0x00448U
+#define IDT_NT_INMSG3                  0x0044CU
+/* Inbound Message Source N            (DWORD) */
+#define IDT_NT_INMSGSRC0               0x00450U
+#define IDT_NT_INMSGSRC1               0x00454U
+#define IDT_NT_INMSGSRC2               0x00458U
+#define IDT_NT_INMSGSRC3               0x0045CU
+/* Message Status                      (DWORD) */
+#define IDT_NT_MSGSTS                  0x00460U
+/* Message Status Mask                 (DWORD) */
+#define IDT_NT_MSGSTSMSK               0x00464U
+/* BAR-setup registers */
+/* BAR N Setup/Limit Address/Lower and Upper Translated Base Address (DWORD) */
+#define IDT_NT_BARSETUP0               0x00470U
+#define IDT_NT_BARLIMIT0               0x00474U
+#define IDT_NT_BARLTBASE0              0x00478U
+#define IDT_NT_BARUTBASE0              0x0047CU
+#define IDT_NT_BARSETUP1               0x00480U
+#define IDT_NT_BARLIMIT1               0x00484U
+#define IDT_NT_BARLTBASE1              0x00488U
+#define IDT_NT_BARUTBASE1              0x0048CU
+#define IDT_NT_BARSETUP2               0x00490U
+#define IDT_NT_BARLIMIT2               0x00494U
+#define IDT_NT_BARLTBASE2              0x00498U
+#define IDT_NT_BARUTBASE2              0x0049CU
+#define IDT_NT_BARSETUP3               0x004A0U
+#define IDT_NT_BARLIMIT3               0x004A4U
+#define IDT_NT_BARLTBASE3              0x004A8U
+#define IDT_NT_BARUTBASE3              0x004ACU
+#define IDT_NT_BARSETUP4               0x004B0U
+#define IDT_NT_BARLIMIT4               0x004B4U
+#define IDT_NT_BARLTBASE4              0x004B8U
+#define IDT_NT_BARUTBASE4              0x004BCU
+#define IDT_NT_BARSETUP5               0x004C0U
+#define IDT_NT_BARLIMIT5               0x004C4U
+#define IDT_NT_BARLTBASE5              0x004C8U
+#define IDT_NT_BARUTBASE5              0x004CCU
+/* NT mapping table registers */
+/* NT Mapping Table Address/Status/Data        (DWORD) */
+#define IDT_NT_NTMTBLADDR              0x004D0U
+#define IDT_NT_NTMTBLSTS               0x004D4U
+#define IDT_NT_NTMTBLDATA              0x004D8U
+/* Requester ID (Bus:Device:Function) Capture  (DWORD) */
+#define IDT_NT_REQIDCAP                        0x004DCU
+/* Memory Windows Lookup table registers */
+/* Lookup Table Offset/Lower, Middle and Upper data    (DWORD) */
+#define IDT_NT_LUTOFFSET               0x004E0U
+#define IDT_NT_LUTLDATA                        0x004E4U
+#define IDT_NT_LUTMDATA                        0x004E8U
+#define IDT_NT_LUTUDATA                        0x004ECU
+/* NT Endpoint Uncorrectable/Correctable Errors Emulation registers (DWORD) */
+#define IDT_NT_NTUEEM                  0x004F0U
+#define IDT_NT_NTCEEM                  0x004F4U
+/* Global Address Space Access/Data registers  (DWARD) */
+#define IDT_NT_GASAADDR                        0x00FF8U
+#define IDT_NT_GASADATA                        0x00FFCU
+
+/*
+ * IDT PCIe-switch Global Configuration and Status registers
+ */
+/* Port N Configuration register in global space */
+/* PCI Express command/status and link control/status registers (WORD+WORD) */
+#define IDT_SW_NTP0_PCIECMDSTS         0x01004U
+#define IDT_SW_NTP0_PCIELCTLSTS                0x01050U
+/* NT-function control register                (DWORD) */
+#define IDT_SW_NTP0_NTCTL              0x01400U
+/* BAR setup/limit/base address registers (DWORD) */
+#define IDT_SW_NTP0_BARSETUP0          0x01470U
+#define IDT_SW_NTP0_BARLIMIT0          0x01474U
+#define IDT_SW_NTP0_BARLTBASE0         0x01478U
+#define IDT_SW_NTP0_BARUTBASE0         0x0147CU
+#define IDT_SW_NTP0_BARSETUP1          0x01480U
+#define IDT_SW_NTP0_BARLIMIT1          0x01484U
+#define IDT_SW_NTP0_BARLTBASE1         0x01488U
+#define IDT_SW_NTP0_BARUTBASE1         0x0148CU
+#define IDT_SW_NTP0_BARSETUP2          0x01490U
+#define IDT_SW_NTP0_BARLIMIT2          0x01494U
+#define IDT_SW_NTP0_BARLTBASE2         0x01498U
+#define IDT_SW_NTP0_BARUTBASE2         0x0149CU
+#define IDT_SW_NTP0_BARSETUP3          0x014A0U
+#define IDT_SW_NTP0_BARLIMIT3          0x014A4U
+#define IDT_SW_NTP0_BARLTBASE3         0x014A8U
+#define IDT_SW_NTP0_BARUTBASE3         0x014ACU
+#define IDT_SW_NTP0_BARSETUP4          0x014B0U
+#define IDT_SW_NTP0_BARLIMIT4          0x014B4U
+#define IDT_SW_NTP0_BARLTBASE4         0x014B8U
+#define IDT_SW_NTP0_BARUTBASE4         0x014BCU
+#define IDT_SW_NTP0_BARSETUP5          0x014C0U
+#define IDT_SW_NTP0_BARLIMIT5          0x014C4U
+#define IDT_SW_NTP0_BARLTBASE5         0x014C8U
+#define IDT_SW_NTP0_BARUTBASE5         0x014CCU
+/* PCI Express command/status and link control/status registers (WORD+WORD) */
+#define IDT_SW_NTP2_PCIECMDSTS         0x05004U
+#define IDT_SW_NTP2_PCIELCTLSTS                0x05050U
+/* NT-function control register                (DWORD) */
+#define IDT_SW_NTP2_NTCTL              0x05400U
+/* BAR setup/limit/base address registers (DWORD) */
+#define IDT_SW_NTP2_BARSETUP0          0x05470U
+#define IDT_SW_NTP2_BARLIMIT0          0x05474U
+#define IDT_SW_NTP2_BARLTBASE0         0x05478U
+#define IDT_SW_NTP2_BARUTBASE0         0x0547CU
+#define IDT_SW_NTP2_BARSETUP1          0x05480U
+#define IDT_SW_NTP2_BARLIMIT1          0x05484U
+#define IDT_SW_NTP2_BARLTBASE1         0x05488U
+#define IDT_SW_NTP2_BARUTBASE1         0x0548CU
+#define IDT_SW_NTP2_BARSETUP2          0x05490U
+#define IDT_SW_NTP2_BARLIMIT2          0x05494U
+#define IDT_SW_NTP2_BARLTBASE2         0x05498U
+#define IDT_SW_NTP2_BARUTBASE2         0x0549CU
+#define IDT_SW_NTP2_BARSETUP3          0x054A0U
+#define IDT_SW_NTP2_BARLIMIT3          0x054A4U
+#define IDT_SW_NTP2_BARLTBASE3         0x054A8U
+#define IDT_SW_NTP2_BARUTBASE3         0x054ACU
+#define IDT_SW_NTP2_BARSETUP4          0x054B0U
+#define IDT_SW_NTP2_BARLIMIT4          0x054B4U
+#define IDT_SW_NTP2_BARLTBASE4         0x054B8U
+#define IDT_SW_NTP2_BARUTBASE4         0x054BCU
+#define IDT_SW_NTP2_BARSETUP5          0x054C0U
+#define IDT_SW_NTP2_BARLIMIT5          0x054C4U
+#define IDT_SW_NTP2_BARLTBASE5         0x054C8U
+#define IDT_SW_NTP2_BARUTBASE5         0x054CCU
+/* PCI Express command/status and link control/status registers (WORD+WORD) */
+#define IDT_SW_NTP4_PCIECMDSTS         0x09004U
+#define IDT_SW_NTP4_PCIELCTLSTS                0x09050U
+/* NT-function control register                (DWORD) */
+#define IDT_SW_NTP4_NTCTL              0x09400U
+/* BAR setup/limit/base address registers (DWORD) */
+#define IDT_SW_NTP4_BARSETUP0          0x09470U
+#define IDT_SW_NTP4_BARLIMIT0          0x09474U
+#define IDT_SW_NTP4_BARLTBASE0         0x09478U
+#define IDT_SW_NTP4_BARUTBASE0         0x0947CU
+#define IDT_SW_NTP4_BARSETUP1          0x09480U
+#define IDT_SW_NTP4_BARLIMIT1          0x09484U
+#define IDT_SW_NTP4_BARLTBASE1         0x09488U
+#define IDT_SW_NTP4_BARUTBASE1         0x0948CU
+#define IDT_SW_NTP4_BARSETUP2          0x09490U
+#define IDT_SW_NTP4_BARLIMIT2          0x09494U
+#define IDT_SW_NTP4_BARLTBASE2         0x09498U
+#define IDT_SW_NTP4_BARUTBASE2         0x0949CU
+#define IDT_SW_NTP4_BARSETUP3          0x094A0U
+#define IDT_SW_NTP4_BARLIMIT3          0x094A4U
+#define IDT_SW_NTP4_BARLTBASE3         0x094A8U
+#define IDT_SW_NTP4_BARUTBASE3         0x094ACU
+#define IDT_SW_NTP4_BARSETUP4          0x094B0U
+#define IDT_SW_NTP4_BARLIMIT4          0x094B4U
+#define IDT_SW_NTP4_BARLTBASE4         0x094B8U
+#define IDT_SW_NTP4_BARUTBASE4         0x094BCU
+#define IDT_SW_NTP4_BARSETUP5          0x094C0U
+#define IDT_SW_NTP4_BARLIMIT5          0x094C4U
+#define IDT_SW_NTP4_BARLTBASE5         0x094C8U
+#define IDT_SW_NTP4_BARUTBASE5         0x094CCU
+/* PCI Express command/status and link control/status registers (WORD+WORD) */
+#define IDT_SW_NTP6_PCIECMDSTS         0x0D004U
+#define IDT_SW_NTP6_PCIELCTLSTS                0x0D050U
+/* NT-function control register                (DWORD) */
+#define IDT_SW_NTP6_NTCTL              0x0D400U
+/* BAR setup/limit/base address registers (DWORD) */
+#define IDT_SW_NTP6_BARSETUP0          0x0D470U
+#define IDT_SW_NTP6_BARLIMIT0          0x0D474U
+#define IDT_SW_NTP6_BARLTBASE0         0x0D478U
+#define IDT_SW_NTP6_BARUTBASE0         0x0D47CU
+#define IDT_SW_NTP6_BARSETUP1          0x0D480U
+#define IDT_SW_NTP6_BARLIMIT1          0x0D484U
+#define IDT_SW_NTP6_BARLTBASE1         0x0D488U
+#define IDT_SW_NTP6_BARUTBASE1         0x0D48CU
+#define IDT_SW_NTP6_BARSETUP2          0x0D490U
+#define IDT_SW_NTP6_BARLIMIT2          0x0D494U
+#define IDT_SW_NTP6_BARLTBASE2         0x0D498U
+#define IDT_SW_NTP6_BARUTBASE2         0x0D49CU
+#define IDT_SW_NTP6_BARSETUP3          0x0D4A0U
+#define IDT_SW_NTP6_BARLIMIT3          0x0D4A4U
+#define IDT_SW_NTP6_BARLTBASE3         0x0D4A8U
+#define IDT_SW_NTP6_BARUTBASE3         0x0D4ACU
+#define IDT_SW_NTP6_BARSETUP4          0x0D4B0U
+#define IDT_SW_NTP6_BARLIMIT4          0x0D4B4U
+#define IDT_SW_NTP6_BARLTBASE4         0x0D4B8U
+#define IDT_SW_NTP6_BARUTBASE4         0x0D4BCU
+#define IDT_SW_NTP6_BARSETUP5          0x0D4C0U
+#define IDT_SW_NTP6_BARLIMIT5          0x0D4C4U
+#define IDT_SW_NTP6_BARLTBASE5         0x0D4C8U
+#define IDT_SW_NTP6_BARUTBASE5         0x0D4CCU
+/* PCI Express command/status and link control/status registers (WORD+WORD) */
+#define IDT_SW_NTP8_PCIECMDSTS         0x11004U
+#define IDT_SW_NTP8_PCIELCTLSTS                0x11050U
+/* NT-function control register                (DWORD) */
+#define IDT_SW_NTP8_NTCTL              0x11400U
+/* BAR setup/limit/base address registers (DWORD) */
+#define IDT_SW_NTP8_BARSETUP0          0x11470U
+#define IDT_SW_NTP8_BARLIMIT0          0x11474U
+#define IDT_SW_NTP8_BARLTBASE0         0x11478U
+#define IDT_SW_NTP8_BARUTBASE0         0x1147CU
+#define IDT_SW_NTP8_BARSETUP1          0x11480U
+#define IDT_SW_NTP8_BARLIMIT1          0x11484U
+#define IDT_SW_NTP8_BARLTBASE1         0x11488U
+#define IDT_SW_NTP8_BARUTBASE1         0x1148CU
+#define IDT_SW_NTP8_BARSETUP2          0x11490U
+#define IDT_SW_NTP8_BARLIMIT2          0x11494U
+#define IDT_SW_NTP8_BARLTBASE2         0x11498U
+#define IDT_SW_NTP8_BARUTBASE2         0x1149CU
+#define IDT_SW_NTP8_BARSETUP3          0x114A0U
+#define IDT_SW_NTP8_BARLIMIT3          0x114A4U
+#define IDT_SW_NTP8_BARLTBASE3         0x114A8U
+#define IDT_SW_NTP8_BARUTBASE3         0x114ACU
+#define IDT_SW_NTP8_BARSETUP4          0x114B0U
+#define IDT_SW_NTP8_BARLIMIT4          0x114B4U
+#define IDT_SW_NTP8_BARLTBASE4         0x114B8U
+#define IDT_SW_NTP8_BARUTBASE4         0x114BCU
+#define IDT_SW_NTP8_BARSETUP5          0x114C0U
+#define IDT_SW_NTP8_BARLIMIT5          0x114C4U
+#define IDT_SW_NTP8_BARLTBASE5         0x114C8U
+#define IDT_SW_NTP8_BARUTBASE5         0x114CCU
+/* PCI Express command/status and link control/status registers (WORD+WORD) */
+#define IDT_SW_NTP12_PCIECMDSTS                0x19004U
+#define IDT_SW_NTP12_PCIELCTLSTS       0x19050U
+/* NT-function control register                (DWORD) */
+#define IDT_SW_NTP12_NTCTL             0x19400U
+/* BAR setup/limit/base address registers (DWORD) */
+#define IDT_SW_NTP12_BARSETUP0         0x19470U
+#define IDT_SW_NTP12_BARLIMIT0         0x19474U
+#define IDT_SW_NTP12_BARLTBASE0                0x19478U
+#define IDT_SW_NTP12_BARUTBASE0                0x1947CU
+#define IDT_SW_NTP12_BARSETUP1         0x19480U
+#define IDT_SW_NTP12_BARLIMIT1         0x19484U
+#define IDT_SW_NTP12_BARLTBASE1                0x19488U
+#define IDT_SW_NTP12_BARUTBASE1                0x1948CU
+#define IDT_SW_NTP12_BARSETUP2         0x19490U
+#define IDT_SW_NTP12_BARLIMIT2         0x19494U
+#define IDT_SW_NTP12_BARLTBASE2                0x19498U
+#define IDT_SW_NTP12_BARUTBASE2                0x1949CU
+#define IDT_SW_NTP12_BARSETUP3         0x194A0U
+#define IDT_SW_NTP12_BARLIMIT3         0x194A4U
+#define IDT_SW_NTP12_BARLTBASE3                0x194A8U
+#define IDT_SW_NTP12_BARUTBASE3                0x194ACU
+#define IDT_SW_NTP12_BARSETUP4         0x194B0U
+#define IDT_SW_NTP12_BARLIMIT4         0x194B4U
+#define IDT_SW_NTP12_BARLTBASE4                0x194B8U
+#define IDT_SW_NTP12_BARUTBASE4                0x194BCU
+#define IDT_SW_NTP12_BARSETUP5         0x194C0U
+#define IDT_SW_NTP12_BARLIMIT5         0x194C4U
+#define IDT_SW_NTP12_BARLTBASE5                0x194C8U
+#define IDT_SW_NTP12_BARUTBASE5                0x194CCU
+/* PCI Express command/status and link control/status registers (WORD+WORD) */
+#define IDT_SW_NTP16_PCIECMDSTS                0x21004U
+#define IDT_SW_NTP16_PCIELCTLSTS       0x21050U
+/* NT-function control register                (DWORD) */
+#define IDT_SW_NTP16_NTCTL             0x21400U
+/* BAR setup/limit/base address registers (DWORD) */
+#define IDT_SW_NTP16_BARSETUP0         0x21470U
+#define IDT_SW_NTP16_BARLIMIT0         0x21474U
+#define IDT_SW_NTP16_BARLTBASE0                0x21478U
+#define IDT_SW_NTP16_BARUTBASE0                0x2147CU
+#define IDT_SW_NTP16_BARSETUP1         0x21480U
+#define IDT_SW_NTP16_BARLIMIT1         0x21484U
+#define IDT_SW_NTP16_BARLTBASE1                0x21488U
+#define IDT_SW_NTP16_BARUTBASE1                0x2148CU
+#define IDT_SW_NTP16_BARSETUP2         0x21490U
+#define IDT_SW_NTP16_BARLIMIT2         0x21494U
+#define IDT_SW_NTP16_BARLTBASE2                0x21498U
+#define IDT_SW_NTP16_BARUTBASE2                0x2149CU
+#define IDT_SW_NTP16_BARSETUP3         0x214A0U
+#define IDT_SW_NTP16_BARLIMIT3         0x214A4U
+#define IDT_SW_NTP16_BARLTBASE3                0x214A8U
+#define IDT_SW_NTP16_BARUTBASE3                0x214ACU
+#define IDT_SW_NTP16_BARSETUP4         0x214B0U
+#define IDT_SW_NTP16_BARLIMIT4         0x214B4U
+#define IDT_SW_NTP16_BARLTBASE4                0x214B8U
+#define IDT_SW_NTP16_BARUTBASE4                0x214BCU
+#define IDT_SW_NTP16_BARSETUP5         0x214C0U
+#define IDT_SW_NTP16_BARLIMIT5         0x214C4U
+#define IDT_SW_NTP16_BARLTBASE5                0x214C8U
+#define IDT_SW_NTP16_BARUTBASE5                0x214CCU
+/* PCI Express command/status and link control/status registers (WORD+WORD) */
+#define IDT_SW_NTP20_PCIECMDSTS                0x29004U
+#define IDT_SW_NTP20_PCIELCTLSTS       0x29050U
+/* NT-function control register                (DWORD) */
+#define IDT_SW_NTP20_NTCTL             0x29400U
+/* BAR setup/limit/base address registers (DWORD) */
+#define IDT_SW_NTP20_BARSETUP0         0x29470U
+#define IDT_SW_NTP20_BARLIMIT0         0x29474U
+#define IDT_SW_NTP20_BARLTBASE0                0x29478U
+#define IDT_SW_NTP20_BARUTBASE0                0x2947CU
+#define IDT_SW_NTP20_BARSETUP1         0x29480U
+#define IDT_SW_NTP20_BARLIMIT1         0x29484U
+#define IDT_SW_NTP20_BARLTBASE1                0x29488U
+#define IDT_SW_NTP20_BARUTBASE1                0x2948CU
+#define IDT_SW_NTP20_BARSETUP2         0x29490U
+#define IDT_SW_NTP20_BARLIMIT2         0x29494U
+#define IDT_SW_NTP20_BARLTBASE2                0x29498U
+#define IDT_SW_NTP20_BARUTBASE2                0x2949CU
+#define IDT_SW_NTP20_BARSETUP3         0x294A0U
+#define IDT_SW_NTP20_BARLIMIT3         0x294A4U
+#define IDT_SW_NTP20_BARLTBASE3                0x294A8U
+#define IDT_SW_NTP20_BARUTBASE3                0x294ACU
+#define IDT_SW_NTP20_BARSETUP4         0x294B0U
+#define IDT_SW_NTP20_BARLIMIT4         0x294B4U
+#define IDT_SW_NTP20_BARLTBASE4                0x294B8U
+#define IDT_SW_NTP20_BARUTBASE4                0x294BCU
+#define IDT_SW_NTP20_BARSETUP5         0x294C0U
+#define IDT_SW_NTP20_BARLIMIT5         0x294C4U
+#define IDT_SW_NTP20_BARLTBASE5                0x294C8U
+#define IDT_SW_NTP20_BARUTBASE5                0x294CCU
+/* IDT PCIe-switch control register    (DWORD) */
+#define IDT_SW_CTL                     0x3E000U
+/* Boot Configuration Vector Status    (DWORD) */
+#define IDT_SW_BCVSTS                  0x3E004U
+/* Port Clocking Mode                  (DWORD) */
+#define IDT_SW_PCLKMODE                        0x3E008U
+/* Reset Drain Delay                   (DWORD) */
+#define IDT_SW_RDRAINDELAY             0x3E080U
+/* Port Operating Mode Change Drain Delay (DWORD) */
+#define IDT_SW_POMCDELAY               0x3E084U
+/* Side Effect Delay                   (DWORD) */
+#define IDT_SW_SEDELAY                 0x3E088U
+/* Upstream Secondary Bus Reset Delay  (DWORD) */
+#define IDT_SW_SSBRDELAY               0x3E08CU
+/* Switch partition N Control/Status/Failover registers */
+#define IDT_SW_SWPART0CTL              0x3E100U
+#define IDT_SW_SWPART0STS              0x3E104U
+#define IDT_SW_SWPART0FCTL             0x3E108U
+#define IDT_SW_SWPART1CTL              0x3E120U
+#define IDT_SW_SWPART1STS              0x3E124U
+#define IDT_SW_SWPART1FCTL             0x3E128U
+#define IDT_SW_SWPART2CTL              0x3E140U
+#define IDT_SW_SWPART2STS              0x3E144U
+#define IDT_SW_SWPART2FCTL             0x3E148U
+#define IDT_SW_SWPART3CTL              0x3E160U
+#define IDT_SW_SWPART3STS              0x3E164U
+#define IDT_SW_SWPART3FCTL             0x3E168U
+#define IDT_SW_SWPART4CTL              0x3E180U
+#define IDT_SW_SWPART4STS              0x3E184U
+#define IDT_SW_SWPART4FCTL             0x3E188U
+#define IDT_SW_SWPART5CTL              0x3E1A0U
+#define IDT_SW_SWPART5STS              0x3E1A4U
+#define IDT_SW_SWPART5FCTL             0x3E1A8U
+#define IDT_SW_SWPART6CTL              0x3E1C0U
+#define IDT_SW_SWPART6STS              0x3E1C4U
+#define IDT_SW_SWPART6FCTL             0x3E1C8U
+#define IDT_SW_SWPART7CTL              0x3E1E0U
+#define IDT_SW_SWPART7STS              0x3E1E4U
+#define IDT_SW_SWPART7FCTL             0x3E1E8U
+/* Switch port N control and status registers */
+#define IDT_SW_SWPORT0CTL              0x3E200U
+#define IDT_SW_SWPORT0STS              0x3E204U
+#define IDT_SW_SWPORT0FCTL             0x3E208U
+#define IDT_SW_SWPORT2CTL              0x3E240U
+#define IDT_SW_SWPORT2STS              0x3E244U
+#define IDT_SW_SWPORT2FCTL             0x3E248U
+#define IDT_SW_SWPORT4CTL              0x3E280U
+#define IDT_SW_SWPORT4STS              0x3E284U
+#define IDT_SW_SWPORT4FCTL             0x3E288U
+#define IDT_SW_SWPORT6CTL              0x3E2C0U
+#define IDT_SW_SWPORT6STS              0x3E2C4U
+#define IDT_SW_SWPORT6FCTL             0x3E2C8U
+#define IDT_SW_SWPORT8CTL              0x3E300U
+#define IDT_SW_SWPORT8STS              0x3E304U
+#define IDT_SW_SWPORT8FCTL             0x3E308U
+#define IDT_SW_SWPORT12CTL             0x3E380U
+#define IDT_SW_SWPORT12STS             0x3E384U
+#define IDT_SW_SWPORT12FCTL            0x3E388U
+#define IDT_SW_SWPORT16CTL             0x3E400U
+#define IDT_SW_SWPORT16STS             0x3E404U
+#define IDT_SW_SWPORT16FCTL            0x3E408U
+#define IDT_SW_SWPORT20CTL             0x3E480U
+#define IDT_SW_SWPORT20STS             0x3E484U
+#define IDT_SW_SWPORT20FCTL            0x3E488U
+/* Switch Event registers */
+/* Switch Event Status/Mask/Partition mask (DWORD) */
+#define IDT_SW_SESTS                   0x3EC00U
+#define IDT_SW_SEMSK                   0x3EC04U
+#define IDT_SW_SEPMSK                  0x3EC08U
+/* Switch Event Link Up/Down Status/Mask (DWORD) */
+#define IDT_SW_SELINKUPSTS             0x3EC0CU
+#define IDT_SW_SELINKUPMSK             0x3EC10U
+#define IDT_SW_SELINKDNSTS             0x3EC14U
+#define IDT_SW_SELINKDNMSK             0x3EC18U
+/* Switch Event Fundamental Reset Status/Mask (DWORD) */
+#define IDT_SW_SEFRSTSTS               0x3EC1CU
+#define IDT_SW_SEFRSTMSK               0x3EC20U
+/* Switch Event Hot Reset Status/Mask  (DWORD) */
+#define IDT_SW_SEHRSTSTS               0x3EC24U
+#define IDT_SW_SEHRSTMSK               0x3EC28U
+/* Switch Event Failover Mask          (DWORD) */
+#define IDT_SW_SEFOVRMSK               0x3EC2CU
+/* Switch Event Global Signal Status/Mask (DWORD) */
+#define IDT_SW_SEGSIGSTS               0x3EC30U
+#define IDT_SW_SEGSIGMSK               0x3EC34U
+/* NT Global Doorbell Status           (DWORD) */
+#define IDT_SW_GDBELLSTS               0x3EC3CU
+/* Switch partition N message M control (msgs routing table) (DWORD) */
+#define IDT_SW_SWP0MSGCTL0             0x3EE00U
+#define IDT_SW_SWP1MSGCTL0             0x3EE04U
+#define IDT_SW_SWP2MSGCTL0             0x3EE08U
+#define IDT_SW_SWP3MSGCTL0             0x3EE0CU
+#define IDT_SW_SWP4MSGCTL0             0x3EE10U
+#define IDT_SW_SWP5MSGCTL0             0x3EE14U
+#define IDT_SW_SWP6MSGCTL0             0x3EE18U
+#define IDT_SW_SWP7MSGCTL0             0x3EE1CU
+#define IDT_SW_SWP0MSGCTL1             0x3EE20U
+#define IDT_SW_SWP1MSGCTL1             0x3EE24U
+#define IDT_SW_SWP2MSGCTL1             0x3EE28U
+#define IDT_SW_SWP3MSGCTL1             0x3EE2CU
+#define IDT_SW_SWP4MSGCTL1             0x3EE30U
+#define IDT_SW_SWP5MSGCTL1             0x3EE34U
+#define IDT_SW_SWP6MSGCTL1             0x3EE38U
+#define IDT_SW_SWP7MSGCTL1             0x3EE3CU
+#define IDT_SW_SWP0MSGCTL2             0x3EE40U
+#define IDT_SW_SWP1MSGCTL2             0x3EE44U
+#define IDT_SW_SWP2MSGCTL2             0x3EE48U
+#define IDT_SW_SWP3MSGCTL2             0x3EE4CU
+#define IDT_SW_SWP4MSGCTL2             0x3EE50U
+#define IDT_SW_SWP5MSGCTL2             0x3EE54U
+#define IDT_SW_SWP6MSGCTL2             0x3EE58U
+#define IDT_SW_SWP7MSGCTL2             0x3EE5CU
+#define IDT_SW_SWP0MSGCTL3             0x3EE60U
+#define IDT_SW_SWP1MSGCTL3             0x3EE64U
+#define IDT_SW_SWP2MSGCTL3             0x3EE68U
+#define IDT_SW_SWP3MSGCTL3             0x3EE6CU
+#define IDT_SW_SWP4MSGCTL3             0x3EE70U
+#define IDT_SW_SWP5MSGCTL3             0x3EE74U
+#define IDT_SW_SWP6MSGCTL3             0x3EE78U
+#define IDT_SW_SWP7MSGCTL3             0x3EE7CU
+/* SMBus Status and Control registers  (DWORD) */
+#define IDT_SW_SMBUSSTS                        0x3F188U
+#define IDT_SW_SMBUSCTL                        0x3F18CU
+/* Serial EEPROM Interface             (DWORD) */
+#define IDT_SW_EEPROMINTF              0x3F190U
+/* MBus I/O Expander Address N         (DWORD) */
+#define IDT_SW_IOEXPADDR0              0x3F198U
+#define IDT_SW_IOEXPADDR1              0x3F19CU
+#define IDT_SW_IOEXPADDR2              0x3F1A0U
+#define IDT_SW_IOEXPADDR3              0x3F1A4U
+#define IDT_SW_IOEXPADDR4              0x3F1A8U
+#define IDT_SW_IOEXPADDR5              0x3F1ACU
+/* General Purpose Events Control and Status registers (DWORD) */
+#define IDT_SW_GPECTL                  0x3F1B0U
+#define IDT_SW_GPESTS                  0x3F1B4U
+/* Temperature sensor Control/Status/Alarm/Adjustment/Slope registers */
+#define IDT_SW_TMPCTL                  0x3F1D4U
+#define IDT_SW_TMPSTS                  0x3F1D8U
+#define IDT_SW_TMPALARM                        0x3F1DCU
+#define IDT_SW_TMPADJ                  0x3F1E0U
+#define IDT_SW_TSSLOPE                 0x3F1E4U
+/* SMBus Configuration Block header log        (DWORD) */
+#define IDT_SW_SMBUSCBHL               0x3F1E8U
+
+/*
+ * Common registers related constants
+ * @IDT_REG_ALIGN:     Registers alignment used in the driver
+ * @IDT_REG_PCI_MAX:   Maximum PCI configuration space register value
+ * @IDT_REG_SW_MAX:    Maximum global register value
+ */
+#define IDT_REG_ALIGN                  4
+#define IDT_REG_PCI_MAX                        0x00FFFU
+#define IDT_REG_SW_MAX                 0x3FFFFU
+
+/*
+ * PCICMDSTS register fields related constants
+ * @IDT_PCICMDSTS_IOAE:        I/O access enable
+ * @IDT_PCICMDSTS_MAE: Memory access enable
+ * @IDT_PCICMDSTS_BME: Bus master enable
+ */
+#define IDT_PCICMDSTS_IOAE             0x00000001U
+#define IDT_PCICMDSTS_MAE              0x00000002U
+#define IDT_PCICMDSTS_BME              0x00000004U
+
+/*
+ * PCIEDCAP register fields related constants
+ * @IDT_PCIEDCAP_MPAYLOAD_MASK:         Maximum payload size mask
+ * @IDT_PCIEDCAP_MPAYLOAD_FLD:  Maximum payload size field offset
+ * @IDT_PCIEDCAP_MPAYLOAD_S128:         Max supported payload size of 128 bytes
+ * @IDT_PCIEDCAP_MPAYLOAD_S256:         Max supported payload size of 256 bytes
+ * @IDT_PCIEDCAP_MPAYLOAD_S512:         Max supported payload size of 512 bytes
+ * @IDT_PCIEDCAP_MPAYLOAD_S1024: Max supported payload size of 1024 bytes
+ * @IDT_PCIEDCAP_MPAYLOAD_S2048: Max supported payload size of 2048 bytes
+ */
+#define IDT_PCIEDCAP_MPAYLOAD_MASK     0x00000007U
+#define IDT_PCIEDCAP_MPAYLOAD_FLD      0
+#define IDT_PCIEDCAP_MPAYLOAD_S128     0x00000000U
+#define IDT_PCIEDCAP_MPAYLOAD_S256     0x00000001U
+#define IDT_PCIEDCAP_MPAYLOAD_S512     0x00000002U
+#define IDT_PCIEDCAP_MPAYLOAD_S1024    0x00000003U
+#define IDT_PCIEDCAP_MPAYLOAD_S2048    0x00000004U
+
+/*
+ * PCIEDCTLSTS registers fields related constants
+ * @IDT_PCIEDCTL_MPS_MASK:     Maximum payload size mask
+ * @IDT_PCIEDCTL_MPS_FLD:      MPS field offset
+ * @IDT_PCIEDCTL_MPS_S128:     Max payload size of 128 bytes
+ * @IDT_PCIEDCTL_MPS_S256:     Max payload size of 256 bytes
+ * @IDT_PCIEDCTL_MPS_S512:     Max payload size of 512 bytes
+ * @IDT_PCIEDCTL_MPS_S1024:    Max payload size of 1024 bytes
+ * @IDT_PCIEDCTL_MPS_S2048:    Max payload size of 2048 bytes
+ * @IDT_PCIEDCTL_MPS_S4096:    Max payload size of 4096 bytes
+ */
+#define IDT_PCIEDCTLSTS_MPS_MASK       0x000000E0U
+#define IDT_PCIEDCTLSTS_MPS_FLD                5
+#define IDT_PCIEDCTLSTS_MPS_S128       0x00000000U
+#define IDT_PCIEDCTLSTS_MPS_S256       0x00000020U
+#define IDT_PCIEDCTLSTS_MPS_S512       0x00000040U
+#define IDT_PCIEDCTLSTS_MPS_S1024      0x00000060U
+#define IDT_PCIEDCTLSTS_MPS_S2048      0x00000080U
+#define IDT_PCIEDCTLSTS_MPS_S4096      0x000000A0U
+
+/*
+ * PCIELCAP register fields related constants
+ * @IDT_PCIELCAP_PORTNUM_MASK: Port number field mask
+ * @IDT_PCIELCAP_PORTNUM_FLD:  Port number field offset
+ */
+#define IDT_PCIELCAP_PORTNUM_MASK      0xFF000000U
+#define IDT_PCIELCAP_PORTNUM_FLD       24
+
+/*
+ * PCIELCTLSTS registers fields related constants
+ * @IDT_PCIELSTS_CLS_MASK:     Current link speed mask
+ * @IDT_PCIELSTS_CLS_FLD:      Current link speed field offset
+ * @IDT_PCIELSTS_NLW_MASK:     Negotiated link width mask
+ * @IDT_PCIELSTS_NLW_FLD:      Negotiated link width field offset
+ * @IDT_PCIELSTS_SCLK_COM:     Common slot clock configuration
+ */
+#define IDT_PCIELCTLSTS_CLS_MASK       0x000F0000U
+#define IDT_PCIELCTLSTS_CLS_FLD                16
+#define IDT_PCIELCTLSTS_NLW_MASK       0x03F00000U
+#define IDT_PCIELCTLSTS_NLW_FLD                20
+#define IDT_PCIELCTLSTS_SCLK_COM       0x10000000U
+
+/*
+ * NTCTL register fields related constants
+ * @IDT_NTCTL_IDPROTDIS:       ID Protection check disable (disable MTBL)
+ * @IDT_NTCTL_CPEN:            Completion enable
+ * @IDT_NTCTL_RNS:             Request no snoop processing (if MTBL disabled)
+ * @IDT_NTCTL_ATP:             Address type processing (if MTBL disabled)
+ */
+#define IDT_NTCTL_IDPROTDIS            0x00000001U
+#define IDT_NTCTL_CPEN                 0x00000002U
+#define IDT_NTCTL_RNS                  0x00000004U
+#define IDT_NTCTL_ATP                  0x00000008U
+
+/*
+ * NTINTSTS register fields related constants
+ * @IDT_NTINTSTS_MSG:          Message interrupt bit
+ * @IDT_NTINTSTS_DBELL:                Doorbell interrupt bit
+ * @IDT_NTINTSTS_SEVENT:       Switch Event interrupt bit
+ * @IDT_NTINTSTS_TMPSENSOR:    Temperature sensor interrupt bit
+ */
+#define IDT_NTINTSTS_MSG               0x00000001U
+#define IDT_NTINTSTS_DBELL             0x00000002U
+#define IDT_NTINTSTS_SEVENT            0x00000008U
+#define IDT_NTINTSTS_TMPSENSOR         0x00000080U
+
+/*
+ * NTINTMSK register fields related constants
+ * @IDT_NTINTMSK_MSG:          Message interrupt mask bit
+ * @IDT_NTINTMSK_DBELL:                Doorbell interrupt mask bit
+ * @IDT_NTINTMSK_SEVENT:       Switch Event interrupt mask bit
+ * @IDT_NTINTMSK_TMPSENSOR:    Temperature sensor interrupt mask bit
+ * @IDT_NTINTMSK_ALL:          All the useful interrupts mask
+ */
+#define IDT_NTINTMSK_MSG               0x00000001U
+#define IDT_NTINTMSK_DBELL             0x00000002U
+#define IDT_NTINTMSK_SEVENT            0x00000008U
+#define IDT_NTINTMSK_TMPSENSOR         0x00000080U
+#define IDT_NTINTMSK_ALL \
+       (IDT_NTINTMSK_MSG | IDT_NTINTMSK_DBELL | \
+        IDT_NTINTMSK_SEVENT | IDT_NTINTMSK_TMPSENSOR)
+
+/*
+ * NTGSIGNAL register fields related constants
+ * @IDT_NTGSIGNAL_SET: Set global signal of the local partition
+ */
+#define IDT_NTGSIGNAL_SET              0x00000001U
+
+/*
+ * BARSETUP register fields related constants
+ * @IDT_BARSETUP_TYPE_MASK:    Mask of the TYPE field
+ * @IDT_BARSETUP_TYPE_32:      32-bit addressing BAR
+ * @IDT_BARSETUP_TYPE_64:      64-bit addressing BAR
+ * @IDT_BARSETUP_PREF:         Value of the BAR prefetchable field
+ * @IDT_BARSETUP_SIZE_MASK:    Mask of the SIZE field
+ * @IDT_BARSETUP_SIZE_FLD:     SIZE field offset
+ * @IDT_BARSETUP_SIZE_CFG:     SIZE field value in case of config space MODE
+ * @IDT_BARSETUP_MODE_CFG:     Configuration space BAR mode
+ * @IDT_BARSETUP_ATRAN_MASK:   ATRAN field mask
+ * @IDT_BARSETUP_ATRAN_FLD:    ATRAN field offset
+ * @IDT_BARSETUP_ATRAN_DIR:    Direct address translation memory window
+ * @IDT_BARSETUP_ATRAN_LUT12:  12-entry lookup table
+ * @IDT_BARSETUP_ATRAN_LUT24:  24-entry lookup table
+ * @IDT_BARSETUP_TPART_MASK:   TPART field mask
+ * @IDT_BARSETUP_TPART_FLD:    TPART field offset
+ * @IDT_BARSETUP_EN:           BAR enable bit
+ */
+#define IDT_BARSETUP_TYPE_MASK         0x00000006U
+#define IDT_BARSETUP_TYPE_FLD          0
+#define IDT_BARSETUP_TYPE_32           0x00000000U
+#define IDT_BARSETUP_TYPE_64           0x00000004U
+#define IDT_BARSETUP_PREF              0x00000008U
+#define IDT_BARSETUP_SIZE_MASK         0x000003F0U
+#define IDT_BARSETUP_SIZE_FLD          4
+#define IDT_BARSETUP_SIZE_CFG          0x000000C0U
+#define IDT_BARSETUP_MODE_CFG          0x00000400U
+#define IDT_BARSETUP_ATRAN_MASK                0x00001800U
+#define IDT_BARSETUP_ATRAN_FLD         11
+#define IDT_BARSETUP_ATRAN_DIR         0x00000000U
+#define IDT_BARSETUP_ATRAN_LUT12       0x00000800U
+#define IDT_BARSETUP_ATRAN_LUT24       0x00001000U
+#define IDT_BARSETUP_TPART_MASK                0x0000E000U
+#define IDT_BARSETUP_TPART_FLD         13
+#define IDT_BARSETUP_EN                        0x80000000U
+
+/*
+ * NTMTBLDATA register fields related constants
+ * @IDT_NTMTBLDATA_VALID:      Set the MTBL entry being valid
+ * @IDT_NTMTBLDATA_REQID_MASK: Bus:Device:Function field mask
+ * @IDT_NTMTBLDATA_REQID_FLD:  Bus:Device:Function field offset
+ * @IDT_NTMTBLDATA_PART_MASK:  Partition field mask
+ * @IDT_NTMTBLDATA_PART_FLD:   Partition field offset
+ * @IDT_NTMTBLDATA_ATP_TRANS:  Enable AT field translation on request TLPs
+ * @IDT_NTMTBLDATA_CNS_INV:    Enable No Snoop attribute inversion of
+ *                             Completion TLPs
+ * @IDT_NTMTBLDATA_RNS_INV:    Enable No Snoop attribute inversion of
+ *                             Request TLPs
+ */
+#define IDT_NTMTBLDATA_VALID           0x00000001U
+#define IDT_NTMTBLDATA_REQID_MASK      0x0001FFFEU
+#define IDT_NTMTBLDATA_REQID_FLD       1
+#define IDT_NTMTBLDATA_PART_MASK       0x000E0000U
+#define IDT_NTMTBLDATA_PART_FLD                17
+#define IDT_NTMTBLDATA_ATP_TRANS       0x20000000U
+#define IDT_NTMTBLDATA_CNS_INV         0x40000000U
+#define IDT_NTMTBLDATA_RNS_INV         0x80000000U
+
+/*
+ * REQIDCAP register fields related constants
+ * @IDT_REQIDCAP_REQID_MASK:   Request ID field mask
+ * @IDT_REQIDCAP_REQID_FLD:    Request ID field offset
+ */
+#define IDT_REQIDCAP_REQID_MASK                0x0000FFFFU
+#define IDT_REQIDCAP_REQID_FLD         0
+
+/*
+ * LUTOFFSET register fields related constants
+ * @IDT_LUTOFFSET_INDEX_MASK:  Lookup table index field mask
+ * @IDT_LUTOFFSET_INDEX_FLD:   Lookup table index field offset
+ * @IDT_LUTOFFSET_BAR_MASK:    Lookup table BAR select field mask
+ * @IDT_LUTOFFSET_BAR_FLD:     Lookup table BAR select field offset
+ */
+#define IDT_LUTOFFSET_INDEX_MASK       0x0000001FU
+#define IDT_LUTOFFSET_INDEX_FLD                0
+#define IDT_LUTOFFSET_BAR_MASK         0x00000700U
+#define IDT_LUTOFFSET_BAR_FLD          8
+
+/*
+ * LUTUDATA register fields related constants
+ * @IDT_LUTUDATA_PART_MASK:    Partition field mask
+ * @IDT_LUTUDATA_PART_FLD:     Partition field offset
+ * @IDT_LUTUDATA_VALID:                Lookup table entry valid bit
+ */
+#define IDT_LUTUDATA_PART_MASK         0x0000000FU
+#define IDT_LUTUDATA_PART_FLD          0
+#define IDT_LUTUDATA_VALID             0x80000000U
+
+/*
+ * SWPARTxSTS register fields related constants
+ * @IDT_SWPARTxSTS_SCI:                Switch partition state change initiated
+ * @IDT_SWPARTxSTS_SCC:                Switch partition state change completed
+ * @IDT_SWPARTxSTS_STATE_MASK: Switch partition state mask
+ * @IDT_SWPARTxSTS_STATE_FLD:  Switch partition state field offset
+ * @IDT_SWPARTxSTS_STATE_DIS:  Switch partition disabled
+ * @IDT_SWPARTxSTS_STATE_ACT:  Switch partition enabled
+ * @IDT_SWPARTxSTS_STATE_RES:  Switch partition in reset
+ * @IDT_SWPARTxSTS_US:         Switch partition has upstream port
+ * @IDT_SWPARTxSTS_USID_MASK:  Switch partition upstream port ID mask
+ * @IDT_SWPARTxSTS_USID_FLD:   Switch partition upstream port ID field offset
+ * @IDT_SWPARTxSTS_NT:         Upstream port has NT function
+ * @IDT_SWPARTxSTS_DMA:                Upstream port has DMA function
+ */
+#define IDT_SWPARTxSTS_SCI             0x00000001U
+#define IDT_SWPARTxSTS_SCC             0x00000002U
+#define IDT_SWPARTxSTS_STATE_MASK      0x00000060U
+#define IDT_SWPARTxSTS_STATE_FLD       5
+#define IDT_SWPARTxSTS_STATE_DIS       0x00000000U
+#define IDT_SWPARTxSTS_STATE_ACT       0x00000020U
+#define IDT_SWPARTxSTS_STATE_RES       0x00000060U
+#define IDT_SWPARTxSTS_US              0x00000100U
+#define IDT_SWPARTxSTS_USID_MASK       0x00003E00U
+#define IDT_SWPARTxSTS_USID_FLD                9
+#define IDT_SWPARTxSTS_NT              0x00004000U
+#define IDT_SWPARTxSTS_DMA             0x00008000U
+
+/*
+ * SWPORTxSTS register fields related constants
+ * @IDT_SWPORTxSTS_OMCI:       Operation mode change initiated
+ * @IDT_SWPORTxSTS_OMCC:       Operation mode change completed
+ * @IDT_SWPORTxSTS_LINKUP:     Link up status
+ * @IDT_SWPORTxSTS_DS:         Port lanes behave as downstream lanes
+ * @IDT_SWPORTxSTS_MODE_MASK:  Port mode field mask
+ * @IDT_SWPORTxSTS_MODE_FLD:   Port mode field offset
+ * @IDT_SWPORTxSTS_MODE_DIS:   Port mode - disabled
+ * @IDT_SWPORTxSTS_MODE_DS:    Port mode - downstream switch port
+ * @IDT_SWPORTxSTS_MODE_US:    Port mode - upstream switch port
+ * @IDT_SWPORTxSTS_MODE_NT:    Port mode - NT function
+ * @IDT_SWPORTxSTS_MODE_USNT:  Port mode - upstream switch port with NTB
+ * @IDT_SWPORTxSTS_MODE_UNAT:  Port mode - unattached
+ * @IDT_SWPORTxSTS_MODE_USDMA: Port mode - upstream switch port with DMA
+ * @IDT_SWPORTxSTS_MODE_USNTDMA:Port mode - upstream port with NTB and DMA
+ * @IDT_SWPORTxSTS_MODE_NTDMA: Port mode - NT function with DMA
+ * @IDT_SWPORTxSTS_SWPART_MASK:        Port partition field mask
+ * @IDT_SWPORTxSTS_SWPART_FLD: Port partition field offset
+ * @IDT_SWPORTxSTS_DEVNUM_MASK:        Port device number field mask
+ * @IDT_SWPORTxSTS_DEVNUM_FLD: Port device number field offset
+ */
+#define IDT_SWPORTxSTS_OMCI            0x00000001U
+#define IDT_SWPORTxSTS_OMCC            0x00000002U
+#define IDT_SWPORTxSTS_LINKUP          0x00000010U
+#define IDT_SWPORTxSTS_DS              0x00000020U
+#define IDT_SWPORTxSTS_MODE_MASK       0x000003C0U
+#define IDT_SWPORTxSTS_MODE_FLD                6
+#define IDT_SWPORTxSTS_MODE_DIS                0x00000000U
+#define IDT_SWPORTxSTS_MODE_DS         0x00000040U
+#define IDT_SWPORTxSTS_MODE_US         0x00000080U
+#define IDT_SWPORTxSTS_MODE_NT         0x000000C0U
+#define IDT_SWPORTxSTS_MODE_USNT       0x00000100U
+#define IDT_SWPORTxSTS_MODE_UNAT       0x00000140U
+#define IDT_SWPORTxSTS_MODE_USDMA      0x00000180U
+#define IDT_SWPORTxSTS_MODE_USNTDMA    0x000001C0U
+#define IDT_SWPORTxSTS_MODE_NTDMA      0x00000200U
+#define IDT_SWPORTxSTS_SWPART_MASK     0x00001C00U
+#define IDT_SWPORTxSTS_SWPART_FLD      10
+#define IDT_SWPORTxSTS_DEVNUM_MASK     0x001F0000U
+#define IDT_SWPORTxSTS_DEVNUM_FLD      16
+
+/*
+ * SEMSK register fields related constants
+ * @IDT_SEMSK_LINKUP:  Link Up event mask bit
+ * @IDT_SEMSK_LINKDN:  Link Down event mask bit
+ * @IDT_SEMSK_GSIGNAL: Global Signal event mask bit
+ */
+#define IDT_SEMSK_LINKUP               0x00000001U
+#define IDT_SEMSK_LINKDN               0x00000002U
+#define IDT_SEMSK_GSIGNAL              0x00000020U
+
+/*
+ * SWPxMSGCTL register fields related constants
+ * @IDT_SWPxMSGCTL_REG_MASK:   Register select field mask
+ * @IDT_SWPxMSGCTL_REG_FLD:    Register select field offset
+ * @IDT_SWPxMSGCTL_PART_MASK:  Partition select field mask
+ * @IDT_SWPxMSGCTL_PART_FLD:   Partition select field offset
+ */
+#define IDT_SWPxMSGCTL_REG_MASK                0x00000003U
+#define IDT_SWPxMSGCTL_REG_FLD         0
+#define IDT_SWPxMSGCTL_PART_MASK       0x00000070U
+#define IDT_SWPxMSGCTL_PART_FLD                4
+
+/*
+ * TMPSTS register fields related constants
+ * @IDT_TMPSTS_TEMP_MASK:      Current temperature field mask
+ * @IDT_TMPSTS_TEMP_FLD:       Current temperature field offset
+ */
+#define IDT_TMPSTS_TEMP_MASK           0x000000FFU
+#define IDT_TMPSTS_TEMP_FLD            0
+
+/*
+ * Helper macro to get/set the corresponding field value
+ * @GET_FIELD:         Retrieve the value of the corresponding field
+ * @SET_FIELD:         Set the specified field up
+ * @IS_FLD_SET:                Check whether a field is set with value
+ */
+#define GET_FIELD(field, data) \
+       (((u32)(data) & IDT_ ##field## _MASK) >> IDT_ ##field## _FLD)
+#define SET_FIELD(field, data, value) \
+       (((u32)(data) & ~IDT_ ##field## _MASK) | \
+        ((u32)(value) << IDT_ ##field## _FLD))
+#define IS_FLD_SET(field, data, value) \
+       (((u32)(data) & IDT_ ##field## _MASK) == IDT_ ##field## _ ##value)
+
+/*
+ * Useful registers masks:
+ * @IDT_DBELL_MASK:    Doorbell bits mask
+ * @IDT_OUTMSG_MASK:   Out messages status bits mask
+ * @IDT_INMSG_MASK:    In messages status bits mask
+ * @IDT_MSG_MASK:      Any message status bits mask
+ */
+#define IDT_DBELL_MASK         ((u32)0xFFFFFFFFU)
+#define IDT_OUTMSG_MASK                ((u32)0x0000000FU)
+#define IDT_INMSG_MASK         ((u32)0x000F0000U)
+#define IDT_MSG_MASK           (IDT_INMSG_MASK | IDT_OUTMSG_MASK)
+
+/*
+ * Number of IDT NTB resources:
+ * @IDT_MSG_CNT:       Number of Message registers
+ * @IDT_BAR_CNT:       Number of BARs of each port
+ * @IDT_MTBL_ENTRY_CNT:        Number mapping table entries
+ */
+#define IDT_MSG_CNT            4
+#define IDT_BAR_CNT            6
+#define IDT_MTBL_ENTRY_CNT     64
+
+/*
+ * General IDT PCIe-switch constant
+ * @IDT_MAX_NR_PORTS:  Maximum number of ports per IDT PCIe-switch
+ * @IDT_MAX_NR_PARTS:  Maximum number of partitions per IDT PCIe-switch
+ * @IDT_MAX_NR_PEERS:  Maximum number of NT-peers per IDT PCIe-switch
+ * @IDT_MAX_NR_MWS:    Maximum number of Memory Widows
+ * @IDT_PCIE_REGSIZE:  Size of the registers in bytes
+ * @IDT_TRANS_ALIGN:   Alignment of translated base address
+ * @IDT_DIR_SIZE_ALIGN:        Alignment of size setting for direct translated MWs.
+ *                     Even though the lower 10 bits are reserved, they are
+ *                     treated by IDT as one's so basically there is no any
+ *                     alignment of size limit for DIR address translation.
+ */
+#define IDT_MAX_NR_PORTS       24
+#define IDT_MAX_NR_PARTS       8
+#define IDT_MAX_NR_PEERS       8
+#define IDT_MAX_NR_MWS         29
+#define IDT_PCIE_REGSIZE       4
+#define IDT_TRANS_ALIGN                4
+#define IDT_DIR_SIZE_ALIGN     1
+
+/*
+ * IDT Memory Windows type. Depending on the device settings, IDT supports
+ * Direct Address Translation MW registers and Lookup Table registers
+ * @IDT_MW_DIR:                Direct address translation
+ * @IDT_MW_LUT12:      12-entry lookup table entry
+ * @IDT_MW_LUT24:      24-entry lookup table entry
+ *
+ * NOTE These values are exactly the same as one of the BARSETUP ATRAN field
+ */
+enum idt_mw_type {
+       IDT_MW_DIR = 0x0,
+       IDT_MW_LUT12 = 0x1,
+       IDT_MW_LUT24 = 0x2
+};
+
+/*
+ * IDT PCIe-switch model private data
+ * @name:      Device name
+ * @port_cnt:  Total number of NT endpoint ports
+ * @ports:     Port ids
+ */
+struct idt_89hpes_cfg {
+       char *name;
+       unsigned char port_cnt;
+       unsigned char ports[];
+};
+
+/*
+ * Memory window configuration structure
+ * @type:      Type of the memory window (direct address translation or lookup
+ *             table)
+ *
+ * @bar:       PCIe BAR the memory window referenced to
+ * @idx:       Index of the memory window within the BAR
+ *
+ * @addr_align:        Alignment of translated address
+ * @size_align:        Alignment of memory window size
+ * @size_max:  Maximum size of memory window
+ */
+struct idt_mw_cfg {
+       enum idt_mw_type type;
+
+       unsigned char bar;
+       unsigned char idx;
+
+       u64 addr_align;
+       u64 size_align;
+       u64 size_max;
+};
+
+/*
+ * Description structure of peer IDT NT-functions:
+ * @port:              NT-function port
+ * @part:              NT-function partition
+ *
+ * @mw_cnt:            Number of memory windows supported by NT-function
+ * @mws:               Array of memory windows descriptors
+ */
+struct idt_ntb_peer {
+       unsigned char port;
+       unsigned char part;
+
+       unsigned char mw_cnt;
+       struct idt_mw_cfg *mws;
+};
+
+/*
+ * Description structure of local IDT NT-function:
+ * @ntb:               Linux NTB-device description structure
+ * @swcfg:             Pointer to the structure of local IDT PCIe-switch
+ *                     specific cofnfigurations
+ *
+ * @port:              Local NT-function port
+ * @part:              Local NT-function partition
+ *
+ * @peer_cnt:          Number of peers with activated NTB-function
+ * @peers:             Array of peers descripting structures
+ * @port_idx_map:      Map of port number -> peer index
+ * @part_idx_map:      Map of partition number -> peer index
+ *
+ * @mtbl_lock:         Mapping table access lock
+ *
+ * @mw_cnt:            Number of memory windows supported by NT-function
+ * @mws:               Array of memory windows descriptors
+ * @lut_lock:          Lookup table access lock
+ *
+ * @msg_locks:         Message registers mapping table lockers
+ *
+ * @cfgspc:            Virtual address of the memory mapped configuration
+ *                     space of the NT-function
+ * @db_mask_lock:      Doorbell mask register lock
+ * @msg_mask_lock:     Message mask register lock
+ * @gasa_lock:         GASA registers access lock
+ *
+ * @dbgfs_info:                DebugFS info node
+ */
+struct idt_ntb_dev {
+       struct ntb_dev ntb;
+       struct idt_89hpes_cfg *swcfg;
+
+       unsigned char port;
+       unsigned char part;
+
+       unsigned char peer_cnt;
+       struct idt_ntb_peer peers[IDT_MAX_NR_PEERS];
+       char port_idx_map[IDT_MAX_NR_PORTS];
+       char part_idx_map[IDT_MAX_NR_PARTS];
+
+       spinlock_t mtbl_lock;
+
+       unsigned char mw_cnt;
+       struct idt_mw_cfg *mws;
+       spinlock_t lut_lock;
+
+       spinlock_t msg_locks[IDT_MSG_CNT];
+
+       void __iomem *cfgspc;
+       spinlock_t db_mask_lock;
+       spinlock_t msg_mask_lock;
+       spinlock_t gasa_lock;
+
+       struct dentry *dbgfs_info;
+};
+#define to_ndev_ntb(__ntb) container_of(__ntb, struct idt_ntb_dev, ntb)
+
+/*
+ * Descriptor of the IDT PCIe-switch BAR resources
+ * @setup:     BAR setup register
+ * @limit:     BAR limit register
+ * @ltbase:    Lower translated base address
+ * @utbase:    Upper translated base address
+ */
+struct idt_ntb_bar {
+       unsigned int setup;
+       unsigned int limit;
+       unsigned int ltbase;
+       unsigned int utbase;
+};
+
+/*
+ * Descriptor of the IDT PCIe-switch message resources
+ * @in:                Inbound message register
+ * @out:       Outbound message register
+ * @src:       Source of inbound message register
+ */
+struct idt_ntb_msg {
+       unsigned int in;
+       unsigned int out;
+       unsigned int src;
+};
+
+/*
+ * Descriptor of the IDT PCIe-switch NT-function specific parameters in the
+ * PCI Configuration Space
+ * @bars:      BARs related registers
+ * @msgs:      Messaging related registers
+ */
+struct idt_ntb_regs {
+       struct idt_ntb_bar bars[IDT_BAR_CNT];
+       struct idt_ntb_msg msgs[IDT_MSG_CNT];
+};
+
+/*
+ * Descriptor of the IDT PCIe-switch port specific parameters in the
+ * Global Configuration Space
+ * @pcicmdsts:  PCI command/status register
+ * @pcielctlsts: PCIe link control/status
+ *
+ * @ctl:       Port control register
+ * @sts:       Port status register
+ *
+ * @bars:      BARs related registers
+ */
+struct idt_ntb_port {
+       unsigned int pcicmdsts;
+       unsigned int pcielctlsts;
+       unsigned int ntctl;
+
+       unsigned int ctl;
+       unsigned int sts;
+
+       struct idt_ntb_bar bars[IDT_BAR_CNT];
+};
+
+/*
+ * Descriptor of the IDT PCIe-switch partition specific parameters.
+ * @ctl:       Partition control register in the Global Address Space
+ * @sts:       Partition status register in the Global Address Space
+ * @msgctl:    Messages control registers
+ */
+struct idt_ntb_part {
+       unsigned int ctl;
+       unsigned int sts;
+       unsigned int msgctl[IDT_MSG_CNT];
+};
+
+#endif /* NTB_HW_IDT_H */
index 7b3b6fd..2557e2c 100644 (file)
@@ -6,6 +6,7 @@
  *
  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
  *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of version 2 of the GNU General Public License as
@@ -15,6 +16,7 @@
  *
  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
  *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
  *   modification, are permitted provided that the following conditions
@@ -270,12 +272,12 @@ static inline int ndev_db_addr(struct intel_ntb_dev *ndev,
 
        if (db_addr) {
                *db_addr = reg_addr + reg;
-               dev_dbg(ndev_dev(ndev), "Peer db addr %llx\n", *db_addr);
+               dev_dbg(&ndev->ntb.pdev->dev, "Peer db addr %llx\n", *db_addr);
        }
 
        if (db_size) {
                *db_size = ndev->reg->db_size;
-               dev_dbg(ndev_dev(ndev), "Peer db size %llx\n", *db_size);
+               dev_dbg(&ndev->ntb.pdev->dev, "Peer db size %llx\n", *db_size);
        }
 
        return 0;
@@ -368,7 +370,8 @@ static inline int ndev_spad_addr(struct intel_ntb_dev *ndev, int idx,
 
        if (spad_addr) {
                *spad_addr = reg_addr + reg + (idx << 2);
-               dev_dbg(ndev_dev(ndev), "Peer spad addr %llx\n", *spad_addr);
+               dev_dbg(&ndev->ntb.pdev->dev, "Peer spad addr %llx\n",
+                       *spad_addr);
        }
 
        return 0;
@@ -409,7 +412,7 @@ static irqreturn_t ndev_interrupt(struct intel_ntb_dev *ndev, int vec)
        if ((ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) && (vec == 31))
                vec_mask |= ndev->db_link_mask;
 
-       dev_dbg(ndev_dev(ndev), "vec %d vec_mask %llx\n", vec, vec_mask);
+       dev_dbg(&ndev->ntb.pdev->dev, "vec %d vec_mask %llx\n", vec, vec_mask);
 
        ndev->last_ts = jiffies;
 
@@ -428,7 +431,7 @@ static irqreturn_t ndev_vec_isr(int irq, void *dev)
 {
        struct intel_ntb_vec *nvec = dev;
 
-       dev_dbg(ndev_dev(nvec->ndev), "irq: %d  nvec->num: %d\n",
+       dev_dbg(&nvec->ndev->ntb.pdev->dev, "irq: %d  nvec->num: %d\n",
                irq, nvec->num);
 
        return ndev_interrupt(nvec->ndev, nvec->num);
@@ -438,7 +441,7 @@ static irqreturn_t ndev_irq_isr(int irq, void *dev)
 {
        struct intel_ntb_dev *ndev = dev;
 
-       return ndev_interrupt(ndev, irq - ndev_pdev(ndev)->irq);
+       return ndev_interrupt(ndev, irq - ndev->ntb.pdev->irq);
 }
 
 static int ndev_init_isr(struct intel_ntb_dev *ndev,
@@ -448,7 +451,7 @@ static int ndev_init_isr(struct intel_ntb_dev *ndev,
        struct pci_dev *pdev;
        int rc, i, msix_count, node;
 
-       pdev = ndev_pdev(ndev);
+       pdev = ndev->ntb.pdev;
 
        node = dev_to_node(&pdev->dev);
 
@@ -487,7 +490,7 @@ static int ndev_init_isr(struct intel_ntb_dev *ndev,
                        goto err_msix_request;
        }
 
-       dev_dbg(ndev_dev(ndev), "Using %d msix interrupts\n", msix_count);
+       dev_dbg(&pdev->dev, "Using %d msix interrupts\n", msix_count);
        ndev->db_vec_count = msix_count;
        ndev->db_vec_shift = msix_shift;
        return 0;
@@ -515,7 +518,7 @@ err_msix_vec_alloc:
        if (rc)
                goto err_msi_request;
 
-       dev_dbg(ndev_dev(ndev), "Using msi interrupts\n");
+       dev_dbg(&pdev->dev, "Using msi interrupts\n");
        ndev->db_vec_count = 1;
        ndev->db_vec_shift = total_shift;
        return 0;
@@ -533,7 +536,7 @@ err_msi_enable:
        if (rc)
                goto err_intx_request;
 
-       dev_dbg(ndev_dev(ndev), "Using intx interrupts\n");
+       dev_dbg(&pdev->dev, "Using intx interrupts\n");
        ndev->db_vec_count = 1;
        ndev->db_vec_shift = total_shift;
        return 0;
@@ -547,7 +550,7 @@ static void ndev_deinit_isr(struct intel_ntb_dev *ndev)
        struct pci_dev *pdev;
        int i;
 
-       pdev = ndev_pdev(ndev);
+       pdev = ndev->ntb.pdev;
 
        /* Mask all doorbell interrupts */
        ndev->db_mask = ndev->db_valid_mask;
@@ -744,7 +747,7 @@ static ssize_t ndev_ntb_debugfs_read(struct file *filp, char __user *ubuf,
        union { u64 v64; u32 v32; u16 v16; u8 v8; } u;
 
        ndev = filp->private_data;
-       pdev = ndev_pdev(ndev);
+       pdev = ndev->ntb.pdev;
        mmio = ndev->self_mmio;
 
        buf_size = min(count, 0x800ul);
@@ -1019,7 +1022,8 @@ static void ndev_init_debugfs(struct intel_ntb_dev *ndev)
                ndev->debugfs_info = NULL;
        } else {
                ndev->debugfs_dir =
-                       debugfs_create_dir(ndev_name(ndev), debugfs_dir);
+                       debugfs_create_dir(pci_name(ndev->ntb.pdev),
+                                          debugfs_dir);
                if (!ndev->debugfs_dir)
                        ndev->debugfs_info = NULL;
                else
@@ -1035,20 +1039,26 @@ static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
        debugfs_remove_recursive(ndev->debugfs_dir);
 }
 
-static int intel_ntb_mw_count(struct ntb_dev *ntb)
+static int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx)
 {
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
        return ntb_ndev(ntb)->mw_count;
 }
 
-static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
-                                 phys_addr_t *base,
-                                 resource_size_t *size,
-                                 resource_size_t *align,
-                                 resource_size_t *align_size)
+static int intel_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int idx,
+                                 resource_size_t *addr_align,
+                                 resource_size_t *size_align,
+                                 resource_size_t *size_max)
 {
        struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+       resource_size_t bar_size, mw_size;
        int bar;
 
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
        if (idx >= ndev->b2b_idx && !ndev->b2b_off)
                idx += 1;
 
@@ -1056,24 +1066,26 @@ static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
        if (bar < 0)
                return bar;
 
-       if (base)
-               *base = pci_resource_start(ndev->ntb.pdev, bar) +
-                       (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+       bar_size = pci_resource_len(ndev->ntb.pdev, bar);
 
-       if (size)
-               *size = pci_resource_len(ndev->ntb.pdev, bar) -
-                       (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+       if (idx == ndev->b2b_idx)
+               mw_size = bar_size - ndev->b2b_off;
+       else
+               mw_size = bar_size;
+
+       if (addr_align)
+               *addr_align = pci_resource_len(ndev->ntb.pdev, bar);
 
-       if (align)
-               *align = pci_resource_len(ndev->ntb.pdev, bar);
+       if (size_align)
+               *size_align = 1;
 
-       if (align_size)
-               *align_size = 1;
+       if (size_max)
+               *size_max = mw_size;
 
        return 0;
 }
 
-static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
+static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
                                  dma_addr_t addr, resource_size_t size)
 {
        struct intel_ntb_dev *ndev = ntb_ndev(ntb);
@@ -1083,6 +1095,9 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
        u64 base, limit, reg_val;
        int bar;
 
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
        if (idx >= ndev->b2b_idx && !ndev->b2b_off)
                idx += 1;
 
@@ -1171,7 +1186,7 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
        return 0;
 }
 
-static int intel_ntb_link_is_up(struct ntb_dev *ntb,
+static u64 intel_ntb_link_is_up(struct ntb_dev *ntb,
                                enum ntb_speed *speed,
                                enum ntb_width *width)
 {
@@ -1206,13 +1221,13 @@ static int intel_ntb_link_enable(struct ntb_dev *ntb,
        if (ndev->ntb.topo == NTB_TOPO_SEC)
                return -EINVAL;
 
-       dev_dbg(ndev_dev(ndev),
+       dev_dbg(&ntb->pdev->dev,
                "Enabling link with max_speed %d max_width %d\n",
                max_speed, max_width);
        if (max_speed != NTB_SPEED_AUTO)
-               dev_dbg(ndev_dev(ndev), "ignoring max_speed %d\n", max_speed);
+               dev_dbg(&ntb->pdev->dev, "ignoring max_speed %d\n", max_speed);
        if (max_width != NTB_WIDTH_AUTO)
-               dev_dbg(ndev_dev(ndev), "ignoring max_width %d\n", max_width);
+               dev_dbg(&ntb->pdev->dev, "ignoring max_width %d\n", max_width);
 
        ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
        ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
@@ -1235,7 +1250,7 @@ static int intel_ntb_link_disable(struct ntb_dev *ntb)
        if (ndev->ntb.topo == NTB_TOPO_SEC)
                return -EINVAL;
 
-       dev_dbg(ndev_dev(ndev), "Disabling link\n");
+       dev_dbg(&ntb->pdev->dev, "Disabling link\n");
 
        /* Bring NTB link down */
        ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
@@ -1249,6 +1264,36 @@ static int intel_ntb_link_disable(struct ntb_dev *ntb)
        return 0;
 }
 
+static int intel_ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+       /* Numbers of inbound and outbound memory windows match */
+       return ntb_ndev(ntb)->mw_count;
+}
+
+static int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
+                                    phys_addr_t *base, resource_size_t *size)
+{
+       struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+       int bar;
+
+       if (idx >= ndev->b2b_idx && !ndev->b2b_off)
+               idx += 1;
+
+       bar = ndev_mw_to_bar(ndev, idx);
+       if (bar < 0)
+               return bar;
+
+       if (base)
+               *base = pci_resource_start(ndev->ntb.pdev, bar) +
+                       (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+
+       if (size)
+               *size = pci_resource_len(ndev->ntb.pdev, bar) -
+                       (idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+
+       return 0;
+}
+
 static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
 {
        return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
@@ -1366,30 +1411,30 @@ static int intel_ntb_spad_write(struct ntb_dev *ntb,
                               ndev->self_reg->spad);
 }
 
-static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
+static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
                                    phys_addr_t *spad_addr)
 {
        struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-       return ndev_spad_addr(ndev, idx, spad_addr, ndev->peer_addr,
+       return ndev_spad_addr(ndev, sidx, spad_addr, ndev->peer_addr,
                              ndev->peer_reg->spad);
 }
 
-static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
 {
        struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-       return ndev_spad_read(ndev, idx,
+       return ndev_spad_read(ndev, sidx,
                              ndev->peer_mmio +
                              ndev->peer_reg->spad);
 }
 
-static int intel_ntb_peer_spad_write(struct ntb_dev *ntb,
-                                    int idx, u32 val)
+static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
+                                    int sidx, u32 val)
 {
        struct intel_ntb_dev *ndev = ntb_ndev(ntb);
 
-       return ndev_spad_write(ndev, idx, val,
+       return ndev_spad_write(ndev, sidx, val,
                               ndev->peer_mmio +
                               ndev->peer_reg->spad);
 }
@@ -1442,30 +1487,33 @@ static int atom_link_is_err(struct intel_ntb_dev *ndev)
 
 static inline enum ntb_topo atom_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd)
 {
+       struct device *dev = &ndev->ntb.pdev->dev;
+
        switch (ppd & ATOM_PPD_TOPO_MASK) {
        case ATOM_PPD_TOPO_B2B_USD:
-               dev_dbg(ndev_dev(ndev), "PPD %d B2B USD\n", ppd);
+               dev_dbg(dev, "PPD %d B2B USD\n", ppd);
                return NTB_TOPO_B2B_USD;
 
        case ATOM_PPD_TOPO_B2B_DSD:
-               dev_dbg(ndev_dev(ndev), "PPD %d B2B DSD\n", ppd);
+               dev_dbg(dev, "PPD %d B2B DSD\n", ppd);
                return NTB_TOPO_B2B_DSD;
 
        case ATOM_PPD_TOPO_PRI_USD:
        case ATOM_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */
        case ATOM_PPD_TOPO_SEC_USD:
        case ATOM_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */
-               dev_dbg(ndev_dev(ndev), "PPD %d non B2B disabled\n", ppd);
+               dev_dbg(dev, "PPD %d non B2B disabled\n", ppd);
                return NTB_TOPO_NONE;
        }
 
-       dev_dbg(ndev_dev(ndev), "PPD %d invalid\n", ppd);
+       dev_dbg(dev, "PPD %d invalid\n", ppd);
        return NTB_TOPO_NONE;
 }
 
 static void atom_link_hb(struct work_struct *work)
 {
        struct intel_ntb_dev *ndev = hb_ndev(work);
+       struct device *dev = &ndev->ntb.pdev->dev;
        unsigned long poll_ts;
        void __iomem *mmio;
        u32 status32;
@@ -1503,30 +1551,30 @@ static void atom_link_hb(struct work_struct *work)
 
        /* Clear AER Errors, write to clear */
        status32 = ioread32(mmio + ATOM_ERRCORSTS_OFFSET);
-       dev_dbg(ndev_dev(ndev), "ERRCORSTS = %x\n", status32);
+       dev_dbg(dev, "ERRCORSTS = %x\n", status32);
        status32 &= PCI_ERR_COR_REP_ROLL;
        iowrite32(status32, mmio + ATOM_ERRCORSTS_OFFSET);
 
        /* Clear unexpected electrical idle event in LTSSM, write to clear */
        status32 = ioread32(mmio + ATOM_LTSSMERRSTS0_OFFSET);
-       dev_dbg(ndev_dev(ndev), "LTSSMERRSTS0 = %x\n", status32);
+       dev_dbg(dev, "LTSSMERRSTS0 = %x\n", status32);
        status32 |= ATOM_LTSSMERRSTS0_UNEXPECTEDEI;
        iowrite32(status32, mmio + ATOM_LTSSMERRSTS0_OFFSET);
 
        /* Clear DeSkew Buffer error, write to clear */
        status32 = ioread32(mmio + ATOM_DESKEWSTS_OFFSET);
-       dev_dbg(ndev_dev(ndev), "DESKEWSTS = %x\n", status32);
+       dev_dbg(dev, "DESKEWSTS = %x\n", status32);
        status32 |= ATOM_DESKEWSTS_DBERR;
        iowrite32(status32, mmio + ATOM_DESKEWSTS_OFFSET);
 
        status32 = ioread32(mmio + ATOM_IBSTERRRCRVSTS0_OFFSET);
-       dev_dbg(ndev_dev(ndev), "IBSTERRRCRVSTS0 = %x\n", status32);
+       dev_dbg(dev, "IBSTERRRCRVSTS0 = %x\n", status32);
        status32 &= ATOM_IBIST_ERR_OFLOW;
        iowrite32(status32, mmio + ATOM_IBSTERRRCRVSTS0_OFFSET);
 
        /* Releases the NTB state machine to allow the link to retrain */
        status32 = ioread32(mmio + ATOM_LTSSMSTATEJMP_OFFSET);
-       dev_dbg(ndev_dev(ndev), "LTSSMSTATEJMP = %x\n", status32);
+       dev_dbg(dev, "LTSSMSTATEJMP = %x\n", status32);
        status32 &= ~ATOM_LTSSMSTATEJMP_FORCEDETECT;
        iowrite32(status32, mmio + ATOM_LTSSMSTATEJMP_OFFSET);
 
@@ -1699,11 +1747,11 @@ static int skx_setup_b2b_mw(struct intel_ntb_dev *ndev,
        int b2b_bar;
        u8 bar_sz;
 
-       pdev = ndev_pdev(ndev);
+       pdev = ndev->ntb.pdev;
        mmio = ndev->self_mmio;
 
        if (ndev->b2b_idx == UINT_MAX) {
-               dev_dbg(ndev_dev(ndev), "not using b2b mw\n");
+               dev_dbg(&pdev->dev, "not using b2b mw\n");
                b2b_bar = 0;
                ndev->b2b_off = 0;
        } else {
@@ -1711,24 +1759,21 @@ static int skx_setup_b2b_mw(struct intel_ntb_dev *ndev,
                if (b2b_bar < 0)
                        return -EIO;
 
-               dev_dbg(ndev_dev(ndev), "using b2b mw bar %d\n", b2b_bar);
+               dev_dbg(&pdev->dev, "using b2b mw bar %d\n", b2b_bar);
 
                bar_size = pci_resource_len(ndev->ntb.pdev, b2b_bar);
 
-               dev_dbg(ndev_dev(ndev), "b2b bar size %#llx\n", bar_size);
+               dev_dbg(&pdev->dev, "b2b bar size %#llx\n", bar_size);
 
                if (b2b_mw_share && ((bar_size >> 1) >= XEON_B2B_MIN_SIZE)) {
-                       dev_dbg(ndev_dev(ndev),
-                               "b2b using first half of bar\n");
+                       dev_dbg(&pdev->dev, "b2b using first half of bar\n");
                        ndev->b2b_off = bar_size >> 1;
                } else if (bar_size >= XEON_B2B_MIN_SIZE) {
-                       dev_dbg(ndev_dev(ndev),
-                               "b2b using whole bar\n");
+                       dev_dbg(&pdev->dev, "b2b using whole bar\n");
                        ndev->b2b_off = 0;
                        --ndev->mw_count;
                } else {
-                       dev_dbg(ndev_dev(ndev),
-                               "b2b bar size is too small\n");
+                       dev_dbg(&pdev->dev, "b2b bar size is too small\n");
                        return -EIO;
                }
        }
@@ -1738,7 +1783,7 @@ static int skx_setup_b2b_mw(struct intel_ntb_dev *ndev,
         * except disable or halve the size of the b2b secondary bar.
         */
        pci_read_config_byte(pdev, SKX_IMBAR1SZ_OFFSET, &bar_sz);
-       dev_dbg(ndev_dev(ndev), "IMBAR1SZ %#x\n", bar_sz);
+       dev_dbg(&pdev->dev, "IMBAR1SZ %#x\n", bar_sz);
        if (b2b_bar == 1) {
                if (ndev->b2b_off)
                        bar_sz -= 1;
@@ -1748,10 +1793,10 @@ static int skx_setup_b2b_mw(struct intel_ntb_dev *ndev,
 
        pci_write_config_byte(pdev, SKX_EMBAR1SZ_OFFSET, bar_sz);
        pci_read_config_byte(pdev, SKX_EMBAR1SZ_OFFSET, &bar_sz);
-       dev_dbg(ndev_dev(ndev), "EMBAR1SZ %#x\n", bar_sz);
+       dev_dbg(&pdev->dev, "EMBAR1SZ %#x\n", bar_sz);
 
        pci_read_config_byte(pdev, SKX_IMBAR2SZ_OFFSET, &bar_sz);
-       dev_dbg(ndev_dev(ndev), "IMBAR2SZ %#x\n", bar_sz);
+       dev_dbg(&pdev->dev, "IMBAR2SZ %#x\n", bar_sz);
        if (b2b_bar == 2) {
                if (ndev->b2b_off)
                        bar_sz -= 1;
@@ -1761,7 +1806,7 @@ static int skx_setup_b2b_mw(struct intel_ntb_dev *ndev,
 
        pci_write_config_byte(pdev, SKX_EMBAR2SZ_OFFSET, bar_sz);
        pci_read_config_byte(pdev, SKX_EMBAR2SZ_OFFSET, &bar_sz);
-       dev_dbg(ndev_dev(ndev), "EMBAR2SZ %#x\n", bar_sz);
+       dev_dbg(&pdev->dev, "EMBAR2SZ %#x\n", bar_sz);
 
        /* SBAR01 hit by first part of the b2b bar */
        if (b2b_bar == 0)
@@ -1777,12 +1822,12 @@ static int skx_setup_b2b_mw(struct intel_ntb_dev *ndev,
        bar_addr = addr->bar2_addr64 + (b2b_bar == 1 ? ndev->b2b_off : 0);
        iowrite64(bar_addr, mmio + SKX_IMBAR1XLMT_OFFSET);
        bar_addr = ioread64(mmio + SKX_IMBAR1XLMT_OFFSET);
-       dev_dbg(ndev_dev(ndev), "IMBAR1XLMT %#018llx\n", bar_addr);
+       dev_dbg(&pdev->dev, "IMBAR1XLMT %#018llx\n", bar_addr);
 
        bar_addr = addr->bar4_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
        iowrite64(bar_addr, mmio + SKX_IMBAR2XLMT_OFFSET);
        bar_addr = ioread64(mmio + SKX_IMBAR2XLMT_OFFSET);
-       dev_dbg(ndev_dev(ndev), "IMBAR2XLMT %#018llx\n", bar_addr);
+       dev_dbg(&pdev->dev, "IMBAR2XLMT %#018llx\n", bar_addr);
 
        /* zero incoming translation addrs */
        iowrite64(0, mmio + SKX_IMBAR1XBASE_OFFSET);
@@ -1852,7 +1897,7 @@ static int skx_init_dev(struct intel_ntb_dev *ndev)
        u8 ppd;
        int rc;
 
-       pdev = ndev_pdev(ndev);
+       pdev = ndev->ntb.pdev;
 
        ndev->reg = &skx_reg;
 
@@ -1861,7 +1906,7 @@ static int skx_init_dev(struct intel_ntb_dev *ndev)
                return -EIO;
 
        ndev->ntb.topo = xeon_ppd_topo(ndev, ppd);
-       dev_dbg(ndev_dev(ndev), "ppd %#x topo %s\n", ppd,
+       dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd,
                ntb_topo_string(ndev->ntb.topo));
        if (ndev->ntb.topo == NTB_TOPO_NONE)
                return -EINVAL;
@@ -1885,14 +1930,14 @@ static int intel_ntb3_link_enable(struct ntb_dev *ntb,
 
        ndev = container_of(ntb, struct intel_ntb_dev, ntb);
 
-       dev_dbg(ndev_dev(ndev),
+       dev_dbg(&ntb->pdev->dev,
                "Enabling link with max_speed %d max_width %d\n",
                max_speed, max_width);
 
        if (max_speed != NTB_SPEED_AUTO)
-               dev_dbg(ndev_dev(ndev), "ignoring max_speed %d\n", max_speed);
+               dev_dbg(&ntb->pdev->dev, "ignoring max_speed %d\n", max_speed);
        if (max_width != NTB_WIDTH_AUTO)
-               dev_dbg(ndev_dev(ndev), "ignoring max_width %d\n", max_width);
+               dev_dbg(&ntb->pdev->dev, "ignoring max_width %d\n", max_width);
 
        ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
        ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
@@ -1902,7 +1947,7 @@ static int intel_ntb3_link_enable(struct ntb_dev *ntb,
 
        return 0;
 }
-static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
+static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
                                   dma_addr_t addr, resource_size_t size)
 {
        struct intel_ntb_dev *ndev = ntb_ndev(ntb);
@@ -1912,6 +1957,9 @@ static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
        u64 base, limit, reg_val;
        int bar;
 
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
        if (idx >= ndev->b2b_idx && !ndev->b2b_off)
                idx += 1;
 
@@ -1953,7 +2001,7 @@ static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
                return -EIO;
        }
 
-       dev_dbg(ndev_dev(ndev), "BAR %d IMBARXBASE: %#Lx\n", bar, reg_val);
+       dev_dbg(&ntb->pdev->dev, "BAR %d IMBARXBASE: %#Lx\n", bar, reg_val);
 
        /* set and verify setting the limit */
        iowrite64(limit, mmio + limit_reg);
@@ -1964,7 +2012,7 @@ static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
                return -EIO;
        }
 
-       dev_dbg(ndev_dev(ndev), "BAR %d IMBARXLMT: %#Lx\n", bar, reg_val);
+       dev_dbg(&ntb->pdev->dev, "BAR %d IMBARXLMT: %#Lx\n", bar, reg_val);
 
        /* setup the EP */
        limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10) + 0x4000;
@@ -1985,7 +2033,7 @@ static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
                return -EIO;
        }
 
-       dev_dbg(ndev_dev(ndev), "BAR %d EMBARXLMT: %#Lx\n", bar, reg_val);
+       dev_dbg(&ntb->pdev->dev, "BAR %d EMBARXLMT: %#Lx\n", bar, reg_val);
 
        return 0;
 }
@@ -2092,7 +2140,7 @@ static inline enum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd)
 static inline int xeon_ppd_bar4_split(struct intel_ntb_dev *ndev, u8 ppd)
 {
        if (ppd & XEON_PPD_SPLIT_BAR_MASK) {
-               dev_dbg(ndev_dev(ndev), "PPD %d split bar\n", ppd);
+               dev_dbg(&ndev->ntb.pdev->dev, "PPD %d split bar\n", ppd);
                return 1;
        }
        return 0;
@@ -2122,11 +2170,11 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
        int b2b_bar;
        u8 bar_sz;
 
-       pdev = ndev_pdev(ndev);
+       pdev = ndev->ntb.pdev;
        mmio = ndev->self_mmio;
 
        if (ndev->b2b_idx == UINT_MAX) {
-               dev_dbg(ndev_dev(ndev), "not using b2b mw\n");
+               dev_dbg(&pdev->dev, "not using b2b mw\n");
                b2b_bar = 0;
                ndev->b2b_off = 0;
        } else {
@@ -2134,24 +2182,21 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
                if (b2b_bar < 0)
                        return -EIO;
 
-               dev_dbg(ndev_dev(ndev), "using b2b mw bar %d\n", b2b_bar);
+               dev_dbg(&pdev->dev, "using b2b mw bar %d\n", b2b_bar);
 
                bar_size = pci_resource_len(ndev->ntb.pdev, b2b_bar);
 
-               dev_dbg(ndev_dev(ndev), "b2b bar size %#llx\n", bar_size);
+               dev_dbg(&pdev->dev, "b2b bar size %#llx\n", bar_size);
 
                if (b2b_mw_share && XEON_B2B_MIN_SIZE <= bar_size >> 1) {
-                       dev_dbg(ndev_dev(ndev),
-                               "b2b using first half of bar\n");
+                       dev_dbg(&pdev->dev, "b2b using first half of bar\n");
                        ndev->b2b_off = bar_size >> 1;
                } else if (XEON_B2B_MIN_SIZE <= bar_size) {
-                       dev_dbg(ndev_dev(ndev),
-                               "b2b using whole bar\n");
+                       dev_dbg(&pdev->dev, "b2b using whole bar\n");
                        ndev->b2b_off = 0;
                        --ndev->mw_count;
                } else {
-                       dev_dbg(ndev_dev(ndev),
-                               "b2b bar size is too small\n");
+                       dev_dbg(&pdev->dev, "b2b bar size is too small\n");
                        return -EIO;
                }
        }
@@ -2163,7 +2208,7 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
         * offsets are not in a consistent order (bar5sz comes after ppd, odd).
         */
        pci_read_config_byte(pdev, XEON_PBAR23SZ_OFFSET, &bar_sz);
-       dev_dbg(ndev_dev(ndev), "PBAR23SZ %#x\n", bar_sz);
+       dev_dbg(&pdev->dev, "PBAR23SZ %#x\n", bar_sz);
        if (b2b_bar == 2) {
                if (ndev->b2b_off)
                        bar_sz -= 1;
@@ -2172,11 +2217,11 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
        }
        pci_write_config_byte(pdev, XEON_SBAR23SZ_OFFSET, bar_sz);
        pci_read_config_byte(pdev, XEON_SBAR23SZ_OFFSET, &bar_sz);
-       dev_dbg(ndev_dev(ndev), "SBAR23SZ %#x\n", bar_sz);
+       dev_dbg(&pdev->dev, "SBAR23SZ %#x\n", bar_sz);
 
        if (!ndev->bar4_split) {
                pci_read_config_byte(pdev, XEON_PBAR45SZ_OFFSET, &bar_sz);
-               dev_dbg(ndev_dev(ndev), "PBAR45SZ %#x\n", bar_sz);
+               dev_dbg(&pdev->dev, "PBAR45SZ %#x\n", bar_sz);
                if (b2b_bar == 4) {
                        if (ndev->b2b_off)
                                bar_sz -= 1;
@@ -2185,10 +2230,10 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
                }
                pci_write_config_byte(pdev, XEON_SBAR45SZ_OFFSET, bar_sz);
                pci_read_config_byte(pdev, XEON_SBAR45SZ_OFFSET, &bar_sz);
-               dev_dbg(ndev_dev(ndev), "SBAR45SZ %#x\n", bar_sz);
+               dev_dbg(&pdev->dev, "SBAR45SZ %#x\n", bar_sz);
        } else {
                pci_read_config_byte(pdev, XEON_PBAR4SZ_OFFSET, &bar_sz);
-               dev_dbg(ndev_dev(ndev), "PBAR4SZ %#x\n", bar_sz);
+               dev_dbg(&pdev->dev, "PBAR4SZ %#x\n", bar_sz);
                if (b2b_bar == 4) {
                        if (ndev->b2b_off)
                                bar_sz -= 1;
@@ -2197,10 +2242,10 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
                }
                pci_write_config_byte(pdev, XEON_SBAR4SZ_OFFSET, bar_sz);
                pci_read_config_byte(pdev, XEON_SBAR4SZ_OFFSET, &bar_sz);
-               dev_dbg(ndev_dev(ndev), "SBAR4SZ %#x\n", bar_sz);
+               dev_dbg(&pdev->dev, "SBAR4SZ %#x\n", bar_sz);
 
                pci_read_config_byte(pdev, XEON_PBAR5SZ_OFFSET, &bar_sz);
-               dev_dbg(ndev_dev(ndev), "PBAR5SZ %#x\n", bar_sz);
+               dev_dbg(&pdev->dev, "PBAR5SZ %#x\n", bar_sz);
                if (b2b_bar == 5) {
                        if (ndev->b2b_off)
                                bar_sz -= 1;
@@ -2209,7 +2254,7 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
                }
                pci_write_config_byte(pdev, XEON_SBAR5SZ_OFFSET, bar_sz);
                pci_read_config_byte(pdev, XEON_SBAR5SZ_OFFSET, &bar_sz);
-               dev_dbg(ndev_dev(ndev), "SBAR5SZ %#x\n", bar_sz);
+               dev_dbg(&pdev->dev, "SBAR5SZ %#x\n", bar_sz);
        }
 
        /* SBAR01 hit by first part of the b2b bar */
@@ -2226,7 +2271,7 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
        else
                return -EIO;
 
-       dev_dbg(ndev_dev(ndev), "SBAR01 %#018llx\n", bar_addr);
+       dev_dbg(&pdev->dev, "SBAR01 %#018llx\n", bar_addr);
        iowrite64(bar_addr, mmio + XEON_SBAR0BASE_OFFSET);
 
        /* Other SBAR are normally hit by the PBAR xlat, except for b2b bar.
@@ -2237,26 +2282,26 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
        bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
        iowrite64(bar_addr, mmio + XEON_SBAR23BASE_OFFSET);
        bar_addr = ioread64(mmio + XEON_SBAR23BASE_OFFSET);
-       dev_dbg(ndev_dev(ndev), "SBAR23 %#018llx\n", bar_addr);
+       dev_dbg(&pdev->dev, "SBAR23 %#018llx\n", bar_addr);
 
        if (!ndev->bar4_split) {
                bar_addr = addr->bar4_addr64 +
                        (b2b_bar == 4 ? ndev->b2b_off : 0);
                iowrite64(bar_addr, mmio + XEON_SBAR45BASE_OFFSET);
                bar_addr = ioread64(mmio + XEON_SBAR45BASE_OFFSET);
-               dev_dbg(ndev_dev(ndev), "SBAR45 %#018llx\n", bar_addr);
+               dev_dbg(&pdev->dev, "SBAR45 %#018llx\n", bar_addr);
        } else {
                bar_addr = addr->bar4_addr32 +
                        (b2b_bar == 4 ? ndev->b2b_off : 0);
                iowrite32(bar_addr, mmio + XEON_SBAR4BASE_OFFSET);
                bar_addr = ioread32(mmio + XEON_SBAR4BASE_OFFSET);
-               dev_dbg(ndev_dev(ndev), "SBAR4 %#010llx\n", bar_addr);
+               dev_dbg(&pdev->dev, "SBAR4 %#010llx\n", bar_addr);
 
                bar_addr = addr->bar5_addr32 +
                        (b2b_bar == 5 ? ndev->b2b_off : 0);
                iowrite32(bar_addr, mmio + XEON_SBAR5BASE_OFFSET);
                bar_addr = ioread32(mmio + XEON_SBAR5BASE_OFFSET);
-               dev_dbg(ndev_dev(ndev), "SBAR5 %#010llx\n", bar_addr);
+               dev_dbg(&pdev->dev, "SBAR5 %#010llx\n", bar_addr);
        }
 
        /* setup incoming bar limits == base addrs (zero length windows) */
@@ -2264,26 +2309,26 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
        bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
        iowrite64(bar_addr, mmio + XEON_SBAR23LMT_OFFSET);
        bar_addr = ioread64(mmio + XEON_SBAR23LMT_OFFSET);
-       dev_dbg(ndev_dev(ndev), "SBAR23LMT %#018llx\n", bar_addr);
+       dev_dbg(&pdev->dev, "SBAR23LMT %#018llx\n", bar_addr);
 
        if (!ndev->bar4_split) {
                bar_addr = addr->bar4_addr64 +
                        (b2b_bar == 4 ? ndev->b2b_off : 0);
                iowrite64(bar_addr, mmio + XEON_SBAR45LMT_OFFSET);
                bar_addr = ioread64(mmio + XEON_SBAR45LMT_OFFSET);
-               dev_dbg(ndev_dev(ndev), "SBAR45LMT %#018llx\n", bar_addr);
+               dev_dbg(&pdev->dev, "SBAR45LMT %#018llx\n", bar_addr);
        } else {
                bar_addr = addr->bar4_addr32 +
                        (b2b_bar == 4 ? ndev->b2b_off : 0);
                iowrite32(bar_addr, mmio + XEON_SBAR4LMT_OFFSET);
                bar_addr = ioread32(mmio + XEON_SBAR4LMT_OFFSET);
-               dev_dbg(ndev_dev(ndev), "SBAR4LMT %#010llx\n", bar_addr);
+               dev_dbg(&pdev->dev, "SBAR4LMT %#010llx\n", bar_addr);
 
                bar_addr = addr->bar5_addr32 +
                        (b2b_bar == 5 ? ndev->b2b_off : 0);
                iowrite32(bar_addr, mmio + XEON_SBAR5LMT_OFFSET);
                bar_addr = ioread32(mmio + XEON_SBAR5LMT_OFFSET);
-               dev_dbg(ndev_dev(ndev), "SBAR5LMT %#05llx\n", bar_addr);
+               dev_dbg(&pdev->dev, "SBAR5LMT %#05llx\n", bar_addr);
        }
 
        /* zero incoming translation addrs */
@@ -2309,23 +2354,23 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
        bar_addr = peer_addr->bar2_addr64;
        iowrite64(bar_addr, mmio + XEON_PBAR23XLAT_OFFSET);
        bar_addr = ioread64(mmio + XEON_PBAR23XLAT_OFFSET);
-       dev_dbg(ndev_dev(ndev), "PBAR23XLAT %#018llx\n", bar_addr);
+       dev_dbg(&pdev->dev, "PBAR23XLAT %#018llx\n", bar_addr);
 
        if (!ndev->bar4_split) {
                bar_addr = peer_addr->bar4_addr64;
                iowrite64(bar_addr, mmio + XEON_PBAR45XLAT_OFFSET);
                bar_addr = ioread64(mmio + XEON_PBAR45XLAT_OFFSET);
-               dev_dbg(ndev_dev(ndev), "PBAR45XLAT %#018llx\n", bar_addr);
+               dev_dbg(&pdev->dev, "PBAR45XLAT %#018llx\n", bar_addr);
        } else {
                bar_addr = peer_addr->bar4_addr32;
                iowrite32(bar_addr, mmio + XEON_PBAR4XLAT_OFFSET);
                bar_addr = ioread32(mmio + XEON_PBAR4XLAT_OFFSET);
-               dev_dbg(ndev_dev(ndev), "PBAR4XLAT %#010llx\n", bar_addr);
+               dev_dbg(&pdev->dev, "PBAR4XLAT %#010llx\n", bar_addr);
 
                bar_addr = peer_addr->bar5_addr32;
                iowrite32(bar_addr, mmio + XEON_PBAR5XLAT_OFFSET);
                bar_addr = ioread32(mmio + XEON_PBAR5XLAT_OFFSET);
-               dev_dbg(ndev_dev(ndev), "PBAR5XLAT %#010llx\n", bar_addr);
+               dev_dbg(&pdev->dev, "PBAR5XLAT %#010llx\n", bar_addr);
        }
 
        /* set the translation offset for b2b registers */
@@ -2343,7 +2388,7 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
                return -EIO;
 
        /* B2B_XLAT_OFFSET is 64bit, but can only take 32bit writes */
-       dev_dbg(ndev_dev(ndev), "B2BXLAT %#018llx\n", bar_addr);
+       dev_dbg(&pdev->dev, "B2BXLAT %#018llx\n", bar_addr);
        iowrite32(bar_addr, mmio + XEON_B2B_XLAT_OFFSETL);
        iowrite32(bar_addr >> 32, mmio + XEON_B2B_XLAT_OFFSETU);
 
@@ -2362,6 +2407,7 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
 
 static int xeon_init_ntb(struct intel_ntb_dev *ndev)
 {
+       struct device *dev = &ndev->ntb.pdev->dev;
        int rc;
        u32 ntb_ctl;
 
@@ -2377,7 +2423,7 @@ static int xeon_init_ntb(struct intel_ntb_dev *ndev)
        switch (ndev->ntb.topo) {
        case NTB_TOPO_PRI:
                if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
-                       dev_err(ndev_dev(ndev), "NTB Primary config disabled\n");
+                       dev_err(dev, "NTB Primary config disabled\n");
                        return -EINVAL;
                }
 
@@ -2395,7 +2441,7 @@ static int xeon_init_ntb(struct intel_ntb_dev *ndev)
 
        case NTB_TOPO_SEC:
                if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
-                       dev_err(ndev_dev(ndev), "NTB Secondary config disabled\n");
+                       dev_err(dev, "NTB Secondary config disabled\n");
                        return -EINVAL;
                }
                /* use half the spads for the peer */
@@ -2420,18 +2466,17 @@ static int xeon_init_ntb(struct intel_ntb_dev *ndev)
                                ndev->b2b_idx = b2b_mw_idx;
 
                        if (ndev->b2b_idx >= ndev->mw_count) {
-                               dev_dbg(ndev_dev(ndev),
+                               dev_dbg(dev,
                                        "b2b_mw_idx %d invalid for mw_count %u\n",
                                        b2b_mw_idx, ndev->mw_count);
                                return -EINVAL;
                        }
 
-                       dev_dbg(ndev_dev(ndev),
-                               "setting up b2b mw idx %d means %d\n",
+                       dev_dbg(dev, "setting up b2b mw idx %d means %d\n",
                                b2b_mw_idx, ndev->b2b_idx);
 
                } else if (ndev->hwerr_flags & NTB_HWERR_B2BDOORBELL_BIT14) {
-                       dev_warn(ndev_dev(ndev), "Reduce doorbell count by 1\n");
+                       dev_warn(dev, "Reduce doorbell count by 1\n");
                        ndev->db_count -= 1;
                }
 
@@ -2472,7 +2517,7 @@ static int xeon_init_dev(struct intel_ntb_dev *ndev)
        u8 ppd;
        int rc, mem;
 
-       pdev = ndev_pdev(ndev);
+       pdev = ndev->ntb.pdev;
 
        switch (pdev->device) {
        /* There is a Xeon hardware errata related to writes to SDOORBELL or
@@ -2548,14 +2593,14 @@ static int xeon_init_dev(struct intel_ntb_dev *ndev)
                return -EIO;
 
        ndev->ntb.topo = xeon_ppd_topo(ndev, ppd);
-       dev_dbg(ndev_dev(ndev), "ppd %#x topo %s\n", ppd,
+       dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd,
                ntb_topo_string(ndev->ntb.topo));
        if (ndev->ntb.topo == NTB_TOPO_NONE)
                return -EINVAL;
 
        if (ndev->ntb.topo != NTB_TOPO_SEC) {
                ndev->bar4_split = xeon_ppd_bar4_split(ndev, ppd);
-               dev_dbg(ndev_dev(ndev), "ppd %#x bar4_split %d\n",
+               dev_dbg(&pdev->dev, "ppd %#x bar4_split %d\n",
                        ppd, ndev->bar4_split);
        } else {
                /* This is a way for transparent BAR to figure out if we are
@@ -2565,7 +2610,7 @@ static int xeon_init_dev(struct intel_ntb_dev *ndev)
                mem = pci_select_bars(pdev, IORESOURCE_MEM);
                ndev->bar4_split = hweight32(mem) ==
                        HSX_SPLIT_BAR_MW_COUNT + 1;
-               dev_dbg(ndev_dev(ndev), "mem %#x bar4_split %d\n",
+               dev_dbg(&pdev->dev, "mem %#x bar4_split %d\n",
                        mem, ndev->bar4_split);
        }
 
@@ -2602,7 +2647,7 @@ static int intel_ntb_init_pci(struct intel_ntb_dev *ndev, struct pci_dev *pdev)
                rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
                if (rc)
                        goto err_dma_mask;
-               dev_warn(ndev_dev(ndev), "Cannot DMA highmem\n");
+               dev_warn(&pdev->dev, "Cannot DMA highmem\n");
        }
 
        rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -2610,7 +2655,7 @@ static int intel_ntb_init_pci(struct intel_ntb_dev *ndev, struct pci_dev *pdev)
                rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
                if (rc)
                        goto err_dma_mask;
-               dev_warn(ndev_dev(ndev), "Cannot DMA consistent highmem\n");
+               dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n");
        }
 
        ndev->self_mmio = pci_iomap(pdev, 0, 0);
@@ -2636,7 +2681,7 @@ err_pci_enable:
 
 static void intel_ntb_deinit_pci(struct intel_ntb_dev *ndev)
 {
-       struct pci_dev *pdev = ndev_pdev(ndev);
+       struct pci_dev *pdev = ndev->ntb.pdev;
 
        if (ndev->peer_mmio && ndev->peer_mmio != ndev->self_mmio)
                pci_iounmap(pdev, ndev->peer_mmio);
@@ -2906,8 +2951,10 @@ static const struct intel_ntb_xlat_reg skx_sec_xlat = {
 /* operations for primary side of local ntb */
 static const struct ntb_dev_ops intel_ntb_ops = {
        .mw_count               = intel_ntb_mw_count,
-       .mw_get_range           = intel_ntb_mw_get_range,
+       .mw_get_align           = intel_ntb_mw_get_align,
        .mw_set_trans           = intel_ntb_mw_set_trans,
+       .peer_mw_count          = intel_ntb_peer_mw_count,
+       .peer_mw_get_addr       = intel_ntb_peer_mw_get_addr,
        .link_is_up             = intel_ntb_link_is_up,
        .link_enable            = intel_ntb_link_enable,
        .link_disable           = intel_ntb_link_disable,
@@ -2932,8 +2979,10 @@ static const struct ntb_dev_ops intel_ntb_ops = {
 
 static const struct ntb_dev_ops intel_ntb3_ops = {
        .mw_count               = intel_ntb_mw_count,
-       .mw_get_range           = intel_ntb_mw_get_range,
+       .mw_get_align           = intel_ntb_mw_get_align,
        .mw_set_trans           = intel_ntb3_mw_set_trans,
+       .peer_mw_count          = intel_ntb_peer_mw_count,
+       .peer_mw_get_addr       = intel_ntb_peer_mw_get_addr,
        .link_is_up             = intel_ntb_link_is_up,
        .link_enable            = intel_ntb3_link_enable,
        .link_disable           = intel_ntb_link_disable,
@@ -3008,4 +3057,3 @@ static void __exit intel_ntb_pci_driver_exit(void)
        debugfs_remove_recursive(debugfs_dir);
 }
 module_exit(intel_ntb_pci_driver_exit);
-
index f2cf8a7..2d6c38a 100644 (file)
@@ -382,9 +382,6 @@ struct intel_ntb_dev {
        struct dentry                   *debugfs_info;
 };
 
-#define ndev_pdev(ndev) ((ndev)->ntb.pdev)
-#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
-#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
 #define ntb_ndev(__ntb) container_of(__ntb, struct intel_ntb_dev, ntb)
 #define hb_ndev(__work) container_of(__work, struct intel_ntb_dev, \
                                     hb_timer.work)
index 2e25307..03b80d8 100644 (file)
@@ -5,6 +5,7 @@
  *   GPL LICENSE SUMMARY
  *
  *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of version 2 of the GNU General Public License as
@@ -18,6 +19,7 @@
  *   BSD LICENSE
  *
  *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
  *   modification, are permitted provided that the following conditions
@@ -191,6 +193,73 @@ void ntb_db_event(struct ntb_dev *ntb, int vector)
 }
 EXPORT_SYMBOL(ntb_db_event);
 
+void ntb_msg_event(struct ntb_dev *ntb)
+{
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&ntb->ctx_lock, irqflags);
+       {
+               if (ntb->ctx_ops && ntb->ctx_ops->msg_event)
+                       ntb->ctx_ops->msg_event(ntb->ctx);
+       }
+       spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
+}
+EXPORT_SYMBOL(ntb_msg_event);
+
+int ntb_default_port_number(struct ntb_dev *ntb)
+{
+       switch (ntb->topo) {
+       case NTB_TOPO_PRI:
+       case NTB_TOPO_B2B_USD:
+               return NTB_PORT_PRI_USD;
+       case NTB_TOPO_SEC:
+       case NTB_TOPO_B2B_DSD:
+               return NTB_PORT_SEC_DSD;
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL(ntb_default_port_number);
+
+int ntb_default_peer_port_count(struct ntb_dev *ntb)
+{
+       return NTB_DEF_PEER_CNT;
+}
+EXPORT_SYMBOL(ntb_default_peer_port_count);
+
+int ntb_default_peer_port_number(struct ntb_dev *ntb, int pidx)
+{
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
+       switch (ntb->topo) {
+       case NTB_TOPO_PRI:
+       case NTB_TOPO_B2B_USD:
+               return NTB_PORT_SEC_DSD;
+       case NTB_TOPO_SEC:
+       case NTB_TOPO_B2B_DSD:
+               return NTB_PORT_PRI_USD;
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL(ntb_default_peer_port_number);
+
+int ntb_default_peer_port_idx(struct ntb_dev *ntb, int port)
+{
+       int peer_port = ntb_default_peer_port_number(ntb, NTB_DEF_PEER_IDX);
+
+       if (peer_port == -EINVAL || port != peer_port)
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL(ntb_default_peer_port_idx);
+
 static int ntb_probe(struct device *dev)
 {
        struct ntb_dev *ntb;
index 10e5bf4..9a03c58 100644 (file)
@@ -95,6 +95,9 @@ MODULE_PARM_DESC(use_dma, "Use DMA engine to perform large data copy");
 
 static struct dentry *nt_debugfs_dir;
 
+/* Only two-ports NTB devices are supported */
+#define PIDX           NTB_DEF_PEER_IDX
+
 struct ntb_queue_entry {
        /* ntb_queue list reference */
        struct list_head entry;
@@ -670,7 +673,7 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
        if (!mw->virt_addr)
                return;
 
-       ntb_mw_clear_trans(nt->ndev, num_mw);
+       ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
        dma_free_coherent(&pdev->dev, mw->buff_size,
                          mw->virt_addr, mw->dma_addr);
        mw->xlat_size = 0;
@@ -727,7 +730,8 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
        }
 
        /* Notify HW the memory location of the receive buffer */
-       rc = ntb_mw_set_trans(nt->ndev, num_mw, mw->dma_addr, mw->xlat_size);
+       rc = ntb_mw_set_trans(nt->ndev, PIDX, num_mw, mw->dma_addr,
+                             mw->xlat_size);
        if (rc) {
                dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw);
                ntb_free_mw(nt, num_mw);
@@ -858,17 +862,17 @@ static void ntb_transport_link_work(struct work_struct *work)
                        size = max_mw_size;
 
                spad = MW0_SZ_HIGH + (i * 2);
-               ntb_peer_spad_write(ndev, spad, upper_32_bits(size));
+               ntb_peer_spad_write(ndev, PIDX, spad, upper_32_bits(size));
 
                spad = MW0_SZ_LOW + (i * 2);
-               ntb_peer_spad_write(ndev, spad, lower_32_bits(size));
+               ntb_peer_spad_write(ndev, PIDX, spad, lower_32_bits(size));
        }
 
-       ntb_peer_spad_write(ndev, NUM_MWS, nt->mw_count);
+       ntb_peer_spad_write(ndev, PIDX, NUM_MWS, nt->mw_count);
 
-       ntb_peer_spad_write(ndev, NUM_QPS, nt->qp_count);
+       ntb_peer_spad_write(ndev, PIDX, NUM_QPS, nt->qp_count);
 
-       ntb_peer_spad_write(ndev, VERSION, NTB_TRANSPORT_VERSION);
+       ntb_peer_spad_write(ndev, PIDX, VERSION, NTB_TRANSPORT_VERSION);
 
        /* Query the remote side for its info */
        val = ntb_spad_read(ndev, VERSION);
@@ -944,7 +948,7 @@ static void ntb_qp_link_work(struct work_struct *work)
 
        val = ntb_spad_read(nt->ndev, QP_LINKS);
 
-       ntb_peer_spad_write(nt->ndev, QP_LINKS, val | BIT(qp->qp_num));
+       ntb_peer_spad_write(nt->ndev, PIDX, QP_LINKS, val | BIT(qp->qp_num));
 
        /* query remote spad for qp ready bits */
        dev_dbg_ratelimited(&pdev->dev, "Remote QP link status = %x\n", val);
@@ -1055,7 +1059,12 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
        int node;
        int rc, i;
 
-       mw_count = ntb_mw_count(ndev);
+       mw_count = ntb_mw_count(ndev, PIDX);
+
+       if (!ndev->ops->mw_set_trans) {
+               dev_err(&ndev->dev, "Inbound MW based NTB API is required\n");
+               return -EINVAL;
+       }
 
        if (ntb_db_is_unsafe(ndev))
                dev_dbg(&ndev->dev,
@@ -1064,6 +1073,9 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
                dev_dbg(&ndev->dev,
                        "scratchpad is unsafe, proceed anyway...\n");
 
+       if (ntb_peer_port_count(ndev) != NTB_DEF_PEER_CNT)
+               dev_warn(&ndev->dev, "Multi-port NTB devices unsupported\n");
+
        node = dev_to_node(&ndev->dev);
 
        nt = kzalloc_node(sizeof(*nt), GFP_KERNEL, node);
@@ -1094,8 +1106,13 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
        for (i = 0; i < mw_count; i++) {
                mw = &nt->mw_vec[i];
 
-               rc = ntb_mw_get_range(ndev, i, &mw->phys_addr, &mw->phys_size,
-                                     &mw->xlat_align, &mw->xlat_align_size);
+               rc = ntb_mw_get_align(ndev, PIDX, i, &mw->xlat_align,
+                                     &mw->xlat_align_size, NULL);
+               if (rc)
+                       goto err1;
+
+               rc = ntb_peer_mw_get_addr(ndev, i, &mw->phys_addr,
+                                         &mw->phys_size);
                if (rc)
                        goto err1;
 
@@ -2091,8 +2108,7 @@ void ntb_transport_link_down(struct ntb_transport_qp *qp)
 
        val = ntb_spad_read(qp->ndev, QP_LINKS);
 
-       ntb_peer_spad_write(qp->ndev, QP_LINKS,
-                           val & ~BIT(qp->qp_num));
+       ntb_peer_spad_write(qp->ndev, PIDX, QP_LINKS, val & ~BIT(qp->qp_num));
 
        if (qp->link_is_up)
                ntb_send_link_down(qp);
index 5cab283..759f772 100644 (file)
@@ -76,6 +76,7 @@
 #define DMA_RETRIES            20
 #define SZ_4G                  (1ULL << 32)
 #define MAX_SEG_ORDER          20 /* no larger than 1M for kmalloc buffer */
+#define PIDX                   NTB_DEF_PEER_IDX
 
 MODULE_LICENSE(DRIVER_LICENSE);
 MODULE_VERSION(DRIVER_VERSION);
@@ -100,6 +101,10 @@ static bool use_dma; /* default to 0 */
 module_param(use_dma, bool, 0644);
 MODULE_PARM_DESC(use_dma, "Using DMA engine to measure performance");
 
+static bool on_node = true; /* default to 1 */
+module_param(on_node, bool, 0644);
+MODULE_PARM_DESC(on_node, "Run threads only on NTB device node (default: true)");
+
 struct perf_mw {
        phys_addr_t     phys_addr;
        resource_size_t phys_size;
@@ -135,9 +140,6 @@ struct perf_ctx {
        bool                    link_is_up;
        struct delayed_work     link_work;
        wait_queue_head_t       link_wq;
-       struct dentry           *debugfs_node_dir;
-       struct dentry           *debugfs_run;
-       struct dentry           *debugfs_threads;
        u8                      perf_threads;
        /* mutex ensures only one set of threads run at once */
        struct mutex            run_mutex;
@@ -344,6 +346,10 @@ static int perf_move_data(struct pthr_ctx *pctx, char __iomem *dst, char *src,
 
 static bool perf_dma_filter_fn(struct dma_chan *chan, void *node)
 {
+       /* Is the channel required to be on the same node as the device? */
+       if (!on_node)
+               return true;
+
        return dev_to_node(&chan->dev->device) == (int)(unsigned long)node;
 }
 
@@ -361,7 +367,7 @@ static int ntb_perf_thread(void *data)
 
        pr_debug("kthread %s starting...\n", current->comm);
 
-       node = dev_to_node(&pdev->dev);
+       node = on_node ? dev_to_node(&pdev->dev) : NUMA_NO_NODE;
 
        if (use_dma && !pctx->dma_chan) {
                dma_cap_mask_t dma_mask;
@@ -454,7 +460,7 @@ static void perf_free_mw(struct perf_ctx *perf)
        if (!mw->virt_addr)
                return;
 
-       ntb_mw_clear_trans(perf->ntb, 0);
+       ntb_mw_clear_trans(perf->ntb, PIDX, 0);
        dma_free_coherent(&pdev->dev, mw->buf_size,
                          mw->virt_addr, mw->dma_addr);
        mw->xlat_size = 0;
@@ -490,7 +496,7 @@ static int perf_set_mw(struct perf_ctx *perf, resource_size_t size)
                mw->buf_size = 0;
        }
 
-       rc = ntb_mw_set_trans(perf->ntb, 0, mw->dma_addr, mw->xlat_size);
+       rc = ntb_mw_set_trans(perf->ntb, PIDX, 0, mw->dma_addr, mw->xlat_size);
        if (rc) {
                dev_err(&perf->ntb->dev, "Unable to set mw0 translation\n");
                perf_free_mw(perf);
@@ -517,9 +523,9 @@ static void perf_link_work(struct work_struct *work)
        if (max_mw_size && size > max_mw_size)
                size = max_mw_size;
 
-       ntb_peer_spad_write(ndev, MW_SZ_HIGH, upper_32_bits(size));
-       ntb_peer_spad_write(ndev, MW_SZ_LOW, lower_32_bits(size));
-       ntb_peer_spad_write(ndev, VERSION, PERF_VERSION);
+       ntb_peer_spad_write(ndev, PIDX, MW_SZ_HIGH, upper_32_bits(size));
+       ntb_peer_spad_write(ndev, PIDX, MW_SZ_LOW, lower_32_bits(size));
+       ntb_peer_spad_write(ndev, PIDX, VERSION, PERF_VERSION);
 
        /* now read what peer wrote */
        val = ntb_spad_read(ndev, VERSION);
@@ -561,8 +567,12 @@ static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf)
 
        mw = &perf->mw;
 
-       rc = ntb_mw_get_range(ntb, 0, &mw->phys_addr, &mw->phys_size,
-                             &mw->xlat_align, &mw->xlat_align_size);
+       rc = ntb_mw_get_align(ntb, PIDX, 0, &mw->xlat_align,
+                             &mw->xlat_align_size, NULL);
+       if (rc)
+               return rc;
+
+       rc = ntb_peer_mw_get_addr(ntb, 0, &mw->phys_addr, &mw->phys_size);
        if (rc)
                return rc;
 
@@ -677,7 +687,8 @@ static ssize_t debugfs_run_write(struct file *filp, const char __user *ubuf,
                pr_info("Fix run_order to %u\n", run_order);
        }
 
-       node = dev_to_node(&perf->ntb->pdev->dev);
+       node = on_node ? dev_to_node(&perf->ntb->pdev->dev)
+                      : NUMA_NO_NODE;
        atomic_set(&perf->tdone, 0);
 
        /* launch kernel thread */
@@ -723,34 +734,71 @@ static const struct file_operations ntb_perf_debugfs_run = {
 static int perf_debugfs_setup(struct perf_ctx *perf)
 {
        struct pci_dev *pdev = perf->ntb->pdev;
+       struct dentry *debugfs_node_dir;
+       struct dentry *debugfs_run;
+       struct dentry *debugfs_threads;
+       struct dentry *debugfs_seg_order;
+       struct dentry *debugfs_run_order;
+       struct dentry *debugfs_use_dma;
+       struct dentry *debugfs_on_node;
 
        if (!debugfs_initialized())
                return -ENODEV;
 
+       /* Assumpion: only one NTB device in the system */
        if (!perf_debugfs_dir) {
                perf_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
                if (!perf_debugfs_dir)
                        return -ENODEV;
        }
 
-       perf->debugfs_node_dir = debugfs_create_dir(pci_name(pdev),
-                                                   perf_debugfs_dir);
-       if (!perf->debugfs_node_dir)
-               return -ENODEV;
+       debugfs_node_dir = debugfs_create_dir(pci_name(pdev),
+                                             perf_debugfs_dir);
+       if (!debugfs_node_dir)
+               goto err;
 
-       perf->debugfs_run = debugfs_create_file("run", S_IRUSR | S_IWUSR,
-                                               perf->debugfs_node_dir, perf,
-                                               &ntb_perf_debugfs_run);
-       if (!perf->debugfs_run)
-               return -ENODEV;
+       debugfs_run = debugfs_create_file("run", S_IRUSR | S_IWUSR,
+                                         debugfs_node_dir, perf,
+                                         &ntb_perf_debugfs_run);
+       if (!debugfs_run)
+               goto err;
 
-       perf->debugfs_threads = debugfs_create_u8("threads", S_IRUSR | S_IWUSR,
-                                                 perf->debugfs_node_dir,
-                                                 &perf->perf_threads);
-       if (!perf->debugfs_threads)
-               return -ENODEV;
+       debugfs_threads = debugfs_create_u8("threads", S_IRUSR | S_IWUSR,
+                                           debugfs_node_dir,
+                                           &perf->perf_threads);
+       if (!debugfs_threads)
+               goto err;
+
+       debugfs_seg_order = debugfs_create_u32("seg_order", 0600,
+                                              debugfs_node_dir,
+                                              &seg_order);
+       if (!debugfs_seg_order)
+               goto err;
+
+       debugfs_run_order = debugfs_create_u32("run_order", 0600,
+                                              debugfs_node_dir,
+                                              &run_order);
+       if (!debugfs_run_order)
+               goto err;
+
+       debugfs_use_dma = debugfs_create_bool("use_dma", 0600,
+                                              debugfs_node_dir,
+                                              &use_dma);
+       if (!debugfs_use_dma)
+               goto err;
+
+       debugfs_on_node = debugfs_create_bool("on_node", 0600,
+                                             debugfs_node_dir,
+                                             &on_node);
+       if (!debugfs_on_node)
+               goto err;
 
        return 0;
+
+err:
+       debugfs_remove_recursive(perf_debugfs_dir);
+       perf_debugfs_dir = NULL;
+       return -ENODEV;
 }
 
 static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
@@ -766,8 +814,15 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
                return -EIO;
        }
 
-       node = dev_to_node(&pdev->dev);
+       if (!ntb->ops->mw_set_trans) {
+               dev_err(&ntb->dev, "Need inbound MW based NTB API\n");
+               return -EINVAL;
+       }
+
+       if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT)
+               dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n");
 
+       node = on_node ? dev_to_node(&pdev->dev) : NUMA_NO_NODE;
        perf = kzalloc_node(sizeof(*perf), GFP_KERNEL, node);
        if (!perf) {
                rc = -ENOMEM;
index 4358611..938a18b 100644 (file)
@@ -90,6 +90,9 @@ static unsigned long db_init = 0x7;
 module_param(db_init, ulong, 0644);
 MODULE_PARM_DESC(db_init, "Initial doorbell bits to ring on the peer");
 
+/* Only two-ports NTB devices are supported */
+#define PIDX           NTB_DEF_PEER_IDX
+
 struct pp_ctx {
        struct ntb_dev                  *ntb;
        u64                             db_bits;
@@ -135,7 +138,7 @@ static void pp_ping(unsigned long ctx)
                        "Ping bits %#llx read %#x write %#x\n",
                        db_bits, spad_rd, spad_wr);
 
-               ntb_peer_spad_write(pp->ntb, 0, spad_wr);
+               ntb_peer_spad_write(pp->ntb, PIDX, 0, spad_wr);
                ntb_peer_db_set(pp->ntb, db_bits);
                ntb_db_clear_mask(pp->ntb, db_mask);
 
@@ -222,6 +225,12 @@ static int pp_probe(struct ntb_client *client,
                }
        }
 
+       if (ntb_spad_count(ntb) < 1) {
+               dev_dbg(&ntb->dev, "no enough scratchpads\n");
+               rc = -EINVAL;
+               goto err_pp;
+       }
+
        if (ntb_spad_is_unsafe(ntb)) {
                dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
                if (!unsafe) {
@@ -230,6 +239,9 @@ static int pp_probe(struct ntb_client *client,
                }
        }
 
+       if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT)
+               dev_warn(&ntb->dev, "multi-port NTB is unsupported\n");
+
        pp = kmalloc(sizeof(*pp), GFP_KERNEL);
        if (!pp) {
                rc = -ENOMEM;
index 61bf2ef..f002bf4 100644 (file)
@@ -119,7 +119,10 @@ MODULE_VERSION(DRIVER_VERSION);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
 
-#define MAX_MWS 16
+/* It is rare to have hadrware with greater than six MWs */
+#define MAX_MWS        6
+/* Only two-ports devices are supported */
+#define PIDX   NTB_DEF_PEER_IDX
 
 static struct dentry *tool_dbgfs;
 
@@ -459,13 +462,22 @@ static TOOL_FOPS_RDWR(tool_spad_fops,
                      tool_spad_read,
                      tool_spad_write);
 
+static u32 ntb_tool_peer_spad_read(struct ntb_dev *ntb, int sidx)
+{
+       return ntb_peer_spad_read(ntb, PIDX, sidx);
+}
+
 static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
                                   size_t size, loff_t *offp)
 {
        struct tool_ctx *tc = filep->private_data;
 
-       return tool_spadfn_read(tc, ubuf, size, offp,
-                               tc->ntb->ops->peer_spad_read);
+       return tool_spadfn_read(tc, ubuf, size, offp, ntb_tool_peer_spad_read);
+}
+
+static int ntb_tool_peer_spad_write(struct ntb_dev *ntb, int sidx, u32 val)
+{
+       return ntb_peer_spad_write(ntb, PIDX, sidx, val);
 }
 
 static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
@@ -474,7 +486,7 @@ static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
        struct tool_ctx *tc = filep->private_data;
 
        return tool_spadfn_write(tc, ubuf, size, offp,
-                                tc->ntb->ops->peer_spad_write);
+                                ntb_tool_peer_spad_write);
 }
 
 static TOOL_FOPS_RDWR(tool_peer_spad_fops,
@@ -668,28 +680,27 @@ static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size)
 {
        int rc;
        struct tool_mw *mw = &tc->mws[idx];
-       phys_addr_t base;
-       resource_size_t size, align, align_size;
+       resource_size_t size, align_addr, align_size;
        char buf[16];
 
        if (mw->peer)
                return 0;
 
-       rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align,
-                             &align_size);
+       rc = ntb_mw_get_align(tc->ntb, PIDX, idx, &align_addr,
+                               &align_size, &size);
        if (rc)
                return rc;
 
        mw->size = min_t(resource_size_t, req_size, size);
-       mw->size = round_up(mw->size, align);
+       mw->size = round_up(mw->size, align_addr);
        mw->size = round_up(mw->size, align_size);
        mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
                                      &mw->peer_dma, GFP_KERNEL);
 
-       if (!mw->peer)
+       if (!mw->peer || !IS_ALIGNED(mw->peer_dma, align_addr))
                return -ENOMEM;
 
-       rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size);
+       rc = ntb_mw_set_trans(tc->ntb, PIDX, idx, mw->peer_dma, mw->size);
        if (rc)
                goto err_free_dma;
 
@@ -716,7 +727,7 @@ static void tool_free_mw(struct tool_ctx *tc, int idx)
        struct tool_mw *mw = &tc->mws[idx];
 
        if (mw->peer) {
-               ntb_mw_clear_trans(tc->ntb, idx);
+               ntb_mw_clear_trans(tc->ntb, PIDX, idx);
                dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
                                  mw->peer,
                                  mw->peer_dma);
@@ -742,8 +753,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
 
        phys_addr_t base;
        resource_size_t mw_size;
-       resource_size_t align;
+       resource_size_t align_addr;
        resource_size_t align_size;
+       resource_size_t max_size;
 
        buf_size = min_t(size_t, size, 512);
 
@@ -751,8 +763,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
        if (!buf)
                return -ENOMEM;
 
-       ntb_mw_get_range(mw->tc->ntb, mw->idx,
-                        &base, &mw_size, &align, &align_size);
+       ntb_mw_get_align(mw->tc->ntb, PIDX, mw->idx,
+                        &align_addr, &align_size, &max_size);
+       ntb_peer_mw_get_addr(mw->tc->ntb, mw->idx, &base, &mw_size);
 
        off += scnprintf(buf + off, buf_size - off,
                         "Peer MW %d Information:\n", mw->idx);
@@ -767,13 +780,17 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
 
        off += scnprintf(buf + off, buf_size - off,
                         "Alignment             \t%lld\n",
-                        (unsigned long long)align);
+                        (unsigned long long)align_addr);
 
        off += scnprintf(buf + off, buf_size - off,
                         "Size Alignment        \t%lld\n",
                         (unsigned long long)align_size);
 
        off += scnprintf(buf + off, buf_size - off,
+                        "Size Max              \t%lld\n",
+                        (unsigned long long)max_size);
+
+       off += scnprintf(buf + off, buf_size - off,
                         "Ready                 \t%c\n",
                         (mw->peer) ? 'Y' : 'N');
 
@@ -827,8 +844,7 @@ static int tool_init_mw(struct tool_ctx *tc, int idx)
        phys_addr_t base;
        int rc;
 
-       rc = ntb_mw_get_range(tc->ntb, idx, &base, &mw->win_size,
-                             NULL, NULL);
+       rc = ntb_peer_mw_get_addr(tc->ntb, idx, &base, &mw->win_size);
        if (rc)
                return rc;
 
@@ -913,12 +929,27 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
        int rc;
        int i;
 
+       if (!ntb->ops->mw_set_trans) {
+               dev_dbg(&ntb->dev, "need inbound MW based NTB API\n");
+               rc = -EINVAL;
+               goto err_tc;
+       }
+
+       if (ntb_spad_count(ntb) < 1) {
+               dev_dbg(&ntb->dev, "no enough scratchpads\n");
+               rc = -EINVAL;
+               goto err_tc;
+       }
+
        if (ntb_db_is_unsafe(ntb))
                dev_dbg(&ntb->dev, "doorbell is unsafe\n");
 
        if (ntb_spad_is_unsafe(ntb))
                dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
 
+       if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT)
+               dev_warn(&ntb->dev, "multi-port NTB is unsupported\n");
+
        tc = kzalloc(sizeof(*tc), GFP_KERNEL);
        if (!tc) {
                rc = -ENOMEM;
@@ -928,7 +959,7 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
        tc->ntb = ntb;
        init_waitqueue_head(&tc->link_wq);
 
-       tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS);
+       tc->mw_count = min(ntb_mw_count(tc->ntb, PIDX), MAX_MWS);
        for (i = 0; i < tc->mw_count; i++) {
                rc = tool_init_mw(tc, i);
                if (rc)
index 7cd99b1..75bc08c 100644 (file)
@@ -421,14 +421,15 @@ static void set_badblock(struct badblocks *bb, sector_t s, int num)
 static void __add_badblock_range(struct badblocks *bb, u64 ns_offset, u64 len)
 {
        const unsigned int sector_size = 512;
-       sector_t start_sector;
+       sector_t start_sector, end_sector;
        u64 num_sectors;
        u32 rem;
 
        start_sector = div_u64(ns_offset, sector_size);
-       num_sectors = div_u64_rem(len, sector_size, &rem);
+       end_sector = div_u64_rem(ns_offset + len, sector_size, &rem);
        if (rem)
-               num_sectors++;
+               end_sector++;
+       num_sectors = end_sector - start_sector;
 
        if (unlikely(num_sectors > (u64)INT_MAX)) {
                u64 remaining = num_sectors;
index cb96f4a..c49f1f8 100644 (file)
@@ -336,7 +336,7 @@ static int nvme_get_stream_params(struct nvme_ctrl *ctrl,
 
        c.directive.opcode = nvme_admin_directive_recv;
        c.directive.nsid = cpu_to_le32(nsid);
-       c.directive.numd = sizeof(*s);
+       c.directive.numd = cpu_to_le32(sizeof(*s));
        c.directive.doper = NVME_DIR_RCV_ST_OP_PARAM;
        c.directive.dtype = NVME_DIR_STREAMS;
 
@@ -1995,6 +1995,9 @@ static ssize_t wwid_show(struct device *dev, struct device_attribute *attr,
        int serial_len = sizeof(ctrl->serial);
        int model_len = sizeof(ctrl->model);
 
+       if (!uuid_is_null(&ns->uuid))
+               return sprintf(buf, "uuid.%pU\n", &ns->uuid);
+
        if (memchr_inv(ns->nguid, 0, sizeof(ns->nguid)))
                return sprintf(buf, "eui.%16phN\n", ns->nguid);
 
@@ -2709,7 +2712,8 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl)
        mutex_lock(&ctrl->namespaces_mutex);
 
        /* Forcibly unquiesce queues to avoid blocking dispatch */
-       blk_mq_unquiesce_queue(ctrl->admin_q);
+       if (ctrl->admin_q)
+               blk_mq_unquiesce_queue(ctrl->admin_q);
 
        list_for_each_entry(ns, &ctrl->namespaces, list) {
                /*
index d666ada..5c2a08e 100644 (file)
@@ -1888,7 +1888,7 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue,
         * the target device is present
         */
        if (ctrl->rport->remoteport.port_state != FC_OBJSTATE_ONLINE)
-               return BLK_STS_IOERR;
+               goto busy;
 
        if (!nvme_fc_ctrl_get(ctrl))
                return BLK_STS_IOERR;
@@ -1958,22 +1958,25 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue,
                                        queue->lldd_handle, &op->fcp_req);
 
        if (ret) {
-               if (op->rq)                     /* normal request */
+               if (!(op->flags & FCOP_FLAGS_AEN))
                        nvme_fc_unmap_data(ctrl, op->rq, op);
-               /* else - aen. no cleanup needed */
 
                nvme_fc_ctrl_put(ctrl);
 
-               if (ret != -EBUSY)
+               if (ctrl->rport->remoteport.port_state == FC_OBJSTATE_ONLINE &&
+                               ret != -EBUSY)
                        return BLK_STS_IOERR;
 
-               if (op->rq)
-                       blk_mq_delay_run_hw_queue(queue->hctx, NVMEFC_QUEUE_DELAY);
-
-               return BLK_STS_RESOURCE;
+               goto busy;
        }
 
        return BLK_STS_OK;
+
+busy:
+       if (!(op->flags & FCOP_FLAGS_AEN) && queue->hctx)
+               blk_mq_delay_run_hw_queue(queue->hctx, NVMEFC_QUEUE_DELAY);
+
+       return BLK_STS_RESOURCE;
 }
 
 static blk_status_t
@@ -2802,66 +2805,70 @@ out_fail:
        return ERR_PTR(ret);
 }
 
-enum {
-       FCT_TRADDR_ERR          = 0,
-       FCT_TRADDR_WWNN         = 1 << 0,
-       FCT_TRADDR_WWPN         = 1 << 1,
-};
 
 struct nvmet_fc_traddr {
        u64     nn;
        u64     pn;
 };
 
-static const match_table_t traddr_opt_tokens = {
-       { FCT_TRADDR_WWNN,      "nn-%s"         },
-       { FCT_TRADDR_WWPN,      "pn-%s"         },
-       { FCT_TRADDR_ERR,       NULL            }
-};
-
 static int
-nvme_fc_parse_address(struct nvmet_fc_traddr *traddr, char *buf)
+__nvme_fc_parse_u64(substring_t *sstr, u64 *val)
 {
-       substring_t args[MAX_OPT_ARGS];
-       char *options, *o, *p;
-       int token, ret = 0;
        u64 token64;
 
-       options = o = kstrdup(buf, GFP_KERNEL);
-       if (!options)
-               return -ENOMEM;
+       if (match_u64(sstr, &token64))
+               return -EINVAL;
+       *val = token64;
 
-       while ((p = strsep(&o, ":\n")) != NULL) {
-               if (!*p)
-                       continue;
+       return 0;
+}
 
-               token = match_token(p, traddr_opt_tokens, args);
-               switch (token) {
-               case FCT_TRADDR_WWNN:
-                       if (match_u64(args, &token64)) {
-                               ret = -EINVAL;
-                               goto out;
-                       }
-                       traddr->nn = token64;
-                       break;
-               case FCT_TRADDR_WWPN:
-                       if (match_u64(args, &token64)) {
-                               ret = -EINVAL;
-                               goto out;
-                       }
-                       traddr->pn = token64;
-                       break;
-               default:
-                       pr_warn("unknown traddr token or missing value '%s'\n",
-                                       p);
-                       ret = -EINVAL;
-                       goto out;
-               }
-       }
+/*
+ * This routine validates and extracts the WWN's from the TRADDR string.
+ * As kernel parsers need the 0x to determine number base, universally
+ * build string to parse with 0x prefix before parsing name strings.
+ */
+static int
+nvme_fc_parse_traddr(struct nvmet_fc_traddr *traddr, char *buf, size_t blen)
+{
+       char name[2 + NVME_FC_TRADDR_HEXNAMELEN + 1];
+       substring_t wwn = { name, &name[sizeof(name)-1] };
+       int nnoffset, pnoffset;
+
+       /* validate it string one of the 2 allowed formats */
+       if (strnlen(buf, blen) == NVME_FC_TRADDR_MAXLENGTH &&
+                       !strncmp(buf, "nn-0x", NVME_FC_TRADDR_OXNNLEN) &&
+                       !strncmp(&buf[NVME_FC_TRADDR_MAX_PN_OFFSET],
+                               "pn-0x", NVME_FC_TRADDR_OXNNLEN)) {
+               nnoffset = NVME_FC_TRADDR_OXNNLEN;
+               pnoffset = NVME_FC_TRADDR_MAX_PN_OFFSET +
+                                               NVME_FC_TRADDR_OXNNLEN;
+       } else if ((strnlen(buf, blen) == NVME_FC_TRADDR_MINLENGTH &&
+                       !strncmp(buf, "nn-", NVME_FC_TRADDR_NNLEN) &&
+                       !strncmp(&buf[NVME_FC_TRADDR_MIN_PN_OFFSET],
+                               "pn-", NVME_FC_TRADDR_NNLEN))) {
+               nnoffset = NVME_FC_TRADDR_NNLEN;
+               pnoffset = NVME_FC_TRADDR_MIN_PN_OFFSET + NVME_FC_TRADDR_NNLEN;
+       } else
+               goto out_einval;
 
-out:
-       kfree(options);
-       return ret;
+       name[0] = '0';
+       name[1] = 'x';
+       name[2 + NVME_FC_TRADDR_HEXNAMELEN] = 0;
+
+       memcpy(&name[2], &buf[nnoffset], NVME_FC_TRADDR_HEXNAMELEN);
+       if (__nvme_fc_parse_u64(&wwn, &traddr->nn))
+               goto out_einval;
+
+       memcpy(&name[2], &buf[pnoffset], NVME_FC_TRADDR_HEXNAMELEN);
+       if (__nvme_fc_parse_u64(&wwn, &traddr->pn))
+               goto out_einval;
+
+       return 0;
+
+out_einval:
+       pr_warn("%s: bad traddr string\n", __func__);
+       return -EINVAL;
 }
 
 static struct nvme_ctrl *
@@ -2875,11 +2882,11 @@ nvme_fc_create_ctrl(struct device *dev, struct nvmf_ctrl_options *opts)
        unsigned long flags;
        int ret;
 
-       ret = nvme_fc_parse_address(&raddr, opts->traddr);
+       ret = nvme_fc_parse_traddr(&raddr, opts->traddr, NVMF_TRADDR_SIZE);
        if (ret || !raddr.nn || !raddr.pn)
                return ERR_PTR(-EINVAL);
 
-       ret = nvme_fc_parse_address(&laddr, opts->host_traddr);
+       ret = nvme_fc_parse_traddr(&laddr, opts->host_traddr, NVMF_TRADDR_SIZE);
        if (ret || !laddr.nn || !laddr.pn)
                return ERR_PTR(-EINVAL);
 
index d10d2f2..cd888a4 100644 (file)
@@ -539,7 +539,7 @@ static void nvme_dif_complete(u32 p, u32 v, struct t10_pi_tuple *pi)
 }
 #endif
 
-static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
+static blk_status_t nvme_setup_prps(struct nvme_dev *dev, struct request *req)
 {
        struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
        struct dma_pool *pool;
@@ -556,7 +556,7 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
 
        length -= (page_size - offset);
        if (length <= 0)
-               return true;
+               return BLK_STS_OK;
 
        dma_len -= (page_size - offset);
        if (dma_len) {
@@ -569,7 +569,7 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
 
        if (length <= page_size) {
                iod->first_dma = dma_addr;
-               return true;
+               return BLK_STS_OK;
        }
 
        nprps = DIV_ROUND_UP(length, page_size);
@@ -585,7 +585,7 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
        if (!prp_list) {
                iod->first_dma = dma_addr;
                iod->npages = -1;
-               return false;
+               return BLK_STS_RESOURCE;
        }
        list[0] = prp_list;
        iod->first_dma = prp_dma;
@@ -595,7 +595,7 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
                        __le64 *old_prp_list = prp_list;
                        prp_list = dma_pool_alloc(pool, GFP_ATOMIC, &prp_dma);
                        if (!prp_list)
-                               return false;
+                               return BLK_STS_RESOURCE;
                        list[iod->npages++] = prp_list;
                        prp_list[0] = old_prp_list[i - 1];
                        old_prp_list[i - 1] = cpu_to_le64(prp_dma);
@@ -609,13 +609,29 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
                        break;
                if (dma_len > 0)
                        continue;
-               BUG_ON(dma_len < 0);
+               if (unlikely(dma_len < 0))
+                       goto bad_sgl;
                sg = sg_next(sg);
                dma_addr = sg_dma_address(sg);
                dma_len = sg_dma_len(sg);
        }
 
-       return true;
+       return BLK_STS_OK;
+
+ bad_sgl:
+       if (WARN_ONCE(1, "Invalid SGL for payload:%d nents:%d\n",
+                               blk_rq_payload_bytes(req), iod->nents)) {
+               for_each_sg(iod->sg, sg, iod->nents, i) {
+                       dma_addr_t phys = sg_phys(sg);
+                       pr_warn("sg[%d] phys_addr:%pad offset:%d length:%d "
+                              "dma_address:%pad dma_length:%d\n", i, &phys,
+                                       sg->offset, sg->length,
+                                       &sg_dma_address(sg),
+                                       sg_dma_len(sg));
+               }
+       }
+       return BLK_STS_IOERR;
+
 }
 
 static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
@@ -637,7 +653,8 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
                                DMA_ATTR_NO_WARN))
                goto out;
 
-       if (!nvme_setup_prps(dev, req))
+       ret = nvme_setup_prps(dev, req);
+       if (ret != BLK_STS_OK)
                goto out_unmap;
 
        ret = BLK_STS_IOERR;
@@ -1602,7 +1619,7 @@ static void nvme_free_host_mem(struct nvme_dev *dev)
 static int nvme_alloc_host_mem(struct nvme_dev *dev, u64 min, u64 preferred)
 {
        struct nvme_host_mem_buf_desc *descs;
-       u32 chunk_size, max_entries;
+       u32 chunk_size, max_entries, len;
        int i = 0;
        void **bufs;
        u64 size = 0, tmp;
@@ -1621,10 +1638,10 @@ retry:
        if (!bufs)
                goto out_free_descs;
 
-       for (size = 0; size < preferred; size += chunk_size) {
-               u32 len = min_t(u64, chunk_size, preferred - size);
+       for (size = 0; size < preferred; size += len) {
                dma_addr_t dma_addr;
 
+               len = min_t(u64, chunk_size, preferred - size);
                bufs[i] = dma_alloc_attrs(dev->dev, len, &dma_addr, GFP_KERNEL,
                                DMA_ATTR_NO_KERNEL_MAPPING | DMA_ATTR_NO_WARN);
                if (!bufs[i])
@@ -2282,7 +2299,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        result = nvme_dev_map(dev);
        if (result)
-               goto free;
+               goto put_pci;
 
        INIT_WORK(&dev->ctrl.reset_work, nvme_reset_work);
        INIT_WORK(&dev->remove_work, nvme_remove_dead_ctrl_work);
@@ -2291,7 +2308,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        result = nvme_setup_prp_pools(dev);
        if (result)
-               goto put_pci;
+               goto unmap;
 
        quirks |= check_dell_samsung_bug(pdev);
 
@@ -2308,9 +2325,10 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
  release_pools:
        nvme_release_prp_pools(dev);
+ unmap:
+       nvme_dev_unmap(dev);
  put_pci:
        put_device(dev->dev);
-       nvme_dev_unmap(dev);
  free:
        kfree(dev->queues);
        kfree(dev);
@@ -2466,6 +2484,9 @@ static const struct pci_device_id nvme_id_table[] = {
        { PCI_VDEVICE(INTEL, 0x0a54),
                .driver_data = NVME_QUIRK_STRIPE_SIZE |
                                NVME_QUIRK_DEALLOCATE_ZEROES, },
+       { PCI_VDEVICE(INTEL, 0x0a55),
+               .driver_data = NVME_QUIRK_STRIPE_SIZE |
+                               NVME_QUIRK_DEALLOCATE_ZEROES, },
        { PCI_VDEVICE(INTEL, 0xf1a5),   /* Intel 600P/P3100 */
                .driver_data = NVME_QUIRK_NO_DEEPEST_PS },
        { PCI_VDEVICE(INTEL, 0x5845),   /* Qemu emulated controller */
index 35f930d..2d7a98a 100644 (file)
@@ -168,11 +168,21 @@ out:
        nvmet_req_complete(req, status);
 }
 
+static void copy_and_pad(char *dst, int dst_len, const char *src, int src_len)
+{
+       int len = min(src_len, dst_len);
+
+       memcpy(dst, src, len);
+       if (dst_len > len)
+               memset(dst + len, ' ', dst_len - len);
+}
+
 static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 {
        struct nvmet_ctrl *ctrl = req->sq->ctrl;
        struct nvme_id_ctrl *id;
        u16 status = 0;
+       const char model[] = "Linux";
 
        id = kzalloc(sizeof(*id), GFP_KERNEL);
        if (!id) {
@@ -184,8 +194,10 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
        id->vid = 0;
        id->ssvid = 0;
 
-       memset(id->sn, ' ', sizeof(id->sn));
-       snprintf(id->sn, sizeof(id->sn), "%llx", ctrl->serial);
+       bin2hex(id->sn, &ctrl->subsys->serial,
+               min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
+       copy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1);
+       copy_and_pad(id->fr, sizeof(id->fr), UTS_RELEASE, strlen(UTS_RELEASE));
 
        memset(id->mn, ' ', sizeof(id->mn));
        strncpy((char *)id->mn, "Linux", sizeof(id->mn));
index a358ecd..0a0067e 100644 (file)
@@ -650,7 +650,7 @@ out_unlock:
 
 CONFIGFS_ATTR(nvmet_subsys_, attr_allow_any_host);
 
-static ssize_t nvmet_subsys_version_show(struct config_item *item,
+static ssize_t nvmet_subsys_attr_version_show(struct config_item *item,
                                              char *page)
 {
        struct nvmet_subsys *subsys = to_subsys(item);
@@ -666,7 +666,7 @@ static ssize_t nvmet_subsys_version_show(struct config_item *item,
                                (int)NVME_MINOR(subsys->ver));
 }
 
-static ssize_t nvmet_subsys_version_store(struct config_item *item,
+static ssize_t nvmet_subsys_attr_version_store(struct config_item *item,
                                               const char *page, size_t count)
 {
        struct nvmet_subsys *subsys = to_subsys(item);
@@ -684,11 +684,33 @@ static ssize_t nvmet_subsys_version_store(struct config_item *item,
 
        return count;
 }
-CONFIGFS_ATTR(nvmet_subsys_, version);
+CONFIGFS_ATTR(nvmet_subsys_, attr_version);
+
+static ssize_t nvmet_subsys_attr_serial_show(struct config_item *item,
+                                            char *page)
+{
+       struct nvmet_subsys *subsys = to_subsys(item);
+
+       return snprintf(page, PAGE_SIZE, "%llx\n", subsys->serial);
+}
+
+static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
+                                             const char *page, size_t count)
+{
+       struct nvmet_subsys *subsys = to_subsys(item);
+
+       down_write(&nvmet_config_sem);
+       sscanf(page, "%llx\n", &subsys->serial);
+       up_write(&nvmet_config_sem);
+
+       return count;
+}
+CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
 
 static struct configfs_attribute *nvmet_subsys_attrs[] = {
        &nvmet_subsys_attr_attr_allow_any_host,
-       &nvmet_subsys_attr_version,
+       &nvmet_subsys_attr_attr_version,
+       &nvmet_subsys_attr_attr_serial,
        NULL,
 };
 
index b5b4ac1..f4b02bb 100644 (file)
@@ -767,9 +767,6 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
        memcpy(ctrl->subsysnqn, subsysnqn, NVMF_NQN_SIZE);
        memcpy(ctrl->hostnqn, hostnqn, NVMF_NQN_SIZE);
 
-       /* generate a random serial number as our controllers are ephemeral: */
-       get_random_bytes(&ctrl->serial, sizeof(ctrl->serial));
-
        kref_init(&ctrl->ref);
        ctrl->subsys = subsys;
 
@@ -928,6 +925,8 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
                return NULL;
 
        subsys->ver = NVME_VS(1, 3, 0); /* NVMe 1.3.0 */
+       /* generate a random serial number as our controllers are ephemeral: */
+       get_random_bytes(&subsys->serial, sizeof(subsys->serial));
 
        switch (type) {
        case NVME_NQN_NVME:
index 1e6dcc2..31ca55d 100644 (file)
@@ -1174,14 +1174,14 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport,
         */
        if (iod->rqstdatalen < FCNVME_LSDESC_CRA_RQST_MINLEN)
                ret = VERR_CR_ASSOC_LEN;
-       else if (rqst->desc_list_len <
-                       cpu_to_be32(FCNVME_LSDESC_CRA_RQST_MIN_LISTLEN))
+       else if (be32_to_cpu(rqst->desc_list_len) <
+                       FCNVME_LSDESC_CRA_RQST_MIN_LISTLEN)
                ret = VERR_CR_ASSOC_RQST_LEN;
        else if (rqst->assoc_cmd.desc_tag !=
                        cpu_to_be32(FCNVME_LSDESC_CREATE_ASSOC_CMD))
                ret = VERR_CR_ASSOC_CMD;
-       else if (rqst->assoc_cmd.desc_len <
-                       cpu_to_be32(FCNVME_LSDESC_CRA_CMD_DESC_MIN_DESCLEN))
+       else if (be32_to_cpu(rqst->assoc_cmd.desc_len) <
+                       FCNVME_LSDESC_CRA_CMD_DESC_MIN_DESCLEN)
                ret = VERR_CR_ASSOC_CMD_LEN;
        else if (!rqst->assoc_cmd.ersp_ratio ||
                 (be16_to_cpu(rqst->assoc_cmd.ersp_ratio) >=
@@ -2293,66 +2293,70 @@ nvmet_fc_rcv_fcp_abort(struct nvmet_fc_target_port *target_port,
 }
 EXPORT_SYMBOL_GPL(nvmet_fc_rcv_fcp_abort);
 
-enum {
-       FCT_TRADDR_ERR          = 0,
-       FCT_TRADDR_WWNN         = 1 << 0,
-       FCT_TRADDR_WWPN         = 1 << 1,
-};
 
 struct nvmet_fc_traddr {
        u64     nn;
        u64     pn;
 };
 
-static const match_table_t traddr_opt_tokens = {
-       { FCT_TRADDR_WWNN,      "nn-%s"         },
-       { FCT_TRADDR_WWPN,      "pn-%s"         },
-       { FCT_TRADDR_ERR,       NULL            }
-};
-
 static int
-nvmet_fc_parse_traddr(struct nvmet_fc_traddr *traddr, char *buf)
+__nvme_fc_parse_u64(substring_t *sstr, u64 *val)
 {
-       substring_t args[MAX_OPT_ARGS];
-       char *options, *o, *p;
-       int token, ret = 0;
        u64 token64;
 
-       options = o = kstrdup(buf, GFP_KERNEL);
-       if (!options)
-               return -ENOMEM;
+       if (match_u64(sstr, &token64))
+               return -EINVAL;
+       *val = token64;
 
-       while ((p = strsep(&o, ":\n")) != NULL) {
-               if (!*p)
-                       continue;
+       return 0;
+}
 
-               token = match_token(p, traddr_opt_tokens, args);
-               switch (token) {
-               case FCT_TRADDR_WWNN:
-                       if (match_u64(args, &token64)) {
-                               ret = -EINVAL;
-                               goto out;
-                       }
-                       traddr->nn = token64;
-                       break;
-               case FCT_TRADDR_WWPN:
-                       if (match_u64(args, &token64)) {
-                               ret = -EINVAL;
-                               goto out;
-                       }
-                       traddr->pn = token64;
-                       break;
-               default:
-                       pr_warn("unknown traddr token or missing value '%s'\n",
-                                       p);
-                       ret = -EINVAL;
-                       goto out;
-               }
-       }
+/*
+ * This routine validates and extracts the WWN's from the TRADDR string.
+ * As kernel parsers need the 0x to determine number base, universally
+ * build string to parse with 0x prefix before parsing name strings.
+ */
+static int
+nvme_fc_parse_traddr(struct nvmet_fc_traddr *traddr, char *buf, size_t blen)
+{
+       char name[2 + NVME_FC_TRADDR_HEXNAMELEN + 1];
+       substring_t wwn = { name, &name[sizeof(name)-1] };
+       int nnoffset, pnoffset;
+
+       /* validate it string one of the 2 allowed formats */
+       if (strnlen(buf, blen) == NVME_FC_TRADDR_MAXLENGTH &&
+                       !strncmp(buf, "nn-0x", NVME_FC_TRADDR_OXNNLEN) &&
+                       !strncmp(&buf[NVME_FC_TRADDR_MAX_PN_OFFSET],
+                               "pn-0x", NVME_FC_TRADDR_OXNNLEN)) {
+               nnoffset = NVME_FC_TRADDR_OXNNLEN;
+               pnoffset = NVME_FC_TRADDR_MAX_PN_OFFSET +
+                                               NVME_FC_TRADDR_OXNNLEN;
+       } else if ((strnlen(buf, blen) == NVME_FC_TRADDR_MINLENGTH &&
+                       !strncmp(buf, "nn-", NVME_FC_TRADDR_NNLEN) &&
+                       !strncmp(&buf[NVME_FC_TRADDR_MIN_PN_OFFSET],
+                               "pn-", NVME_FC_TRADDR_NNLEN))) {
+               nnoffset = NVME_FC_TRADDR_NNLEN;
+               pnoffset = NVME_FC_TRADDR_MIN_PN_OFFSET + NVME_FC_TRADDR_NNLEN;
+       } else
+               goto out_einval;
+
+       name[0] = '0';
+       name[1] = 'x';
+       name[2 + NVME_FC_TRADDR_HEXNAMELEN] = 0;
+
+       memcpy(&name[2], &buf[nnoffset], NVME_FC_TRADDR_HEXNAMELEN);
+       if (__nvme_fc_parse_u64(&wwn, &traddr->nn))
+               goto out_einval;
+
+       memcpy(&name[2], &buf[pnoffset], NVME_FC_TRADDR_HEXNAMELEN);
+       if (__nvme_fc_parse_u64(&wwn, &traddr->pn))
+               goto out_einval;
 
-out:
-       kfree(options);
-       return ret;
+       return 0;
+
+out_einval:
+       pr_warn("%s: bad traddr string\n", __func__);
+       return -EINVAL;
 }
 
 static int
@@ -2370,7 +2374,8 @@ nvmet_fc_add_port(struct nvmet_port *port)
 
        /* map the traddr address info to a target port */
 
-       ret = nvmet_fc_parse_traddr(&traddr, port->disc_addr.traddr);
+       ret = nvme_fc_parse_traddr(&traddr, port->disc_addr.traddr,
+                       sizeof(port->disc_addr.traddr));
        if (ret)
                return ret;
 
index 747bbdb..e3b244c 100644 (file)
@@ -112,7 +112,6 @@ struct nvmet_ctrl {
 
        struct mutex            lock;
        u64                     cap;
-       u64                     serial;
        u32                     cc;
        u32                     csts;
 
@@ -152,6 +151,7 @@ struct nvmet_subsys {
        u16                     max_qid;
 
        u64                     ver;
+       u64                     serial;
        char                    *subsysnqn;
 
        struct config_group     group;
index a0d4ede..63e3eb5 100644 (file)
@@ -170,7 +170,7 @@ static const struct of_device_id rockchip_efuse_match[] = {
                .data = (void *)&rockchip_rk3288_efuse_read,
        },
        {
-               .compatible = "rockchip,rk322x-efuse",
+               .compatible = "rockchip,rk3228-efuse",
                .data = (void *)&rockchip_rk3288_efuse_read,
        },
        {
index 6ce72aa..ab21c84 100644 (file)
@@ -476,7 +476,7 @@ int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
        int i;
 
        for (i = 0; i < nr_irqs; i++, res++)
-               if (!of_irq_to_resource(dev, i, res))
+               if (of_irq_to_resource(dev, i, res) <= 0)
                        break;
 
        return i;
index e0dbd6e..a0d27c0 100644 (file)
@@ -422,13 +422,11 @@ int of_phy_register_fixed_link(struct device_node *np)
        struct fixed_phy_status status = {};
        struct device_node *fixed_link_node;
        const __be32 *fixed_link_prop;
-       int link_gpio;
-       int len, err;
        struct phy_device *phy;
        const char *managed;
+       int link_gpio, len;
 
-       err = of_property_read_string(np, "managed", &managed);
-       if (err == 0) {
+       if (of_property_read_string(np, "managed", &managed) == 0) {
                if (strcmp(managed, "in-band-status") == 0) {
                        /* status is zeroed, namely its .link member */
                        phy = fixed_phy_register(PHY_POLL, &status, -1, np);
index 055f83f..7147aa5 100644 (file)
@@ -954,7 +954,7 @@ static struct attribute *pdcs_subsys_attrs[] = {
        NULL,
 };
 
-static struct attribute_group pdcs_attr_group = {
+static const struct attribute_group pdcs_attr_group = {
        .attrs = pdcs_subsys_attrs,
 };
 
index 5acf869..7bb9870 100644 (file)
@@ -1483,7 +1483,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
        bridge->swizzle_irq = pci_common_swizzle;
 
        err = pci_scan_root_bus_bridge(bridge);
-       if (!err)
+       if (err < 0)
                goto err_free_res;
 
        bus = bridge->bus;
index 607f677..d51e873 100644 (file)
@@ -511,6 +511,7 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
        }
 
        pci_restore_state(pci_dev);
+       pci_pme_restore(pci_dev);
        return 0;
 }
 
@@ -522,6 +523,7 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
 {
        pci_power_up(pci_dev);
        pci_restore_state(pci_dev);
+       pci_pme_restore(pci_dev);
        pci_fixup_device(pci_fixup_resume_early, pci_dev);
 }
 
index d88edf5..af0cc34 100644 (file)
@@ -1801,7 +1801,11 @@ static void __pci_pme_active(struct pci_dev *dev, bool enable)
        pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
 }
 
-static void pci_pme_restore(struct pci_dev *dev)
+/**
+ * pci_pme_restore - Restore PME configuration after config space restore.
+ * @dev: PCI device to update.
+ */
+void pci_pme_restore(struct pci_dev *dev)
 {
        u16 pmcsr;
 
@@ -1811,6 +1815,7 @@ static void pci_pme_restore(struct pci_dev *dev)
        pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
        if (dev->wakeup_prepared) {
                pmcsr |= PCI_PM_CTRL_PME_ENABLE;
+               pmcsr &= ~PCI_PM_CTRL_PME_STATUS;
        } else {
                pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
                pmcsr |= PCI_PM_CTRL_PME_STATUS;
@@ -1907,14 +1912,9 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
 {
        int ret = 0;
 
-       /*
-        * Don't do the same thing twice in a row for one device, but restore
-        * PME Enable in case it has been updated by config space restoration.
-        */
-       if (!!enable == !!dev->wakeup_prepared) {
-               pci_pme_restore(dev);
+       /* Don't do the same thing twice in a row for one device. */
+       if (!!enable == !!dev->wakeup_prepared)
                return 0;
-       }
 
        /*
         * According to "PCI System Architecture" 4th ed. by Tom Shanley & Don
index 03e3d02..22e0617 100644 (file)
@@ -71,6 +71,7 @@ void pci_power_up(struct pci_dev *dev);
 void pci_disable_enabled_device(struct pci_dev *dev);
 int pci_finish_runtime_suspend(struct pci_dev *dev);
 int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
+void pci_pme_restore(struct pci_dev *dev);
 bool pci_dev_keep_suspended(struct pci_dev *dev);
 void pci_dev_complete_resume(struct pci_dev *pci_dev);
 void pci_config_pm_runtime_get(struct pci_dev *dev);
index 80e58d2..fafdb16 100644 (file)
@@ -40,17 +40,11 @@ static int __init pcie_pme_setup(char *str)
 }
 __setup("pcie_pme=", pcie_pme_setup);
 
-enum pme_suspend_level {
-       PME_SUSPEND_NONE = 0,
-       PME_SUSPEND_WAKEUP,
-       PME_SUSPEND_NOIRQ,
-};
-
 struct pcie_pme_service_data {
        spinlock_t lock;
        struct pcie_device *srv;
        struct work_struct work;
-       enum pme_suspend_level suspend_level;
+       bool noirq; /* If set, keep the PME interrupt disabled. */
 };
 
 /**
@@ -228,7 +222,7 @@ static void pcie_pme_work_fn(struct work_struct *work)
        spin_lock_irq(&data->lock);
 
        for (;;) {
-               if (data->suspend_level != PME_SUSPEND_NONE)
+               if (data->noirq)
                        break;
 
                pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
@@ -255,7 +249,7 @@ static void pcie_pme_work_fn(struct work_struct *work)
                spin_lock_irq(&data->lock);
        }
 
-       if (data->suspend_level == PME_SUSPEND_NONE)
+       if (!data->noirq)
                pcie_pme_interrupt_enable(port, true);
 
        spin_unlock_irq(&data->lock);
@@ -378,7 +372,7 @@ static int pcie_pme_suspend(struct pcie_device *srv)
 {
        struct pcie_pme_service_data *data = get_service_data(srv);
        struct pci_dev *port = srv->port;
-       bool wakeup, wake_irq_enabled = false;
+       bool wakeup;
        int ret;
 
        if (device_may_wakeup(&port->dev)) {
@@ -388,19 +382,16 @@ static int pcie_pme_suspend(struct pcie_device *srv)
                wakeup = pcie_pme_check_wakeup(port->subordinate);
                up_read(&pci_bus_sem);
        }
-       spin_lock_irq(&data->lock);
        if (wakeup) {
                ret = enable_irq_wake(srv->irq);
-               if (ret == 0) {
-                       data->suspend_level = PME_SUSPEND_WAKEUP;
-                       wake_irq_enabled = true;
-               }
-       }
-       if (!wake_irq_enabled) {
-               pcie_pme_interrupt_enable(port, false);
-               pcie_clear_root_pme_status(port);
-               data->suspend_level = PME_SUSPEND_NOIRQ;
+               if (!ret)
+                       return 0;
        }
+
+       spin_lock_irq(&data->lock);
+       pcie_pme_interrupt_enable(port, false);
+       pcie_clear_root_pme_status(port);
+       data->noirq = true;
        spin_unlock_irq(&data->lock);
 
        synchronize_irq(srv->irq);
@@ -417,15 +408,15 @@ static int pcie_pme_resume(struct pcie_device *srv)
        struct pcie_pme_service_data *data = get_service_data(srv);
 
        spin_lock_irq(&data->lock);
-       if (data->suspend_level == PME_SUSPEND_NOIRQ) {
+       if (data->noirq) {
                struct pci_dev *port = srv->port;
 
                pcie_clear_root_pme_status(port);
                pcie_pme_interrupt_enable(port, true);
+               data->noirq = false;
        } else {
                disable_irq_wake(srv->irq);
        }
-       data->suspend_level = PME_SUSPEND_NONE;
        spin_unlock_irq(&data->lock);
 
        return 0;
index dc459eb..1c5e0f3 100644 (file)
@@ -569,22 +569,41 @@ int armpmu_request_irq(struct arm_pmu *armpmu, int cpu)
                if (irq != other_irq) {
                        pr_warn("mismatched PPIs detected.\n");
                        err = -EINVAL;
+                       goto err_out;
                }
        } else {
-               err = request_irq(irq, handler,
-                                 IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu",
+               struct arm_pmu_platdata *platdata = armpmu_get_platdata(armpmu);
+               unsigned long irq_flags;
+
+               err = irq_force_affinity(irq, cpumask_of(cpu));
+
+               if (err && num_possible_cpus() > 1) {
+                       pr_warn("unable to set irq affinity (irq=%d, cpu=%u)\n",
+                               irq, cpu);
+                       goto err_out;
+               }
+
+               if (platdata && platdata->irq_flags) {
+                       irq_flags = platdata->irq_flags;
+               } else {
+                       irq_flags = IRQF_PERCPU |
+                                   IRQF_NOBALANCING |
+                                   IRQF_NO_THREAD;
+               }
+
+               err = request_irq(irq, handler, irq_flags, "arm-pmu",
                                  per_cpu_ptr(&hw_events->percpu_pmu, cpu));
        }
 
-       if (err) {
-               pr_err("unable to request IRQ%d for ARM PMU counters\n",
-                       irq);
-               return err;
-       }
+       if (err)
+               goto err_out;
 
        cpumask_set_cpu(cpu, &armpmu->active_irqs);
-
        return 0;
+
+err_out:
+       pr_err("unable to request IRQ%d for ARM PMU counters\n", irq);
+       return err;
 }
 
 int armpmu_request_irqs(struct arm_pmu *armpmu)
@@ -628,12 +647,6 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node)
                        enable_percpu_irq(irq, IRQ_TYPE_NONE);
                        return 0;
                }
-
-               if (irq_force_affinity(irq, cpumask_of(cpu)) &&
-                   num_possible_cpus() > 1) {
-                       pr_warn("unable to set irq affinity (irq=%d, cpu=%u)\n",
-                               irq, cpu);
-               }
        }
 
        return 0;
index 69255f5..4eafa7a 100644 (file)
@@ -131,8 +131,8 @@ static int pmu_parse_irqs(struct arm_pmu *pmu)
        }
 
        if (!pmu_has_irq_affinity(pdev->dev.of_node)) {
-               pr_warn("no interrupt-affinity property for %s, guessing.\n",
-                       of_node_full_name(pdev->dev.of_node));
+               pr_warn("no interrupt-affinity property for %pOF, guessing.\n",
+                       pdev->dev.of_node);
        }
 
        /*
@@ -211,7 +211,7 @@ int arm_pmu_device_probe(struct platform_device *pdev,
        }
 
        if (ret) {
-               pr_info("%s: failed to probe PMU!\n", of_node_full_name(node));
+               pr_info("%pOF: failed to probe PMU!\n", node);
                goto out_free;
        }
 
@@ -228,8 +228,7 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 out_free_irqs:
        armpmu_free_irqs(pmu);
 out_free:
-       pr_info("%s: failed to register PMU devices!\n",
-               of_node_full_name(node));
+       pr_info("%pOF: failed to register PMU devices!\n", node);
        armpmu_free(pmu);
        return ret;
 }
index c259848..b242cce 100644 (file)
@@ -546,6 +546,7 @@ static int l2_cache_event_init(struct perf_event *event)
        }
 
        if ((event != event->group_leader) &&
+           !is_software_event(event->group_leader) &&
            (L2_EVT_GROUP(event->group_leader->attr.config) ==
             L2_EVT_GROUP(event->attr.config))) {
                dev_dbg_ratelimited(&l2cache_pmu->pdev->dev,
@@ -558,6 +559,7 @@ static int l2_cache_event_init(struct perf_event *event)
        list_for_each_entry(sibling, &event->group_leader->sibling_list,
                            group_entry) {
                if ((sibling != event) &&
+                   !is_software_event(sibling) &&
                    (L2_EVT_GROUP(sibling->attr.config) ==
                     L2_EVT_GROUP(event->attr.config))) {
                        dev_dbg_ratelimited(&l2cache_pmu->pdev->dev,
index 37371b8..64fc59c 100644 (file)
@@ -30,8 +30,8 @@ config PHY_BCM_NS_USB3
        tristate "Broadcom Northstar USB 3.0 PHY Driver"
        depends on ARCH_BCM_IPROC || COMPILE_TEST
        depends on HAS_IOMEM && OF
+       depends on MDIO_BUS
        select GENERIC_PHY
-       select MDIO_DEVICE
        help
          Enable this to support Broadcom USB 3.0 PHY connected to the USB
          controller on Northstar family.
index 4300a55..322de58 100644 (file)
  */
 int loongson3_cpu_temp(int cpu)
 {
-       u32 reg;
+       u32 reg, prid_rev;
 
        reg = LOONGSON_CHIPTEMP(cpu);
-       if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1)
+       prid_rev = read_c0_prid() & PRID_REV_MASK;
+       switch (prid_rev) {
+       case PRID_REV_LOONGSON3A_R1:
                reg = (reg >> 8) & 0xff;
-       else
+               break;
+       case PRID_REV_LOONGSON3A_R2:
+       case PRID_REV_LOONGSON3B_R1:
+       case PRID_REV_LOONGSON3B_R2:
                reg = ((reg >> 8) & 0xff) - 100;
-
+               break;
+       case PRID_REV_LOONGSON3A_R3:
+               reg = (reg & 0xffff)*731/0x4000 - 273;
+               break;
+       }
        return (int)reg * 1000;
 }
 
+static int nr_packages;
 static struct device *cpu_hwmon_dev;
 
 static ssize_t get_hwmon_name(struct device *dev,
@@ -51,88 +61,74 @@ static ssize_t get_hwmon_name(struct device *dev,
        return sprintf(buf, "cpu-hwmon\n");
 }
 
-static ssize_t get_cpu0_temp(struct device *dev,
-                       struct device_attribute *attr, char *buf);
-static ssize_t get_cpu1_temp(struct device *dev,
+static ssize_t get_cpu_temp(struct device *dev,
                        struct device_attribute *attr, char *buf);
-static ssize_t cpu0_temp_label(struct device *dev,
+static ssize_t cpu_temp_label(struct device *dev,
                        struct device_attribute *attr, char *buf);
-static ssize_t cpu1_temp_label(struct device *dev,
-                       struct device_attribute *attr, char *buf);
-
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_cpu0_temp, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, cpu0_temp_label, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_cpu1_temp, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, cpu1_temp_label, NULL, 2);
 
-static const struct attribute *hwmon_cputemp1[] = {
-       &sensor_dev_attr_temp1_input.dev_attr.attr,
-       &sensor_dev_attr_temp1_label.dev_attr.attr,
-       NULL
-};
-
-static const struct attribute *hwmon_cputemp2[] = {
-       &sensor_dev_attr_temp2_input.dev_attr.attr,
-       &sensor_dev_attr_temp2_label.dev_attr.attr,
-       NULL
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, cpu_temp_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_cpu_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, cpu_temp_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, get_cpu_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, cpu_temp_label, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, get_cpu_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, cpu_temp_label, NULL, 4);
+
+static const struct attribute *hwmon_cputemp[4][3] = {
+       {
+               &sensor_dev_attr_temp1_input.dev_attr.attr,
+               &sensor_dev_attr_temp1_label.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_temp2_input.dev_attr.attr,
+               &sensor_dev_attr_temp2_label.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_temp3_input.dev_attr.attr,
+               &sensor_dev_attr_temp3_label.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_temp4_input.dev_attr.attr,
+               &sensor_dev_attr_temp4_label.dev_attr.attr,
+               NULL
+       }
 };
 
-static ssize_t cpu0_temp_label(struct device *dev,
-                       struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "CPU 0 Temperature\n");
-}
-
-static ssize_t cpu1_temp_label(struct device *dev,
+static ssize_t cpu_temp_label(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "CPU 1 Temperature\n");
+       int id = (to_sensor_dev_attr(attr))->index - 1;
+       return sprintf(buf, "CPU %d Temperature\n", id);
 }
 
-static ssize_t get_cpu0_temp(struct device *dev,
+static ssize_t get_cpu_temp(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
-       int value = loongson3_cpu_temp(0);
-       return sprintf(buf, "%d\n", value);
-}
-
-static ssize_t get_cpu1_temp(struct device *dev,
-                       struct device_attribute *attr, char *buf)
-{
-       int value = loongson3_cpu_temp(1);
+       int id = (to_sensor_dev_attr(attr))->index - 1;
+       int value = loongson3_cpu_temp(id);
        return sprintf(buf, "%d\n", value);
 }
 
 static int create_sysfs_cputemp_files(struct kobject *kobj)
 {
-       int ret;
-
-       ret = sysfs_create_files(kobj, hwmon_cputemp1);
-       if (ret)
-               goto sysfs_create_temp1_fail;
-
-       if (loongson_sysconf.nr_cpus <= loongson_sysconf.cores_per_package)
-               return 0;
+       int i, ret = 0;
 
-       ret = sysfs_create_files(kobj, hwmon_cputemp2);
-       if (ret)
-               goto sysfs_create_temp2_fail;
+       for (i=0; i<nr_packages; i++)
+               ret = sysfs_create_files(kobj, hwmon_cputemp[i]);
 
-       return 0;
-
-sysfs_create_temp2_fail:
-       sysfs_remove_files(kobj, hwmon_cputemp1);
-
-sysfs_create_temp1_fail:
-       return -1;
+       return ret;
 }
 
 static void remove_sysfs_cputemp_files(struct kobject *kobj)
 {
-       sysfs_remove_files(&cpu_hwmon_dev->kobj, hwmon_cputemp1);
+       int i;
 
-       if (loongson_sysconf.nr_cpus > loongson_sysconf.cores_per_package)
-               sysfs_remove_files(&cpu_hwmon_dev->kobj, hwmon_cputemp2);
+       for (i=0; i<nr_packages; i++)
+               sysfs_remove_files(kobj, hwmon_cputemp[i]);
 }
 
 #define CPU_THERMAL_THRESHOLD 90000
@@ -140,8 +136,15 @@ static struct delayed_work thermal_work;
 
 static void do_thermal_timer(struct work_struct *work)
 {
-       int value = loongson3_cpu_temp(0);
-       if (value <= CPU_THERMAL_THRESHOLD)
+       int i, value, temp_max = 0;
+
+       for (i=0; i<nr_packages; i++) {
+               value = loongson3_cpu_temp(i);
+               if (value > temp_max)
+                       temp_max = value;
+       }
+
+       if (temp_max <= CPU_THERMAL_THRESHOLD)
                schedule_delayed_work(&thermal_work, msecs_to_jiffies(5000));
        else
                orderly_poweroff(true);
@@ -160,6 +163,9 @@ static int __init loongson_hwmon_init(void)
                goto fail_hwmon_device_register;
        }
 
+       nr_packages = loongson_sysconf.nr_cpus /
+               loongson_sysconf.cores_per_package;
+
        ret = sysfs_create_group(&cpu_hwmon_dev->kobj,
                                &cpu_hwmon_attribute_group);
        if (ret) {
index 9866fec..0831b42 100644 (file)
@@ -604,7 +604,7 @@ static struct attribute *hdmi_attrs[] = {
        NULL,
 };
 
-static struct attribute_group hdmi_attribute_group = {
+static const struct attribute_group hdmi_attribute_group = {
        .name = "hdmi",
        .attrs = hdmi_attrs,
 };
@@ -660,7 +660,7 @@ static struct attribute *amplifier_attrs[] = {
        NULL,
 };
 
-static struct attribute_group amplifier_attribute_group = {
+static const struct attribute_group amplifier_attribute_group = {
        .name = "amplifier",
        .attrs = amplifier_attrs,
 };
@@ -741,7 +741,7 @@ static struct attribute *deepsleep_attrs[] = {
        NULL,
 };
 
-static struct attribute_group deepsleep_attribute_group = {
+static const struct attribute_group deepsleep_attribute_group = {
        .name = "deepsleep",
        .attrs = deepsleep_attrs,
 };
index 6c7d860..709e3a6 100644 (file)
@@ -1433,7 +1433,7 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
        return ok ? attr->mode : 0;
 }
 
-static struct attribute_group hwmon_attribute_group = {
+static const struct attribute_group hwmon_attribute_group = {
        .is_visible = asus_hwmon_sysfs_is_visible,
        .attrs = hwmon_attributes
 };
@@ -1821,7 +1821,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
        return ok ? attr->mode : 0;
 }
 
-static struct attribute_group platform_attribute_group = {
+static const struct attribute_group platform_attribute_group = {
        .is_visible = asus_sysfs_is_visible,
        .attrs = platform_attributes
 };
index e1c2b6d..a8e4a53 100644 (file)
@@ -718,7 +718,7 @@ static struct attribute *compal_platform_attrs[] = {
        &dev_attr_wake_up_mouse.attr,
        NULL
 };
-static struct attribute_group compal_platform_attr_group = {
+static const struct attribute_group compal_platform_attr_group = {
        .attrs = compal_platform_attrs
 };
 
index c1a8528..85de30f 100644 (file)
@@ -317,7 +317,7 @@ static struct attribute *fujitsu_pf_attributes[] = {
        NULL
 };
 
-static struct attribute_group fujitsu_pf_attribute_group = {
+static const struct attribute_group fujitsu_pf_attribute_group = {
        .attrs = fujitsu_pf_attributes
 };
 
@@ -695,6 +695,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
        if (call_fext_func(device,
                           FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
                led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       return -ENOMEM;
+
                led->name = "fujitsu::logolamp";
                led->brightness_set_blocking = logolamp_set;
                led->brightness_get = logolamp_get;
@@ -707,6 +710,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
                            FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
            (call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
                led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       return -ENOMEM;
+
                led->name = "fujitsu::kblamps";
                led->brightness_set_blocking = kblamps_set;
                led->brightness_get = kblamps_get;
@@ -723,6 +729,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
         */
        if (call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) {
                led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       return -ENOMEM;
+
                led->name = "fujitsu::radio_led";
                led->brightness_set_blocking = radio_led_set;
                led->brightness_get = radio_led_get;
@@ -741,6 +750,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
            (call_fext_func(device,
                            FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
                led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       return -ENOMEM;
+
                led->name = "fujitsu::eco_led";
                led->brightness_set_blocking = eco_led_set;
                led->brightness_get = eco_led_get;
index 527e5d9..603fc60 100644 (file)
@@ -909,17 +909,94 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
                },
        },
        {
+               .ident = "Lenovo V310-14IKB",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14IKB"),
+               },
+       },
+       {
+               .ident = "Lenovo V310-14ISK",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14ISK"),
+               },
+       },
+       {
+               .ident = "Lenovo V310-15IKB",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15IKB"),
+               },
+       },
+       {
                .ident = "Lenovo V310-15ISK",
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15ISK"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15ISK"),
+               },
+       },
+       {
+               .ident = "Lenovo V510-15IKB",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V510-15IKB"),
+               },
+       },
+       {
+               .ident = "Lenovo ideapad 300-15IBR",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300-15IBR"),
+               },
+       },
+       {
+               .ident = "Lenovo ideapad 300-15IKB",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300-15IKB"),
+               },
+       },
+       {
+               .ident = "Lenovo ideapad 300S-11IBR",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300S-11BR"),
+               },
+       },
+       {
+               .ident = "Lenovo ideapad 310-15ABR",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15ABR"),
+               },
+       },
+       {
+               .ident = "Lenovo ideapad 310-15IAP",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IAP"),
                },
        },
        {
                .ident = "Lenovo ideapad 310-15IKB",
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IKB"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IKB"),
+               },
+       },
+       {
+               .ident = "Lenovo ideapad 310-15ISK",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15ISK"),
+               },
+       },
+       {
+               .ident = "Lenovo ideapad Y700-14ISK",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-14ISK"),
                },
        },
        {
index 4cc2f4e..cd21df9 100644 (file)
@@ -710,6 +710,24 @@ static const struct file_operations telem_socstate_ops = {
        .release        = single_release,
 };
 
+static int telem_s0ix_res_get(void *data, u64 *val)
+{
+       u64 s0ix_total_res;
+       int ret;
+
+       ret = intel_pmc_s0ix_counter_read(&s0ix_total_res);
+       if (ret) {
+               pr_err("Failed to read S0ix residency");
+               return ret;
+       }
+
+       *val = s0ix_total_res;
+
+       return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(telem_s0ix_fops, telem_s0ix_res_get, NULL, "%llu\n");
+
 static int telem_pss_trc_verb_show(struct seq_file *s, void *unused)
 {
        u32 verbosity;
@@ -938,7 +956,7 @@ static struct notifier_block pm_notifier = {
 static int __init telemetry_debugfs_init(void)
 {
        const struct x86_cpu_id *id;
-       int err = -ENOMEM;
+       int err;
        struct dentry *f;
 
        /* Only APL supported for now */
@@ -958,11 +976,10 @@ static int __init telemetry_debugfs_init(void)
 
        register_pm_notifier(&pm_notifier);
 
+       err = -ENOMEM;
        debugfs_conf->telemetry_dbg_dir = debugfs_create_dir("telemetry", NULL);
-       if (!debugfs_conf->telemetry_dbg_dir) {
-               err = -ENOMEM;
+       if (!debugfs_conf->telemetry_dbg_dir)
                goto out_pm;
-       }
 
        f = debugfs_create_file("pss_info", S_IFREG | S_IRUGO,
                                debugfs_conf->telemetry_dbg_dir, NULL,
@@ -988,6 +1005,14 @@ static int __init telemetry_debugfs_init(void)
                goto out;
        }
 
+       f = debugfs_create_file("s0ix_residency_usec", S_IFREG | S_IRUGO,
+                               debugfs_conf->telemetry_dbg_dir,
+                               NULL, &telem_s0ix_fops);
+       if (!f) {
+               pr_err("s0ix_residency_usec debugfs register failed\n");
+               goto out;
+       }
+
        f = debugfs_create_file("pss_trace_verbosity", S_IFREG | S_IRUGO,
                                debugfs_conf->telemetry_dbg_dir, NULL,
                                &telem_pss_trc_verb_ops);
index 76b0a58..5c39b32 100644 (file)
@@ -437,7 +437,7 @@ static struct attribute *pcc_sysfs_entries[] = {
        NULL,
 };
 
-static struct attribute_group pcc_attr_group = {
+static const struct attribute_group pcc_attr_group = {
        .name   = NULL,         /* put in device directory */
        .attrs  = pcc_sysfs_entries,
 };
index ca75b4d..77d1f90 100644 (file)
@@ -51,7 +51,7 @@ static void peaq_wmi_poll(struct input_polled_dev *dev)
                return;
        }
 
-       if (peaq_ignore_events_counter && --peaq_ignore_events_counter > 0)
+       if (peaq_ignore_events_counter && --peaq_ignore_events_counter >= 0)
                return;
 
        if (obj.integer.value) {
index 5c4dfe4..0c703fe 100644 (file)
@@ -1232,7 +1232,7 @@ static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
        return ok ? attr->mode : 0;
 }
 
-static struct attribute_group platform_attribute_group = {
+static const struct attribute_group platform_attribute_group = {
        .is_visible = samsung_sysfs_is_visible,
        .attrs = platform_attributes
 };
index 3cd3bdf..1157a7b 100644 (file)
@@ -122,6 +122,20 @@ static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_data = {
        .properties     = pov_mobii_wintab_p800w_props,
 };
 
+static const struct property_entry itworks_tw891_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1600),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 890),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+       PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-itworks-tw891.fw"),
+       { }
+};
+
+static const struct silead_ts_dmi_data itworks_tw891_data = {
+       .acpi_name      = "MSSL1680:00",
+       .properties     = itworks_tw891_props,
+};
+
 static const struct dmi_system_id silead_ts_dmi_table[] = {
        {
                /* CUBE iwork8 Air */
@@ -160,6 +174,16 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
                },
        },
        {
+               /* Ployer Momo7w (same hardware as the Trekstor ST70416-6) */
+               .driver_data = (void *)&surftab_wintron70_st70416_6_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Shenzhen PLOYER"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MOMO7W"),
+                       /* Exact match, different versions need different fw */
+                       DMI_MATCH(DMI_BIOS_VERSION, "MOMO.G.WI71C.MABMRBA02"),
+               },
+       },
+       {
                /* GP-electronic T701 */
                .driver_data = (void *)&gp_electronic_t701_data,
                .matches = {
@@ -187,6 +211,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
                        DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"),
                },
        },
+       {
+               /* I.T.Works TW891 */
+               .driver_data = (void *)&itworks_tw891_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TW891"),
+               },
+       },
        { },
 };
 
index 88f9f79..bb1dcd7 100644 (file)
@@ -2419,7 +2419,7 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
        return exists ? attr->mode : 0;
 }
 
-static struct attribute_group toshiba_attr_group = {
+static const struct attribute_group toshiba_attr_group = {
        .is_visible = toshiba_sysfs_is_visible,
        .attrs = toshiba_attributes,
 };
index 3de802f..9dff1b4 100644 (file)
@@ -980,10 +980,37 @@ static int twl4030_bci_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, bci);
 
+       INIT_WORK(&bci->work, twl4030_bci_usb_work);
+       INIT_DELAYED_WORK(&bci->current_worker, twl4030_current_worker);
+
        bci->channel_vac = devm_iio_channel_get(&pdev->dev, "vac");
        if (IS_ERR(bci->channel_vac)) {
+               ret = PTR_ERR(bci->channel_vac);
+               if (ret == -EPROBE_DEFER)
+                       return ret;     /* iio not ready */
+               dev_warn(&pdev->dev, "could not request vac iio channel (%d)",
+                       ret);
                bci->channel_vac = NULL;
-               dev_warn(&pdev->dev, "could not request vac iio channel");
+       }
+
+       if (bci->dev->of_node) {
+               struct device_node *phynode;
+
+               phynode = of_find_compatible_node(bci->dev->of_node->parent,
+                                                 NULL, "ti,twl4030-usb");
+               if (phynode) {
+                       bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
+                       bci->transceiver = devm_usb_get_phy_by_node(
+                               bci->dev, phynode, &bci->usb_nb);
+                       if (IS_ERR(bci->transceiver)) {
+                               ret = PTR_ERR(bci->transceiver);
+                               if (ret == -EPROBE_DEFER)
+                                       return ret;     /* phy not ready */
+                               dev_warn(&pdev->dev, "could not request transceiver (%d)",
+                                       ret);
+                               bci->transceiver = NULL;
+                       }
+               }
        }
 
        bci->ac = devm_power_supply_register(&pdev->dev, &twl4030_bci_ac_desc,
@@ -1019,20 +1046,6 @@ static int twl4030_bci_probe(struct platform_device *pdev)
                return ret;
        }
 
-       INIT_WORK(&bci->work, twl4030_bci_usb_work);
-       INIT_DELAYED_WORK(&bci->current_worker, twl4030_current_worker);
-
-       bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
-       if (bci->dev->of_node) {
-               struct device_node *phynode;
-
-               phynode = of_find_compatible_node(bci->dev->of_node->parent,
-                                                 NULL, "ti,twl4030-usb");
-               if (phynode)
-                       bci->transceiver = devm_usb_get_phy_by_node(
-                               bci->dev, phynode, &bci->usb_nb);
-       }
-
        /* Enable interrupts now. */
        reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 |
                TWL4030_TBATOR1 | TWL4030_BATSTS);
index a0860b3..1581f6a 100644 (file)
@@ -678,7 +678,9 @@ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
 
        pc = of_node_to_pwmchip(args.np);
        if (IS_ERR(pc)) {
-               pr_err("%s(): PWM chip not found\n", __func__);
+               if (PTR_ERR(pc) != -EPROBE_DEFER)
+                       pr_err("%s(): PWM chip not found\n", __func__);
+
                pwm = ERR_CAST(pc);
                goto put;
        }
index d2ed0a2..a9a8813 100644 (file)
@@ -118,10 +118,8 @@ static int bfin_pwm_probe(struct platform_device *pdev)
        int ret;
 
        pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
-       if (!pwm) {
-               dev_err(&pdev->dev, "failed to allocate memory\n");
+       if (!pwm)
                return -ENOMEM;
-       }
 
        platform_set_drvdata(pdev, pwm);
 
index f6ca4e8..9c13694 100644 (file)
@@ -75,8 +75,8 @@ static int __cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index,
 
        msg->version = 0;
        msg->command = EC_CMD_PWM_GET_DUTY;
-       msg->insize = sizeof(*params);
-       msg->outsize = sizeof(*resp);
+       msg->insize = sizeof(*resp);
+       msg->outsize = sizeof(*params);
 
        params->pwm_type = EC_PWM_TYPE_GENERIC;
        params->index = index;
index d0e8f85..8dadc58 100644 (file)
@@ -165,7 +165,7 @@ static int hibvt_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        return 0;
 }
 
-static struct pwm_ops hibvt_pwm_ops = {
+static const struct pwm_ops hibvt_pwm_ops = {
        .get_state = hibvt_pwm_get_state,
        .apply = hibvt_pwm_apply,
 
index 045ef9f..cb845ed 100644 (file)
@@ -103,6 +103,7 @@ struct meson_pwm_channel {
 
 struct meson_pwm_data {
        const char * const *parent_names;
+       unsigned int num_parents;
 };
 
 struct meson_pwm {
@@ -162,7 +163,8 @@ static int meson_pwm_calc(struct meson_pwm *meson,
                          unsigned int duty, unsigned int period)
 {
        unsigned int pre_div, cnt, duty_cnt;
-       unsigned long fin_freq = -1, fin_ns;
+       unsigned long fin_freq = -1;
+       u64 fin_ps;
 
        if (~(meson->inverter_mask >> id) & 0x1)
                duty = period - duty;
@@ -178,13 +180,15 @@ static int meson_pwm_calc(struct meson_pwm *meson,
        }
 
        dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq);
-       fin_ns = NSEC_PER_SEC / fin_freq;
+       fin_ps = (u64)NSEC_PER_SEC * 1000;
+       do_div(fin_ps, fin_freq);
 
        /* Calc pre_div with the period */
        for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) {
-               cnt = DIV_ROUND_CLOSEST(period, fin_ns * (pre_div + 1));
-               dev_dbg(meson->chip.dev, "fin_ns=%lu pre_div=%u cnt=%u\n",
-                       fin_ns, pre_div, cnt);
+               cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000,
+                                           fin_ps * (pre_div + 1));
+               dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n",
+                       fin_ps, pre_div, cnt);
                if (cnt <= 0xffff)
                        break;
        }
@@ -207,7 +211,8 @@ static int meson_pwm_calc(struct meson_pwm *meson,
                channel->lo = cnt;
        } else {
                /* Then check is we can have the duty with the same pre_div */
-               duty_cnt = DIV_ROUND_CLOSEST(duty, fin_ns * (pre_div + 1));
+               duty_cnt = DIV_ROUND_CLOSEST_ULL((u64)duty * 1000,
+                                                fin_ps * (pre_div + 1));
                if (duty_cnt > 0xffff) {
                        dev_err(meson->chip.dev, "unable to get duty cycle\n");
                        return -EINVAL;
@@ -381,6 +386,7 @@ static const char * const pwm_meson8b_parent_names[] = {
 
 static const struct meson_pwm_data pwm_meson8b_data = {
        .parent_names = pwm_meson8b_parent_names,
+       .num_parents = ARRAY_SIZE(pwm_meson8b_parent_names),
 };
 
 static const char * const pwm_gxbb_parent_names[] = {
@@ -389,11 +395,35 @@ static const char * const pwm_gxbb_parent_names[] = {
 
 static const struct meson_pwm_data pwm_gxbb_data = {
        .parent_names = pwm_gxbb_parent_names,
+       .num_parents = ARRAY_SIZE(pwm_gxbb_parent_names),
+};
+
+/*
+ * Only the 2 first inputs of the GXBB AO PWMs are valid
+ * The last 2 are grounded
+ */
+static const char * const pwm_gxbb_ao_parent_names[] = {
+       "xtal", "clk81"
+};
+
+static const struct meson_pwm_data pwm_gxbb_ao_data = {
+       .parent_names = pwm_gxbb_ao_parent_names,
+       .num_parents = ARRAY_SIZE(pwm_gxbb_ao_parent_names),
 };
 
 static const struct of_device_id meson_pwm_matches[] = {
-       { .compatible = "amlogic,meson8b-pwm", .data = &pwm_meson8b_data },
-       { .compatible = "amlogic,meson-gxbb-pwm", .data = &pwm_gxbb_data },
+       {
+               .compatible = "amlogic,meson8b-pwm",
+               .data = &pwm_meson8b_data
+       },
+       {
+               .compatible = "amlogic,meson-gxbb-pwm",
+               .data = &pwm_gxbb_data
+       },
+       {
+               .compatible = "amlogic,meson-gxbb-ao-pwm",
+               .data = &pwm_gxbb_ao_data
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, meson_pwm_matches);
@@ -417,7 +447,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson,
                init.ops = &clk_mux_ops;
                init.flags = CLK_IS_BASIC;
                init.parent_names = meson->data->parent_names;
-               init.num_parents = 1 << MISC_CLK_SEL_WIDTH;
+               init.num_parents = meson->data->num_parents;
 
                channel->mux.reg = meson->base + REG_MISC_AB;
                channel->mux.shift = mux_reg_shifts[i];
index 1284ffa..6d23f1d 100644 (file)
@@ -8,8 +8,10 @@
 
 #include <linux/bitops.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/jiffies.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 
 #define PWM_DTY_MASK           GENMASK(15, 0)
 
+#define PWM_REG_PRD(reg)       ((((reg) >> 16) & PWM_PRD_MASK) + 1)
+#define PWM_REG_DTY(reg)       ((reg) & PWM_DTY_MASK)
+#define PWM_REG_PRESCAL(reg, chan)     (((reg) >> ((chan) * PWMCH_OFFSET)) & PWM_PRESCAL_MASK)
+
 #define BIT_CH(bit, chan)      ((bit) << ((chan) * PWMCH_OFFSET))
 
 static const u32 prescaler_table[] = {
@@ -77,6 +83,8 @@ struct sun4i_pwm_chip {
        void __iomem *base;
        spinlock_t ctrl_lock;
        const struct sun4i_pwm_data *data;
+       unsigned long next_period[2];
+       bool needs_delay[2];
 };
 
 static inline struct sun4i_pwm_chip *to_sun4i_pwm_chip(struct pwm_chip *chip)
@@ -96,26 +104,65 @@ static inline void sun4i_pwm_writel(struct sun4i_pwm_chip *chip,
        writel(val, chip->base + offset);
 }
 
-static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
-                           int duty_ns, int period_ns)
+static void sun4i_pwm_get_state(struct pwm_chip *chip,
+                               struct pwm_device *pwm,
+                               struct pwm_state *state)
 {
        struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
-       u32 prd, dty, val, clk_gate;
+       u64 clk_rate, tmp;
+       u32 val;
+       unsigned int prescaler;
+
+       clk_rate = clk_get_rate(sun4i_pwm->clk);
+
+       val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+
+       if ((val == PWM_PRESCAL_MASK) && sun4i_pwm->data->has_prescaler_bypass)
+               prescaler = 1;
+       else
+               prescaler = prescaler_table[PWM_REG_PRESCAL(val, pwm->hwpwm)];
+
+       if (prescaler == 0)
+               return;
+
+       if (val & BIT_CH(PWM_ACT_STATE, pwm->hwpwm))
+               state->polarity = PWM_POLARITY_NORMAL;
+       else
+               state->polarity = PWM_POLARITY_INVERSED;
+
+       if (val & BIT_CH(PWM_CLK_GATING | PWM_EN, pwm->hwpwm))
+               state->enabled = true;
+       else
+               state->enabled = false;
+
+       val = sun4i_pwm_readl(sun4i_pwm, PWM_CH_PRD(pwm->hwpwm));
+
+       tmp = prescaler * NSEC_PER_SEC * PWM_REG_DTY(val);
+       state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
+
+       tmp = prescaler * NSEC_PER_SEC * PWM_REG_PRD(val);
+       state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
+}
+
+static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm,
+                              struct pwm_state *state,
+                              u32 *dty, u32 *prd, unsigned int *prsclr)
+{
        u64 clk_rate, div = 0;
-       unsigned int prescaler = 0;
-       int err;
+       unsigned int pval, prescaler = 0;
 
        clk_rate = clk_get_rate(sun4i_pwm->clk);
 
        if (sun4i_pwm->data->has_prescaler_bypass) {
                /* First, test without any prescaler when available */
                prescaler = PWM_PRESCAL_MASK;
+               pval = 1;
                /*
                 * When not using any prescaler, the clock period in nanoseconds
                 * is not an integer so round it half up instead of
                 * truncating to get less surprising values.
                 */
-               div = clk_rate * period_ns + NSEC_PER_SEC / 2;
+               div = clk_rate * state->period + NSEC_PER_SEC / 2;
                do_div(div, NSEC_PER_SEC);
                if (div - 1 > PWM_PRD_MASK)
                        prescaler = 0;
@@ -126,137 +173,141 @@ static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
                for (prescaler = 0; prescaler < PWM_PRESCAL_MASK; prescaler++) {
                        if (!prescaler_table[prescaler])
                                continue;
+                       pval = prescaler_table[prescaler];
                        div = clk_rate;
-                       do_div(div, prescaler_table[prescaler]);
-                       div = div * period_ns;
+                       do_div(div, pval);
+                       div = div * state->period;
                        do_div(div, NSEC_PER_SEC);
                        if (div - 1 <= PWM_PRD_MASK)
                                break;
                }
 
-               if (div - 1 > PWM_PRD_MASK) {
-                       dev_err(chip->dev, "period exceeds the maximum value\n");
+               if (div - 1 > PWM_PRD_MASK)
                        return -EINVAL;
-               }
-       }
-
-       prd = div;
-       div *= duty_ns;
-       do_div(div, period_ns);
-       dty = div;
-
-       err = clk_prepare_enable(sun4i_pwm->clk);
-       if (err) {
-               dev_err(chip->dev, "failed to enable PWM clock\n");
-               return err;
-       }
-
-       spin_lock(&sun4i_pwm->ctrl_lock);
-       val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
-
-       if (sun4i_pwm->data->has_rdy && (val & PWM_RDY(pwm->hwpwm))) {
-               spin_unlock(&sun4i_pwm->ctrl_lock);
-               clk_disable_unprepare(sun4i_pwm->clk);
-               return -EBUSY;
-       }
-
-       clk_gate = val & BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
-       if (clk_gate) {
-               val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
-               sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
        }
 
-       val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
-       val &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm);
-       val |= BIT_CH(prescaler, pwm->hwpwm);
-       sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
-
-       val = (dty & PWM_DTY_MASK) | PWM_PRD(prd);
-       sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm));
+       *prd = div;
+       div *= state->duty_cycle;
+       do_div(div, state->period);
+       *dty = div;
+       *prsclr = prescaler;
 
-       if (clk_gate) {
-               val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
-               val |= clk_gate;
-               sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
-       }
+       div = (u64)pval * NSEC_PER_SEC * *prd;
+       state->period = DIV_ROUND_CLOSEST_ULL(div, clk_rate);
 
-       spin_unlock(&sun4i_pwm->ctrl_lock);
-       clk_disable_unprepare(sun4i_pwm->clk);
+       div = (u64)pval * NSEC_PER_SEC * *dty;
+       state->duty_cycle = DIV_ROUND_CLOSEST_ULL(div, clk_rate);
 
        return 0;
 }
 
-static int sun4i_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
-                                 enum pwm_polarity polarity)
+static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+                          struct pwm_state *state)
 {
        struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
-       u32 val;
+       struct pwm_state cstate;
+       u32 ctrl;
        int ret;
+       unsigned int delay_us;
+       unsigned long now;
 
-       ret = clk_prepare_enable(sun4i_pwm->clk);
-       if (ret) {
-               dev_err(chip->dev, "failed to enable PWM clock\n");
-               return ret;
+       pwm_get_state(pwm, &cstate);
+
+       if (!cstate.enabled) {
+               ret = clk_prepare_enable(sun4i_pwm->clk);
+               if (ret) {
+                       dev_err(chip->dev, "failed to enable PWM clock\n");
+                       return ret;
+               }
        }
 
        spin_lock(&sun4i_pwm->ctrl_lock);
-       val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+       ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
 
-       if (polarity != PWM_POLARITY_NORMAL)
-               val &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
-       else
-               val |= BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
+       if ((cstate.period != state->period) ||
+           (cstate.duty_cycle != state->duty_cycle)) {
+               u32 period, duty, val;
+               unsigned int prescaler;
 
-       sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+               ret = sun4i_pwm_calculate(sun4i_pwm, state,
+                                         &duty, &period, &prescaler);
+               if (ret) {
+                       dev_err(chip->dev, "period exceeds the maximum value\n");
+                       spin_unlock(&sun4i_pwm->ctrl_lock);
+                       if (!cstate.enabled)
+                               clk_disable_unprepare(sun4i_pwm->clk);
+                       return ret;
+               }
 
-       spin_unlock(&sun4i_pwm->ctrl_lock);
-       clk_disable_unprepare(sun4i_pwm->clk);
+               if (PWM_REG_PRESCAL(ctrl, pwm->hwpwm) != prescaler) {
+                       /* Prescaler changed, the clock has to be gated */
+                       ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
+                       sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG);
 
-       return 0;
-}
+                       ctrl &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm);
+                       ctrl |= BIT_CH(prescaler, pwm->hwpwm);
+               }
 
-static int sun4i_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
-       u32 val;
-       int ret;
+               val = (duty & PWM_DTY_MASK) | PWM_PRD(period);
+               sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm));
+               sun4i_pwm->next_period[pwm->hwpwm] = jiffies +
+                       usecs_to_jiffies(cstate.period / 1000 + 1);
+               sun4i_pwm->needs_delay[pwm->hwpwm] = true;
+       }
 
-       ret = clk_prepare_enable(sun4i_pwm->clk);
-       if (ret) {
-               dev_err(chip->dev, "failed to enable PWM clock\n");
-               return ret;
+       if (state->polarity != PWM_POLARITY_NORMAL)
+               ctrl &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
+       else
+               ctrl |= BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
+
+       ctrl |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
+       if (state->enabled) {
+               ctrl |= BIT_CH(PWM_EN, pwm->hwpwm);
+       } else if (!sun4i_pwm->needs_delay[pwm->hwpwm]) {
+               ctrl &= ~BIT_CH(PWM_EN, pwm->hwpwm);
+               ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
        }
 
-       spin_lock(&sun4i_pwm->ctrl_lock);
-       val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
-       val |= BIT_CH(PWM_EN, pwm->hwpwm);
-       val |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
-       sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+       sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG);
+
        spin_unlock(&sun4i_pwm->ctrl_lock);
 
-       return 0;
-}
+       if (state->enabled)
+               return 0;
 
-static void sun4i_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
-       u32 val;
+       if (!sun4i_pwm->needs_delay[pwm->hwpwm]) {
+               clk_disable_unprepare(sun4i_pwm->clk);
+               return 0;
+       }
+
+       /* We need a full period to elapse before disabling the channel. */
+       now = jiffies;
+       if (sun4i_pwm->needs_delay[pwm->hwpwm] &&
+           time_before(now, sun4i_pwm->next_period[pwm->hwpwm])) {
+               delay_us = jiffies_to_usecs(sun4i_pwm->next_period[pwm->hwpwm] -
+                                          now);
+               if ((delay_us / 500) > MAX_UDELAY_MS)
+                       msleep(delay_us / 1000 + 1);
+               else
+                       usleep_range(delay_us, delay_us * 2);
+       }
+       sun4i_pwm->needs_delay[pwm->hwpwm] = false;
 
        spin_lock(&sun4i_pwm->ctrl_lock);
-       val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
-       val &= ~BIT_CH(PWM_EN, pwm->hwpwm);
-       val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
-       sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+       ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+       ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
+       ctrl &= ~BIT_CH(PWM_EN, pwm->hwpwm);
+       sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG);
        spin_unlock(&sun4i_pwm->ctrl_lock);
 
        clk_disable_unprepare(sun4i_pwm->clk);
+
+       return 0;
 }
 
 static const struct pwm_ops sun4i_pwm_ops = {
-       .config = sun4i_pwm_config,
-       .set_polarity = sun4i_pwm_set_polarity,
-       .enable = sun4i_pwm_enable,
-       .disable = sun4i_pwm_disable,
+       .apply = sun4i_pwm_apply,
+       .get_state = sun4i_pwm_get_state,
        .owner = THIS_MODULE,
 };
 
@@ -316,8 +367,7 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
 {
        struct sun4i_pwm_chip *pwm;
        struct resource *res;
-       u32 val;
-       int i, ret;
+       int ret;
        const struct of_device_id *match;
 
        match = of_match_device(sun4i_pwm_dt_ids, &pdev->dev);
@@ -353,24 +403,7 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, pwm);
 
-       ret = clk_prepare_enable(pwm->clk);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to enable PWM clock\n");
-               goto clk_error;
-       }
-
-       val = sun4i_pwm_readl(pwm, PWM_CTRL_REG);
-       for (i = 0; i < pwm->chip.npwm; i++)
-               if (!(val & BIT_CH(PWM_ACT_STATE, i)))
-                       pwm_set_polarity(&pwm->chip.pwms[i],
-                                        PWM_POLARITY_INVERSED);
-       clk_disable_unprepare(pwm->clk);
-
        return 0;
-
-clk_error:
-       pwmchip_remove(&pwm->chip);
-       return ret;
 }
 
 static int sun4i_pwm_remove(struct platform_device *pdev)
index 8c6ed55..e9b33f0 100644 (file)
@@ -41,6 +41,9 @@
 
 struct tegra_pwm_soc {
        unsigned int num_channels;
+
+       /* Maximum IP frequency for given SoCs */
+       unsigned long max_frequency;
 };
 
 struct tegra_pwm_chip {
@@ -201,7 +204,18 @@ static int tegra_pwm_probe(struct platform_device *pdev)
        if (IS_ERR(pwm->clk))
                return PTR_ERR(pwm->clk);
 
-       /* Read PWM clock rate from source */
+       /* Set maximum frequency of the IP */
+       ret = clk_set_rate(pwm->clk, pwm->soc->max_frequency);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to set max frequency: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * The requested and configured frequency may differ due to
+        * clock register resolutions. Get the configured frequency
+        * so that PWM period can be calculated more accurately.
+        */
        pwm->clk_rate = clk_get_rate(pwm->clk);
 
        pwm->rst = devm_reset_control_get(&pdev->dev, "pwm");
@@ -273,10 +287,12 @@ static int tegra_pwm_resume(struct device *dev)
 
 static const struct tegra_pwm_soc tegra20_pwm_soc = {
        .num_channels = 4,
+       .max_frequency = 48000000UL,
 };
 
 static const struct tegra_pwm_soc tegra186_pwm_soc = {
        .num_channels = 1,
+       .max_frequency = 102000000UL,
 };
 
 static const struct of_device_id tegra_pwm_of_match[] = {
index 8d3b957..72419ac 100644 (file)
@@ -77,6 +77,14 @@ config RTC_DEBUG
          Say yes here to enable debugging support in the RTC framework
          and individual RTC drivers.
 
+config RTC_NVMEM
+       bool "RTC non volatile storage support"
+       select NVMEM
+       default RTC_CLASS
+       help
+         Say yes here to add support for the non volatile (often battery
+         backed) storage present on RTCs.
+
 comment "RTC interfaces"
 
 config RTC_INTF_SYSFS
@@ -197,6 +205,17 @@ config RTC_DRV_AC100
          This driver can also be built as a module. If so, the module
          will be called rtc-ac100.
 
+config RTC_DRV_BRCMSTB
+       tristate "Broadcom STB wake-timer"
+       depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
+       default ARCH_BRCMSTB || BMIPS_GENERIC
+       help
+         If you say yes here you get support for the wake-timer found on
+         Broadcom STB SoCs (BCM7xxx).
+
+         This driver can also be built as a module. If so, the module will
+         be called rtc-brcmstb-waketimer.
+
 config RTC_DRV_AS3722
        tristate "ams AS3722 RTC driver"
        depends on MFD_AS3722
@@ -791,6 +810,14 @@ config RTC_DRV_DS3232
          This driver can also be built as a module.  If so, the module
          will be called rtc-ds3232.
 
+config RTC_DRV_DS3232_HWMON
+       bool "HWMON support for Dallas/Maxim DS3232/DS3234"
+       depends on RTC_DRV_DS3232 && HWMON && !(RTC_DRV_DS3232=y && HWMON=m)
+       default y
+       help
+         Say Y here if you want to expose temperature sensor data on
+         rtc-ds3232
+
 config RTC_DRV_PCF2127
        tristate "NXP PCF2127"
        depends on RTC_I2C_AND_SPI
@@ -1484,16 +1511,16 @@ config RTC_DRV_ARMADA38X
          This driver can also be built as a module. If so, the module
          will be called armada38x-rtc.
 
-config RTC_DRV_GEMINI
-       tristate "Gemini SoC RTC"
-       depends on ARCH_GEMINI || COMPILE_TEST
+config RTC_DRV_FTRTC010
+       tristate "Faraday Technology FTRTC010 RTC"
        depends on HAS_IOMEM
+       default ARCH_GEMINI
        help
          If you say Y here you will get support for the
-         RTC found on Gemini SoC's.
+         Faraday Technolog FTRTC010 found on e.g. Gemini SoC's.
 
          This driver can also be built as a module. If so, the module
-         will be called rtc-gemini.
+         will be called rtc-ftrtc010.
 
 config RTC_DRV_PS3
        tristate "PS3 RTC"
index 13857d2..acd366b 100644 (file)
@@ -15,6 +15,7 @@ ifdef CONFIG_RTC_DRV_EFI
 rtc-core-y                     += rtc-efi-platform.o
 endif
 
+rtc-core-$(CONFIG_RTC_NVMEM)           += nvmem.o
 rtc-core-$(CONFIG_RTC_INTF_DEV)                += rtc-dev.o
 rtc-core-$(CONFIG_RTC_INTF_PROC)       += rtc-proc.o
 rtc-core-$(CONFIG_RTC_INTF_SYSFS)      += rtc-sysfs.o
@@ -36,6 +37,7 @@ obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
 obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
 obj-$(CONFIG_RTC_DRV_AU1XXX)   += rtc-au1xxx.o
 obj-$(CONFIG_RTC_DRV_BFIN)     += rtc-bfin.o
+obj-$(CONFIG_RTC_DRV_BRCMSTB)  += rtc-brcmstb-waketimer.o
 obj-$(CONFIG_RTC_DRV_BQ32K)    += rtc-bq32k.o
 obj-$(CONFIG_RTC_DRV_BQ4802)   += rtc-bq4802.o
 obj-$(CONFIG_RTC_DRV_CMOS)     += rtc-cmos.o
@@ -67,7 +69,7 @@ obj-$(CONFIG_RTC_DRV_EFI)     += rtc-efi.o
 obj-$(CONFIG_RTC_DRV_EM3027)   += rtc-em3027.o
 obj-$(CONFIG_RTC_DRV_EP93XX)   += rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_FM3130)   += rtc-fm3130.o
-obj-$(CONFIG_RTC_DRV_GEMINI)   += rtc-gemini.o
+obj-$(CONFIG_RTC_DRV_FTRTC010) += rtc-ftrtc010.o
 obj-$(CONFIG_RTC_DRV_GENERIC)  += rtc-generic.o
 obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
 obj-$(CONFIG_RTC_DRV_HYM8563)  += rtc-hym8563.o
index 5fb4398..2ed970d 100644 (file)
@@ -150,59 +150,19 @@ static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume);
 #define RTC_CLASS_DEV_PM_OPS   NULL
 #endif
 
-
-/**
- * rtc_device_register - register w/ RTC class
- * @dev: the device to register
- *
- * rtc_device_unregister() must be called when the class device is no
- * longer needed.
- *
- * Returns the pointer to the new struct class device.
- */
-struct rtc_device *rtc_device_register(const char *name, struct device *dev,
-                                       const struct rtc_class_ops *ops,
-                                       struct module *owner)
+/* Ensure the caller will set the id before releasing the device */
+static struct rtc_device *rtc_allocate_device(void)
 {
        struct rtc_device *rtc;
-       struct rtc_wkalrm alrm;
-       int of_id = -1, id = -1, err;
-
-       if (dev->of_node)
-               of_id = of_alias_get_id(dev->of_node, "rtc");
-       else if (dev->parent && dev->parent->of_node)
-               of_id = of_alias_get_id(dev->parent->of_node, "rtc");
 
-       if (of_id >= 0) {
-               id = ida_simple_get(&rtc_ida, of_id, of_id + 1,
-                                   GFP_KERNEL);
-               if (id < 0)
-                       dev_warn(dev, "/aliases ID %d not available\n",
-                                   of_id);
-       }
-
-       if (id < 0) {
-               id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
-               if (id < 0) {
-                       err = id;
-                       goto exit;
-               }
-       }
-
-       rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
-       if (rtc == NULL) {
-               err = -ENOMEM;
-               goto exit_ida;
-       }
+       rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+       if (!rtc)
+               return NULL;
 
        device_initialize(&rtc->dev);
 
-       rtc->id = id;
-       rtc->ops = ops;
-       rtc->owner = owner;
        rtc->irq_freq = 1;
        rtc->max_user_freq = 64;
-       rtc->dev.parent = dev;
        rtc->dev.class = rtc_class;
        rtc->dev.groups = rtc_get_dev_attribute_groups();
        rtc->dev.release = rtc_device_release;
@@ -224,7 +184,64 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
        rtc->pie_timer.function = rtc_pie_update_irq;
        rtc->pie_enabled = 0;
 
-       strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
+       return rtc;
+}
+
+static int rtc_device_get_id(struct device *dev)
+{
+       int of_id = -1, id = -1;
+
+       if (dev->of_node)
+               of_id = of_alias_get_id(dev->of_node, "rtc");
+       else if (dev->parent && dev->parent->of_node)
+               of_id = of_alias_get_id(dev->parent->of_node, "rtc");
+
+       if (of_id >= 0) {
+               id = ida_simple_get(&rtc_ida, of_id, of_id + 1, GFP_KERNEL);
+               if (id < 0)
+                       dev_warn(dev, "/aliases ID %d not available\n", of_id);
+       }
+
+       if (id < 0)
+               id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
+
+       return id;
+}
+
+/**
+ * rtc_device_register - register w/ RTC class
+ * @dev: the device to register
+ *
+ * rtc_device_unregister() must be called when the class device is no
+ * longer needed.
+ *
+ * Returns the pointer to the new struct class device.
+ */
+struct rtc_device *rtc_device_register(const char *name, struct device *dev,
+                                       const struct rtc_class_ops *ops,
+                                       struct module *owner)
+{
+       struct rtc_device *rtc;
+       struct rtc_wkalrm alrm;
+       int id, err;
+
+       id = rtc_device_get_id(dev);
+       if (id < 0) {
+               err = id;
+               goto exit;
+       }
+
+       rtc = rtc_allocate_device();
+       if (!rtc) {
+               err = -ENOMEM;
+               goto exit_ida;
+       }
+
+       rtc->id = id;
+       rtc->ops = ops;
+       rtc->owner = owner;
+       rtc->dev.parent = dev;
+
        dev_set_name(&rtc->dev, "rtc%d", id);
 
        /* Check to see if there is an ALARM already set in hw */
@@ -238,20 +255,20 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
        err = cdev_device_add(&rtc->char_dev, &rtc->dev);
        if (err) {
                dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n",
-                        rtc->name, MAJOR(rtc->dev.devt), rtc->id);
+                        name, MAJOR(rtc->dev.devt), rtc->id);
 
                /* This will free both memory and the ID */
                put_device(&rtc->dev);
                goto exit;
        } else {
-               dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name,
+               dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", name,
                        MAJOR(rtc->dev.devt), rtc->id);
        }
 
        rtc_proc_add_device(rtc);
 
        dev_info(dev, "rtc core: registered %s as %s\n",
-                       rtc->name, dev_name(&rtc->dev));
+                       name, dev_name(&rtc->dev));
 
        return rtc;
 
@@ -273,6 +290,8 @@ EXPORT_SYMBOL_GPL(rtc_device_register);
  */
 void rtc_device_unregister(struct rtc_device *rtc)
 {
+       rtc_nvmem_unregister(rtc);
+
        mutex_lock(&rtc->ops_lock);
        /*
         * Remove innards of this RTC, then disable it, before
@@ -356,6 +375,91 @@ void devm_rtc_device_unregister(struct device *dev, struct rtc_device *rtc)
 }
 EXPORT_SYMBOL_GPL(devm_rtc_device_unregister);
 
+static void devm_rtc_release_device(struct device *dev, void *res)
+{
+       struct rtc_device *rtc = *(struct rtc_device **)res;
+
+       if (rtc->registered)
+               rtc_device_unregister(rtc);
+       else
+               put_device(&rtc->dev);
+}
+
+struct rtc_device *devm_rtc_allocate_device(struct device *dev)
+{
+       struct rtc_device **ptr, *rtc;
+       int id, err;
+
+       id = rtc_device_get_id(dev);
+       if (id < 0)
+               return ERR_PTR(id);
+
+       ptr = devres_alloc(devm_rtc_release_device, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr) {
+               err = -ENOMEM;
+               goto exit_ida;
+       }
+
+       rtc = rtc_allocate_device();
+       if (!rtc) {
+               err = -ENOMEM;
+               goto exit_devres;
+       }
+
+       *ptr = rtc;
+       devres_add(dev, ptr);
+
+       rtc->id = id;
+       rtc->dev.parent = dev;
+       dev_set_name(&rtc->dev, "rtc%d", id);
+
+       return rtc;
+
+exit_devres:
+       devres_free(ptr);
+exit_ida:
+       ida_simple_remove(&rtc_ida, id);
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(devm_rtc_allocate_device);
+
+int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
+{
+       struct rtc_wkalrm alrm;
+       int err;
+
+       if (!rtc->ops)
+               return -EINVAL;
+
+       rtc->owner = owner;
+
+       /* Check to see if there is an ALARM already set in hw */
+       err = __rtc_read_alarm(rtc, &alrm);
+       if (!err && !rtc_valid_tm(&alrm.time))
+               rtc_initialize_alarm(rtc, &alrm);
+
+       rtc_dev_prepare(rtc);
+
+       err = cdev_device_add(&rtc->char_dev, &rtc->dev);
+       if (err)
+               dev_warn(rtc->dev.parent, "failed to add char device %d:%d\n",
+                        MAJOR(rtc->dev.devt), rtc->id);
+       else
+               dev_dbg(rtc->dev.parent, "char device (%d:%d)\n",
+                       MAJOR(rtc->dev.devt), rtc->id);
+
+       rtc_proc_add_device(rtc);
+
+       rtc_nvmem_register(rtc);
+
+       rtc->registered = true;
+       dev_info(rtc->dev.parent, "registered as %s\n",
+                dev_name(&rtc->dev));
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__rtc_register_device);
+
 static int __init rtc_init(void)
 {
        rtc_class = class_create(THIS_MODULE, "rtc");
index fc0fa75..8cec9a0 100644 (file)
@@ -227,6 +227,13 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
                        missing = year;
        }
 
+       /* Can't proceed if alarm is still invalid after replacing
+        * missing fields.
+        */
+       err = rtc_valid_tm(&alarm->time);
+       if (err)
+               goto done;
+
        /* with luck, no rollover is needed */
        t_now = rtc_tm_to_time64(&now);
        t_alm = rtc_tm_to_time64(&alarm->time);
@@ -278,9 +285,9 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
                dev_warn(&rtc->dev, "alarm rollover not handled\n");
        }
 
-done:
        err = rtc_valid_tm(&alarm->time);
 
+done:
        if (err) {
                dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n",
                        alarm->time.tm_year + 1900, alarm->time.tm_mon + 1,
diff --git a/drivers/rtc/nvmem.c b/drivers/rtc/nvmem.c
new file mode 100644 (file)
index 0000000..8567b4e
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * RTC subsystem, nvmem interface
+ *
+ * Copyright (C) 2017 Alexandre Belloni
+ *
+ * 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/err.h>
+#include <linux/types.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/rtc.h>
+#include <linux/sysfs.h>
+
+#include "rtc-core.h"
+
+/*
+ * Deprecated ABI compatibility, this should be removed at some point
+ */
+
+static const char nvram_warning[] = "Deprecated ABI, please use nvmem";
+
+static ssize_t
+rtc_nvram_read(struct file *filp, struct kobject *kobj,
+              struct bin_attribute *attr,
+              char *buf, loff_t off, size_t count)
+{
+       struct rtc_device *rtc = attr->private;
+
+       dev_warn_once(kobj_to_dev(kobj), nvram_warning);
+
+       return nvmem_device_read(rtc->nvmem, off, count, buf);
+}
+
+static ssize_t
+rtc_nvram_write(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct rtc_device *rtc = attr->private;
+
+       dev_warn_once(kobj_to_dev(kobj), nvram_warning);
+
+       return nvmem_device_write(rtc->nvmem, off, count, buf);
+}
+
+static int rtc_nvram_register(struct rtc_device *rtc)
+{
+       int err;
+
+       rtc->nvram = devm_kzalloc(rtc->dev.parent,
+                               sizeof(struct bin_attribute),
+                               GFP_KERNEL);
+       if (!rtc->nvram)
+               return -ENOMEM;
+
+       rtc->nvram->attr.name = "nvram";
+       rtc->nvram->attr.mode = 0644;
+       rtc->nvram->private = rtc;
+
+       sysfs_bin_attr_init(rtc->nvram);
+
+       rtc->nvram->read = rtc_nvram_read;
+       rtc->nvram->write = rtc_nvram_write;
+       rtc->nvram->size = rtc->nvmem_config->size;
+
+       err = sysfs_create_bin_file(&rtc->dev.parent->kobj,
+                                   rtc->nvram);
+       if (err) {
+               devm_kfree(rtc->dev.parent, rtc->nvram);
+               rtc->nvram = NULL;
+       }
+
+       return err;
+}
+
+static void rtc_nvram_unregister(struct rtc_device *rtc)
+{
+       sysfs_remove_bin_file(&rtc->dev.parent->kobj, rtc->nvram);
+}
+
+/*
+ * New ABI, uses nvmem
+ */
+void rtc_nvmem_register(struct rtc_device *rtc)
+{
+       if (!rtc->nvmem_config)
+               return;
+
+       rtc->nvmem_config->dev = &rtc->dev;
+       rtc->nvmem_config->owner = rtc->owner;
+       rtc->nvmem = nvmem_register(rtc->nvmem_config);
+       if (IS_ERR_OR_NULL(rtc->nvmem))
+               return;
+
+       /* Register the old ABI */
+       if (rtc->nvram_old_abi)
+               rtc_nvram_register(rtc);
+}
+
+void rtc_nvmem_unregister(struct rtc_device *rtc)
+{
+       if (IS_ERR_OR_NULL(rtc->nvmem))
+               return;
+
+       /* unregister the old ABI */
+       if (rtc->nvram)
+               rtc_nvram_unregister(rtc);
+
+       nvmem_unregister(rtc->nvmem);
+}
index b60fd47..e221b78 100644 (file)
@@ -409,6 +409,11 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       rtc = devm_rtc_allocate_device(&pdev->dev);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+       platform_set_drvdata(pdev, rtc);
+
        sclk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(sclk))
                return PTR_ERR(sclk);
@@ -441,13 +446,10 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
        if (!device_can_wakeup(&pdev->dev))
                device_init_wakeup(&pdev->dev, 1);
 
-       rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
-                               &at91_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc)) {
-               ret = PTR_ERR(rtc);
+       rtc->ops = &at91_rtc_ops;
+       ret = rtc_register_device(rtc);
+       if (ret)
                goto err_clk;
-       }
-       platform_set_drvdata(pdev, rtc);
 
        /* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy
         * completion.
diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c
new file mode 100644 (file)
index 0000000..796ac79
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Copyright © 2014-2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_wakeup.h>
+#include <linux/reboot.h>
+#include <linux/rtc.h>
+#include <linux/stat.h>
+#include <linux/suspend.h>
+
+struct brcmstb_waketmr {
+       struct rtc_device *rtc;
+       struct device *dev;
+       void __iomem *base;
+       int irq;
+       struct notifier_block reboot_notifier;
+       struct clk *clk;
+       u32 rate;
+};
+
+#define BRCMSTB_WKTMR_EVENT            0x00
+#define BRCMSTB_WKTMR_COUNTER          0x04
+#define BRCMSTB_WKTMR_ALARM            0x08
+#define BRCMSTB_WKTMR_PRESCALER                0x0C
+#define BRCMSTB_WKTMR_PRESCALER_VAL    0x10
+
+#define BRCMSTB_WKTMR_DEFAULT_FREQ     27000000
+
+static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer)
+{
+       writel_relaxed(1, timer->base + BRCMSTB_WKTMR_EVENT);
+       (void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
+}
+
+static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer,
+                                     unsigned int secs)
+{
+       brcmstb_waketmr_clear_alarm(timer);
+
+       writel_relaxed(secs + 1, timer->base + BRCMSTB_WKTMR_ALARM);
+}
+
+static irqreturn_t brcmstb_waketmr_irq(int irq, void *data)
+{
+       struct brcmstb_waketmr *timer = data;
+
+       pm_wakeup_event(timer->dev, 0);
+
+       return IRQ_HANDLED;
+}
+
+struct wktmr_time {
+       u32 sec;
+       u32 pre;
+};
+
+static void wktmr_read(struct brcmstb_waketmr *timer,
+                      struct wktmr_time *t)
+{
+       u32 tmp;
+
+       do {
+               t->sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
+               tmp = readl_relaxed(timer->base + BRCMSTB_WKTMR_PRESCALER_VAL);
+       } while (tmp >= timer->rate);
+
+       t->pre = timer->rate - tmp;
+}
+
+static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer)
+{
+       struct device *dev = timer->dev;
+       int ret = 0;
+
+       if (device_may_wakeup(dev)) {
+               ret = enable_irq_wake(timer->irq);
+               if (ret) {
+                       dev_err(dev, "failed to enable wake-up interrupt\n");
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+/* If enabled as a wakeup-source, arm the timer when powering off */
+static int brcmstb_waketmr_reboot(struct notifier_block *nb,
+               unsigned long action, void *data)
+{
+       struct brcmstb_waketmr *timer;
+
+       timer = container_of(nb, struct brcmstb_waketmr, reboot_notifier);
+
+       /* Set timer for cold boot */
+       if (action == SYS_POWER_OFF)
+               brcmstb_waketmr_prepare_suspend(timer);
+
+       return NOTIFY_DONE;
+}
+
+static int brcmstb_waketmr_gettime(struct device *dev,
+                                  struct rtc_time *tm)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+       struct wktmr_time now;
+
+       wktmr_read(timer, &now);
+
+       rtc_time_to_tm(now.sec, tm);
+
+       return 0;
+}
+
+static int brcmstb_waketmr_settime(struct device *dev,
+                                  struct rtc_time *tm)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+       time64_t sec;
+
+       sec = rtc_tm_to_time64(tm);
+
+       if (sec > U32_MAX || sec < 0)
+               return -EINVAL;
+
+       writel_relaxed(sec, timer->base + BRCMSTB_WKTMR_COUNTER);
+
+       return 0;
+}
+
+static int brcmstb_waketmr_getalarm(struct device *dev,
+                                   struct rtc_wkalrm *alarm)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+       time64_t sec;
+       u32 reg;
+
+       sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM);
+       if (sec != 0) {
+               /* Alarm is enabled */
+               alarm->enabled = 1;
+               rtc_time64_to_tm(sec, &alarm->time);
+       }
+
+       reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
+       alarm->pending = !!(reg & 1);
+
+       return 0;
+}
+
+static int brcmstb_waketmr_setalarm(struct device *dev,
+                                    struct rtc_wkalrm *alarm)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+       time64_t sec;
+
+       if (alarm->enabled)
+               sec = rtc_tm_to_time64(&alarm->time);
+       else
+               sec = 0;
+
+       if (sec > U32_MAX || sec < 0)
+               return -EINVAL;
+
+       brcmstb_waketmr_set_alarm(timer, sec);
+
+       return 0;
+}
+
+/*
+ * Does not do much but keep the RTC class happy. We always support
+ * alarms.
+ */
+static int brcmstb_waketmr_alarm_enable(struct device *dev,
+                                       unsigned int enabled)
+{
+       return 0;
+}
+
+static const struct rtc_class_ops brcmstb_waketmr_ops = {
+       .read_time      = brcmstb_waketmr_gettime,
+       .set_time       = brcmstb_waketmr_settime,
+       .read_alarm     = brcmstb_waketmr_getalarm,
+       .set_alarm      = brcmstb_waketmr_setalarm,
+       .alarm_irq_enable = brcmstb_waketmr_alarm_enable,
+};
+
+static int brcmstb_waketmr_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct brcmstb_waketmr *timer;
+       struct resource *res;
+       int ret;
+
+       timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL);
+       if (!timer)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, timer);
+       timer->dev = dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       timer->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(timer->base))
+               return PTR_ERR(timer->base);
+
+       /*
+        * Set wakeup capability before requesting wakeup interrupt, so we can
+        * process boot-time "wakeups" (e.g., from S5 soft-off)
+        */
+       device_set_wakeup_capable(dev, true);
+       device_wakeup_enable(dev);
+
+       timer->irq = platform_get_irq(pdev, 0);
+       if (timer->irq < 0)
+               return -ENODEV;
+
+       timer->clk = devm_clk_get(dev, NULL);
+       if (!IS_ERR(timer->clk)) {
+               ret = clk_prepare_enable(timer->clk);
+               if (ret)
+                       return ret;
+               timer->rate = clk_get_rate(timer->clk);
+               if (!timer->rate)
+                       timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ;
+       } else {
+               timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ;
+               timer->clk = NULL;
+       }
+
+       ret = devm_request_irq(dev, timer->irq, brcmstb_waketmr_irq, 0,
+                              "brcmstb-waketimer", timer);
+       if (ret < 0)
+               return ret;
+
+       timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot;
+       register_reboot_notifier(&timer->reboot_notifier);
+
+       timer->rtc = rtc_device_register("brcmstb-waketmr", dev,
+                                        &brcmstb_waketmr_ops, THIS_MODULE);
+       if (IS_ERR(timer->rtc)) {
+               dev_err(dev, "unable to register device\n");
+               unregister_reboot_notifier(&timer->reboot_notifier);
+               return PTR_ERR(timer->rtc);
+       }
+
+       dev_info(dev, "registered, with irq %d\n", timer->irq);
+
+       return ret;
+}
+
+static int brcmstb_waketmr_remove(struct platform_device *pdev)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(&pdev->dev);
+
+       unregister_reboot_notifier(&timer->reboot_notifier);
+       rtc_device_unregister(timer->rtc);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int brcmstb_waketmr_suspend(struct device *dev)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+
+       return brcmstb_waketmr_prepare_suspend(timer);
+}
+
+static int brcmstb_waketmr_resume(struct device *dev)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+       int ret;
+
+       if (!device_may_wakeup(dev))
+               return 0;
+
+       ret = disable_irq_wake(timer->irq);
+
+       brcmstb_waketmr_clear_alarm(timer);
+
+       return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(brcmstb_waketmr_pm_ops,
+                        brcmstb_waketmr_suspend, brcmstb_waketmr_resume);
+
+static const struct of_device_id brcmstb_waketmr_of_match[] = {
+       { .compatible = "brcm,brcmstb-waketimer" },
+       { /* sentinel */ },
+};
+
+static struct platform_driver brcmstb_waketmr_driver = {
+       .probe                  = brcmstb_waketmr_probe,
+       .remove                 = brcmstb_waketmr_remove,
+       .driver = {
+               .name           = "brcmstb-waketimer",
+               .pm             = &brcmstb_waketmr_pm_ops,
+               .of_match_table = of_match_ptr(brcmstb_waketmr_of_match),
+       }
+};
+module_platform_driver(brcmstb_waketmr_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Brian Norris");
+MODULE_AUTHOR("Markus Mayer");
+MODULE_DESCRIPTION("Wake-up timer driver for STB chips");
index 7a4ed2f..ecab76a 100644 (file)
@@ -45,3 +45,11 @@ static inline const struct attribute_group **rtc_get_dev_attribute_groups(void)
        return NULL;
 }
 #endif
+
+#ifdef CONFIG_RTC_NVMEM
+void rtc_nvmem_register(struct rtc_device *rtc);
+void rtc_nvmem_unregister(struct rtc_device *rtc);
+#else
+static inline void rtc_nvmem_register(struct rtc_device *rtc) {}
+static inline void rtc_nvmem_unregister(struct rtc_device *rtc) {}
+#endif
index e81a871..794bc4f 100644 (file)
@@ -464,7 +464,7 @@ void rtc_dev_prepare(struct rtc_device *rtc)
                return;
 
        if (rtc->id >= RTC_DEV_MAX) {
-               dev_dbg(&rtc->dev, "%s: too many RTC devices\n", rtc->name);
+               dev_dbg(&rtc->dev, "too many RTC devices\n");
                return;
        }
 
index 77339b3..4fac49e 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/clk-provider.h>
+#include <linux/regmap.h>
 
 /*
  * We can't determine type by probing, but if we expect pre-Linux code
@@ -33,6 +34,7 @@
  */
 enum ds_type {
        ds_1307,
+       ds_1308,
        ds_1337,
        ds_1338,
        ds_1339,
@@ -43,6 +45,7 @@ enum ds_type {
        m41t00,
        mcp794xx,
        rx_8025,
+       rx_8130,
        last_ds_type /* always last */
        /* rs5c372 too?  different address... */
 };
@@ -115,17 +118,16 @@ struct ds1307 {
        u8                      offset; /* register's offset */
        u8                      regs[11];
        u16                     nvram_offset;
-       struct bin_attribute    *nvram;
+       struct nvmem_config     nvmem_cfg;
        enum ds_type            type;
        unsigned long           flags;
 #define HAS_NVRAM      0               /* bit 0 == sysfs file active */
 #define HAS_ALARM      1               /* bit 1 == irq claimed */
-       struct i2c_client       *client;
+       struct device           *dev;
+       struct regmap           *regmap;
+       const char              *name;
+       int                     irq;
        struct rtc_device       *rtc;
-       s32 (*read_block_data)(const struct i2c_client *client, u8 command,
-                              u8 length, u8 *values);
-       s32 (*write_block_data)(const struct i2c_client *client, u8 command,
-                               u8 length, const u8 *values);
 #ifdef CONFIG_COMMON_CLK
        struct clk_hw           clks[2];
 #endif
@@ -135,21 +137,30 @@ struct chip_desc {
        unsigned                alarm:1;
        u16                     nvram_offset;
        u16                     nvram_size;
+       u8                      century_reg;
+       u8                      century_enable_bit;
+       u8                      century_bit;
        u16                     trickle_charger_reg;
        u8                      trickle_charger_setup;
-       u8                      (*do_trickle_setup)(struct i2c_client *, uint32_t, bool);
+       u8                      (*do_trickle_setup)(struct ds1307 *, uint32_t,
+                                                   bool);
 };
 
-static u8 do_trickle_setup_ds1339(struct i2c_client *,
-                                 uint32_t ohms, bool diode);
+static u8 do_trickle_setup_ds1339(struct ds1307 *, uint32_t ohms, bool diode);
 
 static struct chip_desc chips[last_ds_type] = {
        [ds_1307] = {
                .nvram_offset   = 8,
                .nvram_size     = 56,
        },
+       [ds_1308] = {
+               .nvram_offset   = 8,
+               .nvram_size     = 56,
+       },
        [ds_1337] = {
                .alarm          = 1,
+               .century_reg    = DS1307_REG_MONTH,
+               .century_bit    = DS1337_BIT_CENTURY,
        },
        [ds_1338] = {
                .nvram_offset   = 8,
@@ -157,10 +168,15 @@ static struct chip_desc chips[last_ds_type] = {
        },
        [ds_1339] = {
                .alarm          = 1,
+               .century_reg    = DS1307_REG_MONTH,
+               .century_bit    = DS1337_BIT_CENTURY,
                .trickle_charger_reg = 0x10,
                .do_trickle_setup = &do_trickle_setup_ds1339,
        },
        [ds_1340] = {
+               .century_reg    = DS1307_REG_HOUR,
+               .century_enable_bit = DS1340_BIT_CENTURY_EN,
+               .century_bit    = DS1340_BIT_CENTURY,
                .trickle_charger_reg = 0x08,
        },
        [ds_1388] = {
@@ -168,6 +184,14 @@ static struct chip_desc chips[last_ds_type] = {
        },
        [ds_3231] = {
                .alarm          = 1,
+               .century_reg    = DS1307_REG_MONTH,
+               .century_bit    = DS1337_BIT_CENTURY,
+       },
+       [rx_8130] = {
+               .alarm          = 1,
+               /* this is battery backed SRAM */
+               .nvram_offset   = 0x20,
+               .nvram_size     = 4,    /* 32bit (4 word x 8 bit) */
        },
        [mcp794xx] = {
                .alarm          = 1,
@@ -179,6 +203,7 @@ static struct chip_desc chips[last_ds_type] = {
 
 static const struct i2c_device_id ds1307_id[] = {
        { "ds1307", ds_1307 },
+       { "ds1308", ds_1308 },
        { "ds1337", ds_1337 },
        { "ds1338", ds_1338 },
        { "ds1339", ds_1339 },
@@ -192,6 +217,7 @@ static const struct i2c_device_id ds1307_id[] = {
        { "pt7c4338", ds_1307 },
        { "rx8025", rx_8025 },
        { "isl12057", ds_1337 },
+       { "rx8130", rx_8130 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ds1307_id);
@@ -203,6 +229,10 @@ static const struct of_device_id ds1307_of_match[] = {
                .data = (void *)ds_1307
        },
        {
+               .compatible = "dallas,ds1308",
+               .data = (void *)ds_1308
+       },
+       {
                .compatible = "dallas,ds1337",
                .data = (void *)ds_1337
        },
@@ -262,6 +292,7 @@ MODULE_DEVICE_TABLE(of, ds1307_of_match);
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id ds1307_acpi_ids[] = {
        { .id = "DS1307", .driver_data = ds_1307 },
+       { .id = "DS1308", .driver_data = ds_1308 },
        { .id = "DS1337", .driver_data = ds_1337 },
        { .id = "DS1338", .driver_data = ds_1338 },
        { .id = "DS1339", .driver_data = ds_1339 },
@@ -280,136 +311,6 @@ static const struct acpi_device_id ds1307_acpi_ids[] = {
 MODULE_DEVICE_TABLE(acpi, ds1307_acpi_ids);
 #endif
 
-/*----------------------------------------------------------------------*/
-
-#define BLOCK_DATA_MAX_TRIES 10
-
-static s32 ds1307_read_block_data_once(const struct i2c_client *client,
-                                      u8 command, u8 length, u8 *values)
-{
-       s32 i, data;
-
-       for (i = 0; i < length; i++) {
-               data = i2c_smbus_read_byte_data(client, command + i);
-               if (data < 0)
-                       return data;
-               values[i] = data;
-       }
-       return i;
-}
-
-static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command,
-                                 u8 length, u8 *values)
-{
-       u8 oldvalues[255];
-       s32 ret;
-       int tries = 0;
-
-       dev_dbg(&client->dev, "ds1307_read_block_data (length=%d)\n", length);
-       ret = ds1307_read_block_data_once(client, command, length, values);
-       if (ret < 0)
-               return ret;
-       do {
-               if (++tries > BLOCK_DATA_MAX_TRIES) {
-                       dev_err(&client->dev,
-                               "ds1307_read_block_data failed\n");
-                       return -EIO;
-               }
-               memcpy(oldvalues, values, length);
-               ret = ds1307_read_block_data_once(client, command, length,
-                                                 values);
-               if (ret < 0)
-                       return ret;
-       } while (memcmp(oldvalues, values, length));
-       return length;
-}
-
-static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command,
-                                  u8 length, const u8 *values)
-{
-       u8 currvalues[255];
-       int tries = 0;
-
-       dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length);
-       do {
-               s32 i, ret;
-
-               if (++tries > BLOCK_DATA_MAX_TRIES) {
-                       dev_err(&client->dev,
-                               "ds1307_write_block_data failed\n");
-                       return -EIO;
-               }
-               for (i = 0; i < length; i++) {
-                       ret = i2c_smbus_write_byte_data(client, command + i,
-                                                       values[i]);
-                       if (ret < 0)
-                               return ret;
-               }
-               ret = ds1307_read_block_data_once(client, command, length,
-                                                 currvalues);
-               if (ret < 0)
-                       return ret;
-       } while (memcmp(currvalues, values, length));
-       return length;
-}
-
-/*----------------------------------------------------------------------*/
-
-/* These RTC devices are not designed to be connected to a SMbus adapter.
-   SMbus limits block operations length to 32 bytes, whereas it's not
-   limited on I2C buses. As a result, accesses may exceed 32 bytes;
-   in that case, split them into smaller blocks */
-
-static s32 ds1307_native_smbus_write_block_data(const struct i2c_client *client,
-                               u8 command, u8 length, const u8 *values)
-{
-       u8 suboffset = 0;
-
-       if (length <= I2C_SMBUS_BLOCK_MAX) {
-               s32 retval = i2c_smbus_write_i2c_block_data(client,
-                                       command, length, values);
-               if (retval < 0)
-                       return retval;
-               return length;
-       }
-
-       while (suboffset < length) {
-               s32 retval = i2c_smbus_write_i2c_block_data(client,
-                               command + suboffset,
-                               min(I2C_SMBUS_BLOCK_MAX, length - suboffset),
-                               values + suboffset);
-               if (retval < 0)
-                       return retval;
-
-               suboffset += I2C_SMBUS_BLOCK_MAX;
-       }
-       return length;
-}
-
-static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client,
-                               u8 command, u8 length, u8 *values)
-{
-       u8 suboffset = 0;
-
-       if (length <= I2C_SMBUS_BLOCK_MAX)
-               return i2c_smbus_read_i2c_block_data(client,
-                                       command, length, values);
-
-       while (suboffset < length) {
-               s32 retval = i2c_smbus_read_i2c_block_data(client,
-                               command + suboffset,
-                               min(I2C_SMBUS_BLOCK_MAX, length - suboffset),
-                               values + suboffset);
-               if (retval < 0)
-                       return retval;
-
-               suboffset += I2C_SMBUS_BLOCK_MAX;
-       }
-       return length;
-}
-
-/*----------------------------------------------------------------------*/
-
 /*
  * The ds1337 and ds1339 both have two alarms, but we only use the first
  * one (with a "seconds" field).  For ds1337 we expect nINTA is our alarm
@@ -417,27 +318,24 @@ static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client,
  */
 static irqreturn_t ds1307_irq(int irq, void *dev_id)
 {
-       struct i2c_client       *client = dev_id;
-       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+       struct ds1307           *ds1307 = dev_id;
        struct mutex            *lock = &ds1307->rtc->ops_lock;
-       int                     stat, control;
+       int                     stat, ret;
 
        mutex_lock(lock);
-       stat = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
-       if (stat < 0)
+       ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &stat);
+       if (ret)
                goto out;
 
        if (stat & DS1337_BIT_A1I) {
                stat &= ~DS1337_BIT_A1I;
-               i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, stat);
+               regmap_write(ds1307->regmap, DS1337_REG_STATUS, stat);
 
-               control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
-               if (control < 0)
+               ret = regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL,
+                                        DS1337_BIT_A1IE, 0);
+               if (ret)
                        goto out;
 
-               control &= ~DS1337_BIT_A1IE;
-               i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control);
-
                rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
        }
 
@@ -452,14 +350,14 @@ out:
 static int ds1307_get_time(struct device *dev, struct rtc_time *t)
 {
        struct ds1307   *ds1307 = dev_get_drvdata(dev);
-       int             tmp;
+       int             tmp, ret;
+       const struct chip_desc *chip = &chips[ds1307->type];
 
        /* read the RTC date and time registers all at once */
-       tmp = ds1307->read_block_data(ds1307->client,
-               ds1307->offset, 7, ds1307->regs);
-       if (tmp != 7) {
-               dev_err(dev, "%s error %d\n", "read", tmp);
-               return -EIO;
+       ret = regmap_bulk_read(ds1307->regmap, ds1307->offset, ds1307->regs, 7);
+       if (ret) {
+               dev_err(dev, "%s error %d\n", "read", ret);
+               return ret;
        }
 
        dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs);
@@ -481,22 +379,9 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
        t->tm_mon = bcd2bin(tmp) - 1;
        t->tm_year = bcd2bin(ds1307->regs[DS1307_REG_YEAR]) + 100;
 
-#ifdef CONFIG_RTC_DRV_DS1307_CENTURY
-       switch (ds1307->type) {
-       case ds_1337:
-       case ds_1339:
-       case ds_3231:
-               if (ds1307->regs[DS1307_REG_MONTH] & DS1337_BIT_CENTURY)
-                       t->tm_year += 100;
-               break;
-       case ds_1340:
-               if (ds1307->regs[DS1307_REG_HOUR] & DS1340_BIT_CENTURY)
-                       t->tm_year += 100;
-               break;
-       default:
-               break;
-       }
-#endif
+       if (ds1307->regs[chip->century_reg] & chip->century_bit &&
+           IS_ENABLED(CONFIG_RTC_DRV_DS1307_CENTURY))
+               t->tm_year += 100;
 
        dev_dbg(dev, "%s secs=%d, mins=%d, "
                "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -511,6 +396,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
 static int ds1307_set_time(struct device *dev, struct rtc_time *t)
 {
        struct ds1307   *ds1307 = dev_get_drvdata(dev);
+       const struct chip_desc *chip = &chips[ds1307->type];
        int             result;
        int             tmp;
        u8              *buf = ds1307->regs;
@@ -521,24 +407,14 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
                t->tm_hour, t->tm_mday,
                t->tm_mon, t->tm_year, t->tm_wday);
 
-#ifdef CONFIG_RTC_DRV_DS1307_CENTURY
        if (t->tm_year < 100)
                return -EINVAL;
 
-       switch (ds1307->type) {
-       case ds_1337:
-       case ds_1339:
-       case ds_3231:
-       case ds_1340:
-               if (t->tm_year > 299)
-                       return -EINVAL;
-       default:
-               if (t->tm_year > 199)
-                       return -EINVAL;
-               break;
-       }
+#ifdef CONFIG_RTC_DRV_DS1307_CENTURY
+       if (t->tm_year > (chip->century_bit ? 299 : 199))
+               return -EINVAL;
 #else
-       if (t->tm_year < 100 || t->tm_year > 199)
+       if (t->tm_year > 199)
                return -EINVAL;
 #endif
 
@@ -553,19 +429,12 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
        tmp = t->tm_year - 100;
        buf[DS1307_REG_YEAR] = bin2bcd(tmp);
 
-       switch (ds1307->type) {
-       case ds_1337:
-       case ds_1339:
-       case ds_3231:
-               if (t->tm_year > 199)
-                       buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY;
-               break;
-       case ds_1340:
-               buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN;
-               if (t->tm_year > 199)
-                       buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY;
-               break;
-       case mcp794xx:
+       if (chip->century_enable_bit)
+               buf[chip->century_reg] |= chip->century_enable_bit;
+       if (t->tm_year > 199 && chip->century_bit)
+               buf[chip->century_reg] |= chip->century_bit;
+
+       if (ds1307->type == mcp794xx) {
                /*
                 * these bits were cleared when preparing the date/time
                 * values and need to be set again before writing the
@@ -573,16 +442,12 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
                 */
                buf[DS1307_REG_SECS] |= MCP794XX_BIT_ST;
                buf[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN;
-               break;
-       default:
-               break;
        }
 
        dev_dbg(dev, "%s: %7ph\n", "write", buf);
 
-       result = ds1307->write_block_data(ds1307->client,
-               ds1307->offset, 7, buf);
-       if (result < 0) {
+       result = regmap_bulk_write(ds1307->regmap, ds1307->offset, buf, 7);
+       if (result) {
                dev_err(dev, "%s error %d\n", "write", result);
                return result;
        }
@@ -591,19 +456,18 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
 
 static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
-       struct i2c_client       *client = to_i2c_client(dev);
-       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+       struct ds1307           *ds1307 = dev_get_drvdata(dev);
        int                     ret;
 
        if (!test_bit(HAS_ALARM, &ds1307->flags))
                return -EINVAL;
 
        /* read all ALARM1, ALARM2, and status registers at once */
-       ret = ds1307->read_block_data(client,
-                       DS1339_REG_ALARM1_SECS, 9, ds1307->regs);
-       if (ret != 9) {
+       ret = regmap_bulk_read(ds1307->regmap, DS1339_REG_ALARM1_SECS,
+                              ds1307->regs, 9);
+       if (ret) {
                dev_err(dev, "%s error %d\n", "alarm read", ret);
-               return -EIO;
+               return ret;
        }
 
        dev_dbg(dev, "%s: %4ph, %3ph, %2ph\n", "alarm read",
@@ -633,8 +497,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
 
 static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
-       struct i2c_client       *client = to_i2c_client(dev);
-       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+       struct ds1307           *ds1307 = dev_get_drvdata(dev);
        unsigned char           *buf = ds1307->regs;
        u8                      control, status;
        int                     ret;
@@ -649,11 +512,10 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
                t->enabled, t->pending);
 
        /* read current status of both alarms and the chip */
-       ret = ds1307->read_block_data(client,
-                       DS1339_REG_ALARM1_SECS, 9, buf);
-       if (ret != 9) {
+       ret = regmap_bulk_read(ds1307->regmap, DS1339_REG_ALARM1_SECS, buf, 9);
+       if (ret) {
                dev_err(dev, "%s error %d\n", "alarm write", ret);
-               return -EIO;
+               return ret;
        }
        control = ds1307->regs[7];
        status = ds1307->regs[8];
@@ -676,9 +538,8 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        buf[7] = control & ~(DS1337_BIT_A1IE | DS1337_BIT_A2IE);
        buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I);
 
-       ret = ds1307->write_block_data(client,
-                       DS1339_REG_ALARM1_SECS, 9, buf);
-       if (ret < 0) {
+       ret = regmap_bulk_write(ds1307->regmap, DS1339_REG_ALARM1_SECS, buf, 9);
+       if (ret) {
                dev_err(dev, "can't set alarm time\n");
                return ret;
        }
@@ -687,7 +548,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        if (t->enabled) {
                dev_dbg(dev, "alarm IRQ armed\n");
                buf[7] |= DS1337_BIT_A1IE;      /* only ALARM1 is used */
-               i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, buf[7]);
+               regmap_write(ds1307->regmap, DS1337_REG_CONTROL, buf[7]);
        }
 
        return 0;
@@ -695,35 +556,181 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 
 static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
-       struct i2c_client       *client = to_i2c_client(dev);
-       struct ds1307           *ds1307 = i2c_get_clientdata(client);
-       int                     ret;
+       struct ds1307           *ds1307 = dev_get_drvdata(dev);
 
        if (!test_bit(HAS_ALARM, &ds1307->flags))
                return -ENOTTY;
 
-       ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+       return regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL,
+                                 DS1337_BIT_A1IE,
+                                 enabled ? DS1337_BIT_A1IE : 0);
+}
+
+static const struct rtc_class_ops ds13xx_rtc_ops = {
+       .read_time      = ds1307_get_time,
+       .set_time       = ds1307_set_time,
+       .read_alarm     = ds1337_read_alarm,
+       .set_alarm      = ds1337_set_alarm,
+       .alarm_irq_enable = ds1307_alarm_irq_enable,
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Alarm support for rx8130 devices.
+ */
+
+#define RX8130_REG_ALARM_MIN           0x07
+#define RX8130_REG_ALARM_HOUR          0x08
+#define RX8130_REG_ALARM_WEEK_OR_DAY   0x09
+#define RX8130_REG_EXTENSION           0x0c
+#define RX8130_REG_EXTENSION_WADA      (1 << 3)
+#define RX8130_REG_FLAG                        0x0d
+#define RX8130_REG_FLAG_AF             (1 << 3)
+#define RX8130_REG_CONTROL0            0x0e
+#define RX8130_REG_CONTROL0_AIE                (1 << 3)
+
+static irqreturn_t rx8130_irq(int irq, void *dev_id)
+{
+       struct ds1307           *ds1307 = dev_id;
+       struct mutex            *lock = &ds1307->rtc->ops_lock;
+       u8 ctl[3];
+       int ret;
+
+       mutex_lock(lock);
+
+       /* Read control registers. */
+       ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3);
        if (ret < 0)
-               return ret;
+               goto out;
+       if (!(ctl[1] & RX8130_REG_FLAG_AF))
+               goto out;
+       ctl[1] &= ~RX8130_REG_FLAG_AF;
+       ctl[2] &= ~RX8130_REG_CONTROL0_AIE;
 
-       if (enabled)
-               ret |= DS1337_BIT_A1IE;
-       else
-               ret &= ~DS1337_BIT_A1IE;
+       ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3);
+       if (ret < 0)
+               goto out;
+
+       rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
+
+out:
+       mutex_unlock(lock);
+
+       return IRQ_HANDLED;
+}
 
-       ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, ret);
+static int rx8130_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+       struct ds1307 *ds1307 = dev_get_drvdata(dev);
+       u8 ald[3], ctl[3];
+       int ret;
+
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -EINVAL;
+
+       /* Read alarm registers. */
+       ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_ALARM_MIN, ald, 3);
        if (ret < 0)
                return ret;
 
+       /* Read control registers. */
+       ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3);
+       if (ret < 0)
+               return ret;
+
+       t->enabled = !!(ctl[2] & RX8130_REG_CONTROL0_AIE);
+       t->pending = !!(ctl[1] & RX8130_REG_FLAG_AF);
+
+       /* Report alarm 0 time assuming 24-hour and day-of-month modes. */
+       t->time.tm_sec = -1;
+       t->time.tm_min = bcd2bin(ald[0] & 0x7f);
+       t->time.tm_hour = bcd2bin(ald[1] & 0x7f);
+       t->time.tm_wday = -1;
+       t->time.tm_mday = bcd2bin(ald[2] & 0x7f);
+       t->time.tm_mon = -1;
+       t->time.tm_year = -1;
+       t->time.tm_yday = -1;
+       t->time.tm_isdst = -1;
+
+       dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d enabled=%d\n",
+               __func__, t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
+               t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled);
+
        return 0;
 }
 
-static const struct rtc_class_ops ds13xx_rtc_ops = {
+static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+       struct ds1307 *ds1307 = dev_get_drvdata(dev);
+       u8 ald[3], ctl[3];
+       int ret;
+
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -EINVAL;
+
+       dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
+               "enabled=%d pending=%d\n", __func__,
+               t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
+               t->time.tm_wday, t->time.tm_mday, t->time.tm_mon,
+               t->enabled, t->pending);
+
+       /* Read control registers. */
+       ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3);
+       if (ret < 0)
+               return ret;
+
+       ctl[0] &= ~RX8130_REG_EXTENSION_WADA;
+       ctl[1] |= RX8130_REG_FLAG_AF;
+       ctl[2] &= ~RX8130_REG_CONTROL0_AIE;
+
+       ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3);
+       if (ret < 0)
+               return ret;
+
+       /* Hardware alarm precision is 1 minute! */
+       ald[0] = bin2bcd(t->time.tm_min);
+       ald[1] = bin2bcd(t->time.tm_hour);
+       ald[2] = bin2bcd(t->time.tm_mday);
+
+       ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_ALARM_MIN, ald, 3);
+       if (ret < 0)
+               return ret;
+
+       if (!t->enabled)
+               return 0;
+
+       ctl[2] |= RX8130_REG_CONTROL0_AIE;
+
+       return regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3);
+}
+
+static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct ds1307 *ds1307 = dev_get_drvdata(dev);
+       int ret, reg;
+
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -EINVAL;
+
+       ret = regmap_read(ds1307->regmap, RX8130_REG_CONTROL0, &reg);
+       if (ret < 0)
+               return ret;
+
+       if (enabled)
+               reg |= RX8130_REG_CONTROL0_AIE;
+       else
+               reg &= ~RX8130_REG_CONTROL0_AIE;
+
+       return regmap_write(ds1307->regmap, RX8130_REG_CONTROL0, reg);
+}
+
+static const struct rtc_class_ops rx8130_rtc_ops = {
        .read_time      = ds1307_get_time,
        .set_time       = ds1307_set_time,
-       .read_alarm     = ds1337_read_alarm,
-       .set_alarm      = ds1337_set_alarm,
-       .alarm_irq_enable = ds1307_alarm_irq_enable,
+       .read_alarm     = rx8130_read_alarm,
+       .set_alarm      = rx8130_set_alarm,
+       .alarm_irq_enable = rx8130_alarm_irq_enable,
 };
 
 /*----------------------------------------------------------------------*/
@@ -752,31 +759,27 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
 
 static irqreturn_t mcp794xx_irq(int irq, void *dev_id)
 {
-       struct i2c_client       *client = dev_id;
-       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+       struct ds1307           *ds1307 = dev_id;
        struct mutex            *lock = &ds1307->rtc->ops_lock;
        int reg, ret;
 
        mutex_lock(lock);
 
        /* Check and clear alarm 0 interrupt flag. */
-       reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_ALARM0_CTRL);
-       if (reg < 0)
+       ret = regmap_read(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, &reg);
+       if (ret)
                goto out;
        if (!(reg & MCP794XX_BIT_ALMX_IF))
                goto out;
        reg &= ~MCP794XX_BIT_ALMX_IF;
-       ret = i2c_smbus_write_byte_data(client, MCP794XX_REG_ALARM0_CTRL, reg);
-       if (ret < 0)
+       ret = regmap_write(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, reg);
+       if (ret)
                goto out;
 
        /* Disable alarm 0. */
-       reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_CONTROL);
-       if (reg < 0)
-               goto out;
-       reg &= ~MCP794XX_BIT_ALM0_EN;
-       ret = i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, reg);
-       if (ret < 0)
+       ret = regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL,
+                                MCP794XX_BIT_ALM0_EN, 0);
+       if (ret)
                goto out;
 
        rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
@@ -789,8 +792,7 @@ out:
 
 static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct ds1307 *ds1307 = i2c_get_clientdata(client);
+       struct ds1307 *ds1307 = dev_get_drvdata(dev);
        u8 *regs = ds1307->regs;
        int ret;
 
@@ -798,8 +800,8 @@ static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t)
                return -EINVAL;
 
        /* Read control and alarm 0 registers. */
-       ret = ds1307->read_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
-       if (ret < 0)
+       ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs, 10);
+       if (ret)
                return ret;
 
        t->enabled = !!(regs[0] & MCP794XX_BIT_ALM0_EN);
@@ -828,8 +830,7 @@ static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t)
 
 static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct ds1307 *ds1307 = i2c_get_clientdata(client);
+       struct ds1307 *ds1307 = dev_get_drvdata(dev);
        unsigned char *regs = ds1307->regs;
        int ret;
 
@@ -843,8 +844,8 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
                t->enabled, t->pending);
 
        /* Read control and alarm 0 registers. */
-       ret = ds1307->read_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
-       if (ret < 0)
+       ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs, 10);
+       if (ret)
                return ret;
 
        /* Set alarm 0, using 24-hour and day-of-month modes. */
@@ -862,35 +863,26 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        /* Disable interrupt. We will not enable until completely programmed */
        regs[0] &= ~MCP794XX_BIT_ALM0_EN;
 
-       ret = ds1307->write_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
-       if (ret < 0)
+       ret = regmap_bulk_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs, 10);
+       if (ret)
                return ret;
 
        if (!t->enabled)
                return 0;
        regs[0] |= MCP794XX_BIT_ALM0_EN;
-       return i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, regs[0]);
+       return regmap_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs[0]);
 }
 
 static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct ds1307 *ds1307 = i2c_get_clientdata(client);
-       int reg;
+       struct ds1307 *ds1307 = dev_get_drvdata(dev);
 
        if (!test_bit(HAS_ALARM, &ds1307->flags))
                return -EINVAL;
 
-       reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_CONTROL);
-       if (reg < 0)
-               return reg;
-
-       if (enabled)
-               reg |= MCP794XX_BIT_ALM0_EN;
-       else
-               reg &= ~MCP794XX_BIT_ALM0_EN;
-
-       return i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, reg);
+       return regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL,
+                                 MCP794XX_BIT_ALM0_EN,
+                                 enabled ? MCP794XX_BIT_ALM0_EN : 0);
 }
 
 static const struct rtc_class_ops mcp794xx_rtc_ops = {
@@ -903,50 +895,27 @@ static const struct rtc_class_ops mcp794xx_rtc_ops = {
 
 /*----------------------------------------------------------------------*/
 
-static ssize_t
-ds1307_nvram_read(struct file *filp, struct kobject *kobj,
-               struct bin_attribute *attr,
-               char *buf, loff_t off, size_t count)
+static int ds1307_nvram_read(void *priv, unsigned int offset, void *val,
+                            size_t bytes)
 {
-       struct i2c_client       *client;
-       struct ds1307           *ds1307;
-       int                     result;
+       struct ds1307 *ds1307 = priv;
 
-       client = kobj_to_i2c_client(kobj);
-       ds1307 = i2c_get_clientdata(client);
-
-       result = ds1307->read_block_data(client, ds1307->nvram_offset + off,
-                                                               count, buf);
-       if (result < 0)
-               dev_err(&client->dev, "%s error %d\n", "nvram read", result);
-       return result;
+       return regmap_bulk_read(ds1307->regmap, ds1307->nvram_offset + offset,
+                               val, bytes);
 }
 
-static ssize_t
-ds1307_nvram_write(struct file *filp, struct kobject *kobj,
-               struct bin_attribute *attr,
-               char *buf, loff_t off, size_t count)
+static int ds1307_nvram_write(void *priv, unsigned int offset, void *val,
+                             size_t bytes)
 {
-       struct i2c_client       *client;
-       struct ds1307           *ds1307;
-       int                     result;
+       struct ds1307 *ds1307 = priv;
 
-       client = kobj_to_i2c_client(kobj);
-       ds1307 = i2c_get_clientdata(client);
-
-       result = ds1307->write_block_data(client, ds1307->nvram_offset + off,
-                                                               count, buf);
-       if (result < 0) {
-               dev_err(&client->dev, "%s error %d\n", "nvram write", result);
-               return result;
-       }
-       return count;
+       return regmap_bulk_write(ds1307->regmap, ds1307->nvram_offset + offset,
+                                val, bytes);
 }
 
-
 /*----------------------------------------------------------------------*/
 
-static u8 do_trickle_setup_ds1339(struct i2c_client *client,
+static u8 do_trickle_setup_ds1339(struct ds1307 *ds1307,
                                  uint32_t ohms, bool diode)
 {
        u8 setup = (diode) ? DS1307_TRICKLE_CHARGER_DIODE :
@@ -963,14 +932,14 @@ static u8 do_trickle_setup_ds1339(struct i2c_client *client,
                setup |= DS1307_TRICKLE_CHARGER_4K_OHM;
                break;
        default:
-               dev_warn(&client->dev,
+               dev_warn(ds1307->dev,
                         "Unsupported ohm value %u in dt\n", ohms);
                return 0;
        }
        return setup;
 }
 
-static void ds1307_trickle_init(struct i2c_client *client,
+static void ds1307_trickle_init(struct ds1307 *ds1307,
                                struct chip_desc *chip)
 {
        uint32_t ohms = 0;
@@ -978,11 +947,12 @@ static void ds1307_trickle_init(struct i2c_client *client,
 
        if (!chip->do_trickle_setup)
                goto out;
-       if (device_property_read_u32(&client->dev, "trickle-resistor-ohms", &ohms))
+       if (device_property_read_u32(ds1307->dev, "trickle-resistor-ohms",
+                                    &ohms))
                goto out;
-       if (device_property_read_bool(&client->dev, "trickle-diode-disable"))
+       if (device_property_read_bool(ds1307->dev, "trickle-diode-disable"))
                diode = false;
-       chip->trickle_charger_setup = chip->do_trickle_setup(client,
+       chip->trickle_charger_setup = chip->do_trickle_setup(ds1307,
                                                             ohms, diode);
 out:
        return;
@@ -1009,13 +979,10 @@ static int ds3231_hwmon_read_temp(struct device *dev, s32 *mC)
        s16 temp;
        int ret;
 
-       ret = ds1307->read_block_data(ds1307->client, DS3231_REG_TEMPERATURE,
-                                       sizeof(temp_buf), temp_buf);
-       if (ret < 0)
+       ret = regmap_bulk_read(ds1307->regmap, DS3231_REG_TEMPERATURE,
+                              temp_buf, sizeof(temp_buf));
+       if (ret)
                return ret;
-       if (ret != sizeof(temp_buf))
-               return -EIO;
-
        /*
         * Temperature is represented as a 10-bit code with a resolution of
         * 0.25 degree celsius and encoded in two's complement format.
@@ -1055,12 +1022,11 @@ static void ds1307_hwmon_register(struct ds1307 *ds1307)
        if (ds1307->type != ds_3231)
                return;
 
-       dev = devm_hwmon_device_register_with_groups(&ds1307->client->dev,
-                                               ds1307->client->name,
+       dev = devm_hwmon_device_register_with_groups(ds1307->dev, ds1307->name,
                                                ds1307, ds3231_hwmon_groups);
        if (IS_ERR(dev)) {
-               dev_warn(&ds1307->client->dev,
-                       "unable to register hwmon device %ld\n", PTR_ERR(dev));
+               dev_warn(ds1307->dev, "unable to register hwmon device %ld\n",
+                        PTR_ERR(dev));
        }
 }
 
@@ -1099,24 +1065,12 @@ static int ds3231_clk_sqw_rates[] = {
 
 static int ds1337_write_control(struct ds1307 *ds1307, u8 mask, u8 value)
 {
-       struct i2c_client *client = ds1307->client;
        struct mutex *lock = &ds1307->rtc->ops_lock;
-       int control;
        int ret;
 
        mutex_lock(lock);
-
-       control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
-       if (control < 0) {
-               ret = control;
-               goto out;
-       }
-
-       control &= ~mask;
-       control |= value;
-
-       ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control);
-out:
+       ret = regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL,
+                                mask, value);
        mutex_unlock(lock);
 
        return ret;
@@ -1126,12 +1080,12 @@ static unsigned long ds3231_clk_sqw_recalc_rate(struct clk_hw *hw,
                                                unsigned long parent_rate)
 {
        struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
-       int control;
+       int control, ret;
        int rate_sel = 0;
 
-       control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL);
-       if (control < 0)
-               return control;
+       ret = regmap_read(ds1307->regmap, DS1337_REG_CONTROL, &control);
+       if (ret)
+               return ret;
        if (control & DS1337_BIT_RS1)
                rate_sel += 1;
        if (control & DS1337_BIT_RS2)
@@ -1195,11 +1149,11 @@ static void ds3231_clk_sqw_unprepare(struct clk_hw *hw)
 static int ds3231_clk_sqw_is_prepared(struct clk_hw *hw)
 {
        struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
-       int control;
+       int control, ret;
 
-       control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL);
-       if (control < 0)
-               return control;
+       ret = regmap_read(ds1307->regmap, DS1337_REG_CONTROL, &control);
+       if (ret)
+               return ret;
 
        return !(control & DS1337_BIT_INTCN);
 }
@@ -1221,26 +1175,13 @@ static unsigned long ds3231_clk_32khz_recalc_rate(struct clk_hw *hw,
 
 static int ds3231_clk_32khz_control(struct ds1307 *ds1307, bool enable)
 {
-       struct i2c_client *client = ds1307->client;
        struct mutex *lock = &ds1307->rtc->ops_lock;
-       int status;
        int ret;
 
        mutex_lock(lock);
-
-       status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
-       if (status < 0) {
-               ret = status;
-               goto out;
-       }
-
-       if (enable)
-               status |= DS3231_BIT_EN32KHZ;
-       else
-               status &= ~DS3231_BIT_EN32KHZ;
-
-       ret = i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, status);
-out:
+       ret = regmap_update_bits(ds1307->regmap, DS1337_REG_STATUS,
+                                DS3231_BIT_EN32KHZ,
+                                enable ? DS3231_BIT_EN32KHZ : 0);
        mutex_unlock(lock);
 
        return ret;
@@ -1263,11 +1204,11 @@ static void ds3231_clk_32khz_unprepare(struct clk_hw *hw)
 static int ds3231_clk_32khz_is_prepared(struct clk_hw *hw)
 {
        struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw);
-       int status;
+       int status, ret;
 
-       status = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_STATUS);
-       if (status < 0)
-               return status;
+       ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &status);
+       if (ret)
+               return ret;
 
        return !!(status & DS3231_BIT_EN32KHZ);
 }
@@ -1292,18 +1233,17 @@ static struct clk_init_data ds3231_clks_init[] = {
 
 static int ds3231_clks_register(struct ds1307 *ds1307)
 {
-       struct i2c_client *client = ds1307->client;
-       struct device_node *node = client->dev.of_node;
+       struct device_node *node = ds1307->dev->of_node;
        struct clk_onecell_data *onecell;
        int i;
 
-       onecell = devm_kzalloc(&client->dev, sizeof(*onecell), GFP_KERNEL);
+       onecell = devm_kzalloc(ds1307->dev, sizeof(*onecell), GFP_KERNEL);
        if (!onecell)
                return -ENOMEM;
 
        onecell->clk_num = ARRAY_SIZE(ds3231_clks_init);
-       onecell->clks = devm_kcalloc(&client->dev, onecell->clk_num,
-                                       sizeof(onecell->clks[0]), GFP_KERNEL);
+       onecell->clks = devm_kcalloc(ds1307->dev, onecell->clk_num,
+                                    sizeof(onecell->clks[0]), GFP_KERNEL);
        if (!onecell->clks)
                return -ENOMEM;
 
@@ -1322,8 +1262,8 @@ static int ds3231_clks_register(struct ds1307 *ds1307)
                                                &init.name);
                ds1307->clks[i].init = &init;
 
-               onecell->clks[i] = devm_clk_register(&client->dev,
-                                                       &ds1307->clks[i]);
+               onecell->clks[i] = devm_clk_register(ds1307->dev,
+                                                    &ds1307->clks[i]);
                if (IS_ERR(onecell->clks[i]))
                        return PTR_ERR(onecell->clks[i]);
        }
@@ -1345,8 +1285,8 @@ static void ds1307_clks_register(struct ds1307 *ds1307)
 
        ret = ds3231_clks_register(ds1307);
        if (ret) {
-               dev_warn(&ds1307->client->dev,
-                       "unable to register clock device %d\n", ret);
+               dev_warn(ds1307->dev, "unable to register clock device %d\n",
+                        ret);
        }
 }
 
@@ -1358,6 +1298,12 @@ static void ds1307_clks_register(struct ds1307 *ds1307)
 
 #endif /* CONFIG_COMMON_CLK */
 
+static const struct regmap_config regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0x12,
+};
+
 static int ds1307_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -1365,7 +1311,6 @@ static int ds1307_probe(struct i2c_client *client,
        int                     err = -ENODEV;
        int                     tmp, wday;
        struct chip_desc        *chip;
-       struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
        bool                    want_irq = false;
        bool                    ds1307_can_wakeup_device = false;
        unsigned char           *buf;
@@ -1382,17 +1327,22 @@ static int ds1307_probe(struct i2c_client *client,
        };
        const struct rtc_class_ops *rtc_ops = &ds13xx_rtc_ops;
 
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)
-           && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
-               return -EIO;
-
        ds1307 = devm_kzalloc(&client->dev, sizeof(struct ds1307), GFP_KERNEL);
        if (!ds1307)
                return -ENOMEM;
 
-       i2c_set_clientdata(client, ds1307);
+       dev_set_drvdata(&client->dev, ds1307);
+       ds1307->dev = &client->dev;
+       ds1307->name = client->name;
+       ds1307->irq = client->irq;
 
-       ds1307->client  = client;
+       ds1307->regmap = devm_regmap_init_i2c(client, &regmap_config);
+       if (IS_ERR(ds1307->regmap)) {
+               dev_err(ds1307->dev, "regmap allocation failed\n");
+               return PTR_ERR(ds1307->regmap);
+       }
+
+       i2c_set_clientdata(client, ds1307);
 
        if (client->dev.of_node) {
                ds1307->type = (enum ds_type)
@@ -1405,7 +1355,7 @@ static int ds1307_probe(struct i2c_client *client,
                const struct acpi_device_id *acpi_id;
 
                acpi_id = acpi_match_device(ACPI_PTR(ds1307_acpi_ids),
-                                           &client->dev);
+                                           ds1307->dev);
                if (!acpi_id)
                        return -ENODEV;
                chip = &chips[acpi_id->driver_data];
@@ -1413,27 +1363,21 @@ static int ds1307_probe(struct i2c_client *client,
        }
 
        if (!pdata)
-               ds1307_trickle_init(client, chip);
+               ds1307_trickle_init(ds1307, chip);
        else if (pdata->trickle_charger_setup)
                chip->trickle_charger_setup = pdata->trickle_charger_setup;
 
        if (chip->trickle_charger_setup && chip->trickle_charger_reg) {
-               dev_dbg(&client->dev, "writing trickle charger info 0x%x to 0x%x\n",
+               dev_dbg(ds1307->dev,
+                       "writing trickle charger info 0x%x to 0x%x\n",
                    DS13XX_TRICKLE_CHARGER_MAGIC | chip->trickle_charger_setup,
                    chip->trickle_charger_reg);
-               i2c_smbus_write_byte_data(client, chip->trickle_charger_reg,
+               regmap_write(ds1307->regmap, chip->trickle_charger_reg,
                    DS13XX_TRICKLE_CHARGER_MAGIC |
                    chip->trickle_charger_setup);
        }
 
        buf = ds1307->regs;
-       if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
-               ds1307->read_block_data = ds1307_native_smbus_read_block_data;
-               ds1307->write_block_data = ds1307_native_smbus_write_block_data;
-       } else {
-               ds1307->read_block_data = ds1307_read_block_data;
-               ds1307->write_block_data = ds1307_write_block_data;
-       }
 
 #ifdef CONFIG_OF
 /*
@@ -1459,11 +1403,10 @@ static int ds1307_probe(struct i2c_client *client,
        case ds_1339:
        case ds_3231:
                /* get registers that the "rtc" read below won't read... */
-               tmp = ds1307->read_block_data(ds1307->client,
-                               DS1337_REG_CONTROL, 2, buf);
-               if (tmp != 2) {
-                       dev_dbg(&client->dev, "read error %d\n", tmp);
-                       err = -EIO;
+               err = regmap_bulk_read(ds1307->regmap, DS1337_REG_CONTROL,
+                                      buf, 2);
+               if (err) {
+                       dev_dbg(ds1307->dev, "read error %d\n", err);
                        goto exit;
                }
 
@@ -1477,8 +1420,8 @@ static int ds1307_probe(struct i2c_client *client,
                 * For some variants, be sure alarms can trigger when we're
                 * running on Vbackup (BBSQI/BBSQW)
                 */
-               if (chip->alarm && (ds1307->client->irq > 0 ||
-                                               ds1307_can_wakeup_device)) {
+               if (chip->alarm && (ds1307->irq > 0 ||
+                                   ds1307_can_wakeup_device)) {
                        ds1307->regs[0] |= DS1337_BIT_INTCN
                                        | bbsqi_bitpos[ds1307->type];
                        ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
@@ -1486,50 +1429,49 @@ static int ds1307_probe(struct i2c_client *client,
                        want_irq = true;
                }
 
-               i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
-                                                       ds1307->regs[0]);
+               regmap_write(ds1307->regmap, DS1337_REG_CONTROL,
+                            ds1307->regs[0]);
 
                /* oscillator fault?  clear flag, and warn */
                if (ds1307->regs[1] & DS1337_BIT_OSF) {
-                       i2c_smbus_write_byte_data(client, DS1337_REG_STATUS,
-                               ds1307->regs[1] & ~DS1337_BIT_OSF);
-                       dev_warn(&client->dev, "SET TIME!\n");
+                       regmap_write(ds1307->regmap, DS1337_REG_STATUS,
+                                    ds1307->regs[1] & ~DS1337_BIT_OSF);
+                       dev_warn(ds1307->dev, "SET TIME!\n");
                }
                break;
 
        case rx_8025:
-               tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
-                               RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
-               if (tmp != 2) {
-                       dev_dbg(&client->dev, "read error %d\n", tmp);
-                       err = -EIO;
+               err = regmap_bulk_read(ds1307->regmap,
+                                      RX8025_REG_CTRL1 << 4 | 0x08, buf, 2);
+               if (err) {
+                       dev_dbg(ds1307->dev, "read error %d\n", err);
                        goto exit;
                }
 
                /* oscillator off?  turn it on, so clock can tick. */
                if (!(ds1307->regs[1] & RX8025_BIT_XST)) {
                        ds1307->regs[1] |= RX8025_BIT_XST;
-                       i2c_smbus_write_byte_data(client,
-                                                 RX8025_REG_CTRL2 << 4 | 0x08,
-                                                 ds1307->regs[1]);
-                       dev_warn(&client->dev,
+                       regmap_write(ds1307->regmap,
+                                    RX8025_REG_CTRL2 << 4 | 0x08,
+                                    ds1307->regs[1]);
+                       dev_warn(ds1307->dev,
                                 "oscillator stop detected - SET TIME!\n");
                }
 
                if (ds1307->regs[1] & RX8025_BIT_PON) {
                        ds1307->regs[1] &= ~RX8025_BIT_PON;
-                       i2c_smbus_write_byte_data(client,
-                                                 RX8025_REG_CTRL2 << 4 | 0x08,
-                                                 ds1307->regs[1]);
-                       dev_warn(&client->dev, "power-on detected\n");
+                       regmap_write(ds1307->regmap,
+                                    RX8025_REG_CTRL2 << 4 | 0x08,
+                                    ds1307->regs[1]);
+                       dev_warn(ds1307->dev, "power-on detected\n");
                }
 
                if (ds1307->regs[1] & RX8025_BIT_VDET) {
                        ds1307->regs[1] &= ~RX8025_BIT_VDET;
-                       i2c_smbus_write_byte_data(client,
-                                                 RX8025_REG_CTRL2 << 4 | 0x08,
-                                                 ds1307->regs[1]);
-                       dev_warn(&client->dev, "voltage drop detected\n");
+                       regmap_write(ds1307->regmap,
+                                    RX8025_REG_CTRL2 << 4 | 0x08,
+                                    ds1307->regs[1]);
+                       dev_warn(ds1307->dev, "voltage drop detected\n");
                }
 
                /* make sure we are running in 24hour mode */
@@ -1537,16 +1479,15 @@ static int ds1307_probe(struct i2c_client *client,
                        u8 hour;
 
                        /* switch to 24 hour mode */
-                       i2c_smbus_write_byte_data(client,
-                                                 RX8025_REG_CTRL1 << 4 | 0x08,
-                                                 ds1307->regs[0] |
-                                                 RX8025_BIT_2412);
-
-                       tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
-                                       RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
-                       if (tmp != 2) {
-                               dev_dbg(&client->dev, "read error %d\n", tmp);
-                               err = -EIO;
+                       regmap_write(ds1307->regmap,
+                                    RX8025_REG_CTRL1 << 4 | 0x08,
+                                    ds1307->regs[0] | RX8025_BIT_2412);
+
+                       err = regmap_bulk_read(ds1307->regmap,
+                                              RX8025_REG_CTRL1 << 4 | 0x08,
+                                              buf, 2);
+                       if (err) {
+                               dev_dbg(ds1307->dev, "read error %d\n", err);
                                goto exit;
                        }
 
@@ -1557,9 +1498,16 @@ static int ds1307_probe(struct i2c_client *client,
                        if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM)
                                hour += 12;
 
-                       i2c_smbus_write_byte_data(client,
-                                                 DS1307_REG_HOUR << 4 | 0x08,
-                                                 hour);
+                       regmap_write(ds1307->regmap,
+                                    DS1307_REG_HOUR << 4 | 0x08, hour);
+               }
+               break;
+       case rx_8130:
+               ds1307->offset = 0x10; /* Seconds starts at 0x10 */
+               rtc_ops = &rx8130_rtc_ops;
+               if (chip->alarm && ds1307->irq > 0) {
+                       irq_handler = rx8130_irq;
+                       want_irq = true;
                }
                break;
        case ds_1388:
@@ -1567,7 +1515,8 @@ static int ds1307_probe(struct i2c_client *client,
                break;
        case mcp794xx:
                rtc_ops = &mcp794xx_rtc_ops;
-               if (ds1307->client->irq > 0 && chip->alarm) {
+               if (chip->alarm && (ds1307->irq > 0 ||
+                                   ds1307_can_wakeup_device)) {
                        irq_handler = mcp794xx_irq;
                        want_irq = true;
                }
@@ -1578,10 +1527,9 @@ static int ds1307_probe(struct i2c_client *client,
 
 read_rtc:
        /* read RTC registers */
-       tmp = ds1307->read_block_data(ds1307->client, ds1307->offset, 8, buf);
-       if (tmp != 8) {
-               dev_dbg(&client->dev, "read error %d\n", tmp);
-               err = -EIO;
+       err = regmap_bulk_read(ds1307->regmap, ds1307->offset, buf, 8);
+       if (err) {
+               dev_dbg(ds1307->dev, "read error %d\n", err);
                goto exit;
        }
 
@@ -1597,56 +1545,56 @@ read_rtc:
        case m41t00:
                /* clock halted?  turn it on, so clock can tick. */
                if (tmp & DS1307_BIT_CH) {
-                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
-                       dev_warn(&client->dev, "SET TIME!\n");
+                       regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
+                       dev_warn(ds1307->dev, "SET TIME!\n");
                        goto read_rtc;
                }
                break;
+       case ds_1308:
        case ds_1338:
                /* clock halted?  turn it on, so clock can tick. */
                if (tmp & DS1307_BIT_CH)
-                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+                       regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
 
                /* oscillator fault?  clear flag, and warn */
                if (ds1307->regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) {
-                       i2c_smbus_write_byte_data(client, DS1307_REG_CONTROL,
-                                       ds1307->regs[DS1307_REG_CONTROL]
-                                       ~DS1338_BIT_OSF);
-                       dev_warn(&client->dev, "SET TIME!\n");
+                       regmap_write(ds1307->regmap, DS1307_REG_CONTROL,
+                                       ds1307->regs[DS1307_REG_CONTROL] &
+                                       ~DS1338_BIT_OSF);
+                       dev_warn(ds1307->dev, "SET TIME!\n");
                        goto read_rtc;
                }
                break;
        case ds_1340:
                /* clock halted?  turn it on, so clock can tick. */
                if (tmp & DS1340_BIT_nEOSC)
-                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+                       regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
 
-               tmp = i2c_smbus_read_byte_data(client, DS1340_REG_FLAG);
-               if (tmp < 0) {
-                       dev_dbg(&client->dev, "read error %d\n", tmp);
-                       err = -EIO;
+               err = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp);
+               if (err) {
+                       dev_dbg(ds1307->dev, "read error %d\n", err);
                        goto exit;
                }
 
                /* oscillator fault?  clear flag, and warn */
                if (tmp & DS1340_BIT_OSF) {
-                       i2c_smbus_write_byte_data(client, DS1340_REG_FLAG, 0);
-                       dev_warn(&client->dev, "SET TIME!\n");
+                       regmap_write(ds1307->regmap, DS1340_REG_FLAG, 0);
+                       dev_warn(ds1307->dev, "SET TIME!\n");
                }
                break;
        case mcp794xx:
                /* make sure that the backup battery is enabled */
                if (!(ds1307->regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) {
-                       i2c_smbus_write_byte_data(client, DS1307_REG_WDAY,
-                                       ds1307->regs[DS1307_REG_WDAY]
-                                       | MCP794XX_BIT_VBATEN);
+                       regmap_write(ds1307->regmap, DS1307_REG_WDAY,
+                                    ds1307->regs[DS1307_REG_WDAY] |
+                                    MCP794XX_BIT_VBATEN);
                }
 
                /* clock halted?  turn it on, so clock can tick. */
                if (!(tmp & MCP794XX_BIT_ST)) {
-                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS,
-                                       MCP794XX_BIT_ST);
-                       dev_warn(&client->dev, "SET TIME!\n");
+                       regmap_write(ds1307->regmap, DS1307_REG_SECS,
+                                    MCP794XX_BIT_ST);
+                       dev_warn(ds1307->dev, "SET TIME!\n");
                        goto read_rtc;
                }
 
@@ -1680,16 +1628,15 @@ read_rtc:
                        tmp = 0;
                if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM)
                        tmp += 12;
-               i2c_smbus_write_byte_data(client,
-                               ds1307->offset + DS1307_REG_HOUR,
-                               bin2bcd(tmp));
+               regmap_write(ds1307->regmap, ds1307->offset + DS1307_REG_HOUR,
+                            bin2bcd(tmp));
        }
 
        /*
         * Some IPs have weekday reset value = 0x1 which might not correct
         * hence compute the wday using the current date/month/year values
         */
-       ds1307_get_time(&client->dev, &tm);
+       ds1307_get_time(ds1307->dev, &tm);
        wday = tm.tm_wday;
        timestamp = rtc_tm_to_time64(&tm);
        rtc_time64_to_tm(timestamp, &tm);
@@ -1699,78 +1646,63 @@ read_rtc:
         * If different then set the wday which we computed using
         * timestamp
         */
-       if (wday != tm.tm_wday) {
-               wday = i2c_smbus_read_byte_data(client, MCP794XX_REG_WEEKDAY);
-               wday = wday & ~MCP794XX_REG_WEEKDAY_WDAY_MASK;
-               wday = wday | (tm.tm_wday + 1);
-               i2c_smbus_write_byte_data(client, MCP794XX_REG_WEEKDAY, wday);
-       }
+       if (wday != tm.tm_wday)
+               regmap_update_bits(ds1307->regmap, MCP794XX_REG_WEEKDAY,
+                                  MCP794XX_REG_WEEKDAY_WDAY_MASK,
+                                  tm.tm_wday + 1);
 
        if (want_irq) {
-               device_set_wakeup_capable(&client->dev, true);
+               device_set_wakeup_capable(ds1307->dev, true);
                set_bit(HAS_ALARM, &ds1307->flags);
        }
-       ds1307->rtc = devm_rtc_device_register(&client->dev, client->name,
-                               rtc_ops, THIS_MODULE);
+
+       ds1307->rtc = devm_rtc_allocate_device(ds1307->dev);
        if (IS_ERR(ds1307->rtc)) {
                return PTR_ERR(ds1307->rtc);
        }
 
-       if (ds1307_can_wakeup_device && ds1307->client->irq <= 0) {
+       if (ds1307_can_wakeup_device && ds1307->irq <= 0) {
                /* Disable request for an IRQ */
                want_irq = false;
-               dev_info(&client->dev, "'wakeup-source' is set, request for an IRQ is disabled!\n");
+               dev_info(ds1307->dev,
+                        "'wakeup-source' is set, request for an IRQ is disabled!\n");
                /* We cannot support UIE mode if we do not have an IRQ line */
                ds1307->rtc->uie_unsupported = 1;
        }
 
        if (want_irq) {
-               err = devm_request_threaded_irq(&client->dev,
-                                               client->irq, NULL, irq_handler,
+               err = devm_request_threaded_irq(ds1307->dev,
+                                               ds1307->irq, NULL, irq_handler,
                                                IRQF_SHARED | IRQF_ONESHOT,
-                                               ds1307->rtc->name, client);
+                                               ds1307->name, ds1307);
                if (err) {
                        client->irq = 0;
-                       device_set_wakeup_capable(&client->dev, false);
+                       device_set_wakeup_capable(ds1307->dev, false);
                        clear_bit(HAS_ALARM, &ds1307->flags);
-                       dev_err(&client->dev, "unable to request IRQ!\n");
+                       dev_err(ds1307->dev, "unable to request IRQ!\n");
                } else
-                       dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
+                       dev_dbg(ds1307->dev, "got IRQ %d\n", client->irq);
        }
 
        if (chip->nvram_size) {
-
-               ds1307->nvram = devm_kzalloc(&client->dev,
-                                       sizeof(struct bin_attribute),
-                                       GFP_KERNEL);
-               if (!ds1307->nvram) {
-                       dev_err(&client->dev, "cannot allocate memory for nvram sysfs\n");
-               } else {
-
-                       ds1307->nvram->attr.name = "nvram";
-                       ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
-
-                       sysfs_bin_attr_init(ds1307->nvram);
-
-                       ds1307->nvram->read = ds1307_nvram_read;
-                       ds1307->nvram->write = ds1307_nvram_write;
-                       ds1307->nvram->size = chip->nvram_size;
-                       ds1307->nvram_offset = chip->nvram_offset;
-
-                       err = sysfs_create_bin_file(&client->dev.kobj,
-                                                   ds1307->nvram);
-                       if (err) {
-                               dev_err(&client->dev,
-                                       "unable to create sysfs file: %s\n",
-                                       ds1307->nvram->attr.name);
-                       } else {
-                               set_bit(HAS_NVRAM, &ds1307->flags);
-                               dev_info(&client->dev, "%zu bytes nvram\n",
-                                        ds1307->nvram->size);
-                       }
-               }
+               ds1307->nvmem_cfg.name = "ds1307_nvram";
+               ds1307->nvmem_cfg.word_size = 1;
+               ds1307->nvmem_cfg.stride = 1;
+               ds1307->nvmem_cfg.size = chip->nvram_size;
+               ds1307->nvmem_cfg.reg_read = ds1307_nvram_read;
+               ds1307->nvmem_cfg.reg_write = ds1307_nvram_write;
+               ds1307->nvmem_cfg.priv = ds1307;
+               ds1307->nvram_offset = chip->nvram_offset;
+
+               ds1307->rtc->nvmem_config = &ds1307->nvmem_cfg;
+               ds1307->rtc->nvram_old_abi = true;
        }
 
+       ds1307->rtc->ops = rtc_ops;
+       err = rtc_register_device(ds1307->rtc);
+       if (err)
+               return err;
+
        ds1307_hwmon_register(ds1307);
        ds1307_clks_register(ds1307);
 
@@ -1780,16 +1712,6 @@ exit:
        return err;
 }
 
-static int ds1307_remove(struct i2c_client *client)
-{
-       struct ds1307 *ds1307 = i2c_get_clientdata(client);
-
-       if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
-               sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram);
-
-       return 0;
-}
-
 static struct i2c_driver ds1307_driver = {
        .driver = {
                .name   = "rtc-ds1307",
@@ -1797,7 +1719,6 @@ static struct i2c_driver ds1307_driver = {
                .acpi_match_table = ACPI_PTR(ds1307_acpi_ids),
        },
        .probe          = ds1307_probe,
-       .remove         = ds1307_remove,
        .id_table       = ds1307_id,
 };
 
index deff431..0550f7b 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/bcd.h>
 #include <linux/slab.h>
 #include <linux/regmap.h>
+#include <linux/hwmon.h>
 
 #define DS3232_REG_SECONDS      0x00
 #define DS3232_REG_MINUTES      0x01
@@ -46,6 +47,8 @@
 #       define DS3232_REG_SR_A2F     0x02
 #       define DS3232_REG_SR_A1F     0x01
 
+#define DS3232_REG_TEMPERATURE 0x11
+
 struct ds3232 {
        struct device *dev;
        struct regmap *regmap;
@@ -275,6 +278,120 @@ static int ds3232_update_alarm(struct device *dev, unsigned int enabled)
        return ret;
 }
 
+/*
+ * Temperature sensor support for ds3232/ds3234 devices.
+ * A user-initiated temperature conversion is not started by this function,
+ * so the temperature is updated once every 64 seconds.
+ */
+static int ds3232_hwmon_read_temp(struct device *dev, long int *mC)
+{
+       struct ds3232 *ds3232 = dev_get_drvdata(dev);
+       u8 temp_buf[2];
+       s16 temp;
+       int ret;
+
+       ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_TEMPERATURE, temp_buf,
+                              sizeof(temp_buf));
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Temperature is represented as a 10-bit code with a resolution of
+        * 0.25 degree celsius and encoded in two's complement format.
+        */
+       temp = (temp_buf[0] << 8) | temp_buf[1];
+       temp >>= 6;
+       *mC = temp * 250;
+
+       return 0;
+}
+
+static umode_t ds3232_hwmon_is_visible(const void *data,
+                                      enum hwmon_sensor_types type,
+                                      u32 attr, int channel)
+{
+       if (type != hwmon_temp)
+               return 0;
+
+       switch (attr) {
+       case hwmon_temp_input:
+               return 0444;
+       default:
+               return 0;
+       }
+}
+
+static int ds3232_hwmon_read(struct device *dev,
+                            enum hwmon_sensor_types type,
+                            u32 attr, int channel, long *temp)
+{
+       int err;
+
+       switch (attr) {
+       case hwmon_temp_input:
+               err = ds3232_hwmon_read_temp(dev, temp);
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       return err;
+}
+
+static u32 ds3232_hwmon_chip_config[] = {
+       HWMON_C_REGISTER_TZ,
+       0
+};
+
+static const struct hwmon_channel_info ds3232_hwmon_chip = {
+       .type = hwmon_chip,
+       .config = ds3232_hwmon_chip_config,
+};
+
+static u32 ds3232_hwmon_temp_config[] = {
+       HWMON_T_INPUT,
+       0
+};
+
+static const struct hwmon_channel_info ds3232_hwmon_temp = {
+       .type = hwmon_temp,
+       .config = ds3232_hwmon_temp_config,
+};
+
+static const struct hwmon_channel_info *ds3232_hwmon_info[] = {
+       &ds3232_hwmon_chip,
+       &ds3232_hwmon_temp,
+       NULL
+};
+
+static const struct hwmon_ops ds3232_hwmon_hwmon_ops = {
+       .is_visible = ds3232_hwmon_is_visible,
+       .read = ds3232_hwmon_read,
+};
+
+static const struct hwmon_chip_info ds3232_hwmon_chip_info = {
+       .ops = &ds3232_hwmon_hwmon_ops,
+       .info = ds3232_hwmon_info,
+};
+
+static void ds3232_hwmon_register(struct device *dev, const char *name)
+{
+       struct ds3232 *ds3232 = dev_get_drvdata(dev);
+       struct device *hwmon_dev;
+
+       if (!IS_ENABLED(CONFIG_RTC_DRV_DS3232_HWMON))
+               return;
+
+       hwmon_dev = devm_hwmon_device_register_with_info(dev, name, ds3232,
+                                                       &ds3232_hwmon_chip_info,
+                                                       NULL);
+       if (IS_ERR(hwmon_dev)) {
+               dev_err(dev, "unable to register hwmon device %ld\n",
+                       PTR_ERR(hwmon_dev));
+       }
+}
+
 static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct ds3232 *ds3232 = dev_get_drvdata(dev);
@@ -366,6 +483,8 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
        if (ds3232->irq > 0)
                device_init_wakeup(dev, 1);
 
+       ds3232_hwmon_register(dev, name);
+
        ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops,
                                                THIS_MODULE);
        if (IS_ERR(ds3232->rtc))
similarity index 50%
rename from drivers/rtc/rtc-gemini.c
rename to drivers/rtc/rtc-ftrtc010.c
index 5279390..af8d6be 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Gemini OnChip RTC
+ *  Faraday Technology FTRTC010 driver
  *
  *  Copyright (C) 2009 Janos Laube <janos.dev@gmail.com>
  *
 #include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/clk.h>
 
-#define DRV_NAME        "rtc-gemini"
+#define DRV_NAME        "rtc-ftrtc010"
 
 MODULE_AUTHOR("Hans Ulli Kroll <ulli.kroll@googlemail.com>");
 MODULE_DESCRIPTION("RTC driver for Gemini SoC");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DRV_NAME);
 
-struct gemini_rtc {
+struct ftrtc010_rtc {
        struct rtc_device       *rtc_dev;
        void __iomem            *rtc_base;
        int                     rtc_irq;
+       struct clk              *pclk;
+       struct clk              *extclk;
 };
 
-enum gemini_rtc_offsets {
-       GEMINI_RTC_SECOND       = 0x00,
-       GEMINI_RTC_MINUTE       = 0x04,
-       GEMINI_RTC_HOUR         = 0x08,
-       GEMINI_RTC_DAYS         = 0x0C,
-       GEMINI_RTC_ALARM_SECOND = 0x10,
-       GEMINI_RTC_ALARM_MINUTE = 0x14,
-       GEMINI_RTC_ALARM_HOUR   = 0x18,
-       GEMINI_RTC_RECORD       = 0x1C,
-       GEMINI_RTC_CR           = 0x20
+enum ftrtc010_rtc_offsets {
+       FTRTC010_RTC_SECOND             = 0x00,
+       FTRTC010_RTC_MINUTE             = 0x04,
+       FTRTC010_RTC_HOUR               = 0x08,
+       FTRTC010_RTC_DAYS               = 0x0C,
+       FTRTC010_RTC_ALARM_SECOND       = 0x10,
+       FTRTC010_RTC_ALARM_MINUTE       = 0x14,
+       FTRTC010_RTC_ALARM_HOUR         = 0x18,
+       FTRTC010_RTC_RECORD             = 0x1C,
+       FTRTC010_RTC_CR                 = 0x20,
 };
 
-static irqreturn_t gemini_rtc_interrupt(int irq, void *dev)
+static irqreturn_t ftrtc010_rtc_interrupt(int irq, void *dev)
 {
        return IRQ_HANDLED;
 }
@@ -66,18 +69,18 @@ static irqreturn_t gemini_rtc_interrupt(int irq, void *dev)
  * the same thing, without the rtc-lib.c calls.
  */
 
-static int gemini_rtc_read_time(struct device *dev, struct rtc_time *tm)
+static int ftrtc010_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
-       struct gemini_rtc *rtc = dev_get_drvdata(dev);
+       struct ftrtc010_rtc *rtc = dev_get_drvdata(dev);
 
        unsigned int  days, hour, min, sec;
        unsigned long offset, time;
 
-       sec  = readl(rtc->rtc_base + GEMINI_RTC_SECOND);
-       min  = readl(rtc->rtc_base + GEMINI_RTC_MINUTE);
-       hour = readl(rtc->rtc_base + GEMINI_RTC_HOUR);
-       days = readl(rtc->rtc_base + GEMINI_RTC_DAYS);
-       offset = readl(rtc->rtc_base + GEMINI_RTC_RECORD);
+       sec  = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
+       min  = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
+       hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
+       days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
+       offset = readl(rtc->rtc_base + FTRTC010_RTC_RECORD);
 
        time = offset + days * 86400 + hour * 3600 + min * 60 + sec;
 
@@ -86,9 +89,9 @@ static int gemini_rtc_read_time(struct device *dev, struct rtc_time *tm)
        return 0;
 }
 
-static int gemini_rtc_set_time(struct device *dev, struct rtc_time *tm)
+static int ftrtc010_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
-       struct gemini_rtc *rtc = dev_get_drvdata(dev);
+       struct ftrtc010_rtc *rtc = dev_get_drvdata(dev);
        unsigned int sec, min, hour, day;
        unsigned long offset, time;
 
@@ -97,27 +100,27 @@ static int gemini_rtc_set_time(struct device *dev, struct rtc_time *tm)
 
        rtc_tm_to_time(tm, &time);
 
-       sec = readl(rtc->rtc_base + GEMINI_RTC_SECOND);
-       min = readl(rtc->rtc_base + GEMINI_RTC_MINUTE);
-       hour = readl(rtc->rtc_base + GEMINI_RTC_HOUR);
-       day = readl(rtc->rtc_base + GEMINI_RTC_DAYS);
+       sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
+       min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
+       hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
+       day = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
 
        offset = time - (day * 86400 + hour * 3600 + min * 60 + sec);
 
-       writel(offset, rtc->rtc_base + GEMINI_RTC_RECORD);
-       writel(0x01, rtc->rtc_base + GEMINI_RTC_CR);
+       writel(offset, rtc->rtc_base + FTRTC010_RTC_RECORD);
+       writel(0x01, rtc->rtc_base + FTRTC010_RTC_CR);
 
        return 0;
 }
 
-static const struct rtc_class_ops gemini_rtc_ops = {
-       .read_time     = gemini_rtc_read_time,
-       .set_time      = gemini_rtc_set_time,
+static const struct rtc_class_ops ftrtc010_rtc_ops = {
+       .read_time     = ftrtc010_rtc_read_time,
+       .set_time      = ftrtc010_rtc_set_time,
 };
 
-static int gemini_rtc_probe(struct platform_device *pdev)
+static int ftrtc010_rtc_probe(struct platform_device *pdev)
 {
-       struct gemini_rtc *rtc;
+       struct ftrtc010_rtc *rtc;
        struct device *dev = &pdev->dev;
        struct resource *res;
        int ret;
@@ -127,6 +130,27 @@ static int gemini_rtc_probe(struct platform_device *pdev)
                return -ENOMEM;
        platform_set_drvdata(pdev, rtc);
 
+       rtc->pclk = devm_clk_get(dev, "PCLK");
+       if (IS_ERR(rtc->pclk)) {
+               dev_err(dev, "could not get PCLK\n");
+       } else {
+               ret = clk_prepare_enable(rtc->pclk);
+               if (ret) {
+                       dev_err(dev, "failed to enable PCLK\n");
+                       return ret;
+               }
+       }
+       rtc->extclk = devm_clk_get(dev, "EXTCLK");
+       if (IS_ERR(rtc->extclk)) {
+               dev_err(dev, "could not get EXTCLK\n");
+       } else {
+               ret = clk_prepare_enable(rtc->extclk);
+               if (ret) {
+                       dev_err(dev, "failed to enable EXTCLK\n");
+                       return ret;
+               }
+       }
+
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res)
                return -ENODEV;
@@ -142,38 +166,43 @@ static int gemini_rtc_probe(struct platform_device *pdev)
        if (!rtc->rtc_base)
                return -ENOMEM;
 
-       ret = devm_request_irq(dev, rtc->rtc_irq, gemini_rtc_interrupt,
+       ret = devm_request_irq(dev, rtc->rtc_irq, ftrtc010_rtc_interrupt,
                               IRQF_SHARED, pdev->name, dev);
        if (unlikely(ret))
                return ret;
 
        rtc->rtc_dev = rtc_device_register(pdev->name, dev,
-                                          &gemini_rtc_ops, THIS_MODULE);
+                                          &ftrtc010_rtc_ops, THIS_MODULE);
        return PTR_ERR_OR_ZERO(rtc->rtc_dev);
 }
 
-static int gemini_rtc_remove(struct platform_device *pdev)
+static int ftrtc010_rtc_remove(struct platform_device *pdev)
 {
-       struct gemini_rtc *rtc = platform_get_drvdata(pdev);
+       struct ftrtc010_rtc *rtc = platform_get_drvdata(pdev);
 
+       if (!IS_ERR(rtc->extclk))
+               clk_disable_unprepare(rtc->extclk);
+       if (!IS_ERR(rtc->pclk))
+               clk_disable_unprepare(rtc->pclk);
        rtc_device_unregister(rtc->rtc_dev);
 
        return 0;
 }
 
-static const struct of_device_id gemini_rtc_dt_match[] = {
+static const struct of_device_id ftrtc010_rtc_dt_match[] = {
        { .compatible = "cortina,gemini-rtc" },
+       { .compatible = "faraday,ftrtc010" },
        { }
 };
-MODULE_DEVICE_TABLE(of, gemini_rtc_dt_match);
+MODULE_DEVICE_TABLE(of, ftrtc010_rtc_dt_match);
 
-static struct platform_driver gemini_rtc_driver = {
+static struct platform_driver ftrtc010_rtc_driver = {
        .driver         = {
                .name   = DRV_NAME,
-               .of_match_table = gemini_rtc_dt_match,
+               .of_match_table = ftrtc010_rtc_dt_match,
        },
-       .probe          = gemini_rtc_probe,
-       .remove         = gemini_rtc_remove,
+       .probe          = ftrtc010_rtc_probe,
+       .remove         = ftrtc010_rtc_remove,
 };
 
-module_platform_driver_probe(gemini_rtc_driver, gemini_rtc_probe);
+module_platform_driver_probe(ftrtc010_rtc_driver, ftrtc010_rtc_probe);
index 5ec4653..8940e9e 100644 (file)
@@ -16,6 +16,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/bcd.h>
+#include <linux/clk-provider.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -53,6 +54,8 @@
 #define M41T80_ALARM_REG_SIZE  \
        (M41T80_REG_ALARM_SEC + 1 - M41T80_REG_ALARM_MON)
 
+#define M41T80_SQW_MAX_FREQ    32768
+
 #define M41T80_SEC_ST          BIT(7)  /* ST: Stop Bit */
 #define M41T80_ALMON_AFE       BIT(7)  /* AFE: AF Enable Bit */
 #define M41T80_ALMON_SQWE      BIT(6)  /* SQWE: SQW Enable Bit */
@@ -147,7 +150,11 @@ MODULE_DEVICE_TABLE(of, m41t80_of_match);
 
 struct m41t80_data {
        unsigned long features;
+       struct i2c_client *client;
        struct rtc_device *rtc;
+#ifdef CONFIG_COMMON_CLK
+       struct clk_hw sqw;
+#endif
 };
 
 static irqreturn_t m41t80_handle_irq(int irq, void *dev_id)
@@ -227,6 +234,7 @@ static int m41t80_get_datetime(struct i2c_client *client,
 /* Sets the given date and time to the real time clock. */
 static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
 {
+       struct m41t80_data *clientdata = i2c_get_clientdata(client);
        unsigned char buf[8];
        int err, flags;
 
@@ -242,6 +250,17 @@ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
        buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100);
        buf[M41T80_REG_WDAY] = tm->tm_wday;
 
+       /* If the square wave output is controlled in the weekday register */
+       if (clientdata->features & M41T80_FEATURE_SQ_ALT) {
+               int val;
+
+               val = i2c_smbus_read_byte_data(client, M41T80_REG_WDAY);
+               if (val < 0)
+                       return val;
+
+               buf[M41T80_REG_WDAY] |= (val & 0xf0);
+       }
+
        err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_SSEC,
                                             sizeof(buf), buf);
        if (err < 0) {
@@ -332,6 +351,9 @@ static int m41t80_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
                return err;
        }
 
+       /* Keep SQWE bit value */
+       alarmvals[0] |= (ret & M41T80_ALMON_SQWE);
+
        ret = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
        if (ret < 0)
                return ret;
@@ -431,103 +453,175 @@ static ssize_t flags_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(flags);
 
-static ssize_t sqwfreq_show(struct device *dev,
-                           struct device_attribute *attr, char *buf)
+static struct attribute *attrs[] = {
+       &dev_attr_flags.attr,
+       NULL,
+};
+
+static struct attribute_group attr_group = {
+       .attrs = attrs,
+};
+
+#ifdef CONFIG_COMMON_CLK
+#define sqw_to_m41t80_data(_hw) container_of(_hw, struct m41t80_data, sqw)
+
+static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw,
+                                           unsigned long parent_rate)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct m41t80_data *clientdata = i2c_get_clientdata(client);
-       int val, reg_sqw;
+       struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
+       struct i2c_client *client = m41t80->client;
+       int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ?
+               M41T80_REG_WDAY : M41T80_REG_SQW;
+       int ret = i2c_smbus_read_byte_data(client, reg_sqw);
+       unsigned long val = M41T80_SQW_MAX_FREQ;
 
-       if (!(clientdata->features & M41T80_FEATURE_SQ))
-               return -EINVAL;
+       if (ret < 0)
+               return 0;
 
-       reg_sqw = M41T80_REG_SQW;
-       if (clientdata->features & M41T80_FEATURE_SQ_ALT)
-               reg_sqw = M41T80_REG_WDAY;
-       val = i2c_smbus_read_byte_data(client, reg_sqw);
-       if (val < 0)
-               return val;
-       val = (val >> 4) & 0xf;
-       switch (val) {
-       case 0:
-               break;
-       case 1:
-               val = 32768;
-               break;
-       default:
-               val = 32768 >> val;
-       }
-       return sprintf(buf, "%d\n", val);
+       ret >>= 4;
+       if (ret == 0)
+               val = 0;
+       else if (ret > 1)
+               val = val / (1 << ret);
+
+       return val;
 }
 
-static ssize_t sqwfreq_store(struct device *dev,
-                            struct device_attribute *attr,
-                            const char *buf, size_t count)
+static long m41t80_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
+                                 unsigned long *prate)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct m41t80_data *clientdata = i2c_get_clientdata(client);
-       int almon, sqw, reg_sqw, rc;
-       unsigned long val;
+       int i, freq = M41T80_SQW_MAX_FREQ;
 
-       rc = kstrtoul(buf, 0, &val);
-       if (rc < 0)
-               return rc;
+       if (freq <= rate)
+               return freq;
 
-       if (!(clientdata->features & M41T80_FEATURE_SQ))
-               return -EINVAL;
+       for (i = 2; i <= ilog2(M41T80_SQW_MAX_FREQ); i++) {
+               freq /= 1 << i;
+               if (freq <= rate)
+                       return freq;
+       }
 
-       if (val) {
-               if (!is_power_of_2(val))
+       return 0;
+}
+
+static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
+                              unsigned long parent_rate)
+{
+       struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
+       struct i2c_client *client = m41t80->client;
+       int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ?
+               M41T80_REG_WDAY : M41T80_REG_SQW;
+       int reg, ret, val = 0;
+
+       if (rate) {
+               if (!is_power_of_2(rate))
                        return -EINVAL;
-               val = ilog2(val);
-               if (val == 15)
+               val = ilog2(rate);
+               if (val == ilog2(M41T80_SQW_MAX_FREQ))
                        val = 1;
-               else if (val < 14)
-                       val = 15 - val;
+               else if (val < (ilog2(M41T80_SQW_MAX_FREQ) - 1))
+                       val = ilog2(M41T80_SQW_MAX_FREQ) - val;
                else
                        return -EINVAL;
        }
-       /* disable SQW, set SQW frequency & re-enable */
-       almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
-       if (almon < 0)
-               return almon;
-       reg_sqw = M41T80_REG_SQW;
-       if (clientdata->features & M41T80_FEATURE_SQ_ALT)
-               reg_sqw = M41T80_REG_WDAY;
-       sqw = i2c_smbus_read_byte_data(client, reg_sqw);
-       if (sqw < 0)
-               return sqw;
-       sqw = (sqw & 0x0f) | (val << 4);
-
-       rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
-                                      almon & ~M41T80_ALMON_SQWE);
-       if (rc < 0)
-               return rc;
 
-       if (val) {
-               rc = i2c_smbus_write_byte_data(client, reg_sqw, sqw);
-               if (rc < 0)
-                       return rc;
+       reg = i2c_smbus_read_byte_data(client, reg_sqw);
+       if (reg < 0)
+               return reg;
 
-               rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
-                                              almon | M41T80_ALMON_SQWE);
-               if (rc < 0)
-                       return rc;
-       }
-       return count;
+       reg = (reg & 0x0f) | (val << 4);
+
+       ret = i2c_smbus_write_byte_data(client, reg_sqw, reg);
+       if (ret < 0)
+               return ret;
+
+       return -EINVAL;
 }
-static DEVICE_ATTR_RW(sqwfreq);
 
-static struct attribute *attrs[] = {
-       &dev_attr_flags.attr,
-       &dev_attr_sqwfreq.attr,
-       NULL,
-};
+static int m41t80_sqw_control(struct clk_hw *hw, bool enable)
+{
+       struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
+       struct i2c_client *client = m41t80->client;
+       int ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
 
-static struct attribute_group attr_group = {
-       .attrs = attrs,
+       if (ret < 0)
+               return ret;
+
+       if (enable)
+               ret |= M41T80_ALMON_SQWE;
+       else
+               ret &= ~M41T80_ALMON_SQWE;
+
+       return i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret);
+}
+
+static int m41t80_sqw_prepare(struct clk_hw *hw)
+{
+       return m41t80_sqw_control(hw, 1);
+}
+
+static void m41t80_sqw_unprepare(struct clk_hw *hw)
+{
+       m41t80_sqw_control(hw, 0);
+}
+
+static int m41t80_sqw_is_prepared(struct clk_hw *hw)
+{
+       struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
+       struct i2c_client *client = m41t80->client;
+       int ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
+
+       if (ret < 0)
+               return ret;
+
+       return !!(ret & M41T80_ALMON_SQWE);
+}
+
+static const struct clk_ops m41t80_sqw_ops = {
+       .prepare = m41t80_sqw_prepare,
+       .unprepare = m41t80_sqw_unprepare,
+       .is_prepared = m41t80_sqw_is_prepared,
+       .recalc_rate = m41t80_sqw_recalc_rate,
+       .round_rate = m41t80_sqw_round_rate,
+       .set_rate = m41t80_sqw_set_rate,
 };
 
+static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80)
+{
+       struct i2c_client *client = m41t80->client;
+       struct device_node *node = client->dev.of_node;
+       struct clk *clk;
+       struct clk_init_data init;
+       int ret;
+
+       /* First disable the clock */
+       ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
+       if (ret < 0)
+               return ERR_PTR(ret);
+       ret = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
+                                       ret & ~(M41T80_ALMON_SQWE));
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       init.name = "m41t80-sqw";
+       init.ops = &m41t80_sqw_ops;
+       init.flags = 0;
+       init.parent_names = NULL;
+       init.num_parents = 0;
+       m41t80->sqw.init = &init;
+
+       /* optional override of the clockname */
+       of_property_read_string(node, "clock-output-names", &init.name);
+
+       /* register the clock */
+       clk = clk_register(&client->dev, &m41t80->sqw);
+       if (!IS_ERR(clk))
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+       return clk;
+}
+#endif
+
 #ifdef CONFIG_RTC_DRV_M41T80_WDT
 /*
  *****************************************************************************
@@ -845,6 +939,7 @@ static int m41t80_probe(struct i2c_client *client,
        if (!m41t80_data)
                return -ENOMEM;
 
+       m41t80_data->client = client;
        if (client->dev.of_node)
                m41t80_data->features = (unsigned long)
                        of_device_get_match_data(&client->dev);
@@ -937,6 +1032,10 @@ static int m41t80_probe(struct i2c_client *client,
                }
        }
 #endif
+#ifdef CONFIG_COMMON_CLK
+       if (m41t80_data->features & M41T80_FEATURE_SQ)
+               m41t80_sqw_register_clk(m41t80_data);
+#endif
        return 0;
 }
 
index 7731912..401f46d 100644 (file)
 
 #define MAX_PIE_NUM     9
 #define MAX_PIE_FREQ    512
-static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = {
-       { 2,            RTC_2HZ_BIT },
-       { 4,            RTC_SAM0_BIT },
-       { 8,            RTC_SAM1_BIT },
-       { 16,           RTC_SAM2_BIT },
-       { 32,           RTC_SAM3_BIT },
-       { 64,           RTC_SAM4_BIT },
-       { 128,          RTC_SAM5_BIT },
-       { 256,          RTC_SAM6_BIT },
-       { MAX_PIE_FREQ, RTC_SAM7_BIT },
-};
 
 #define MXC_RTC_TIME   0
 #define MXC_RTC_ALARM  1
index b1b6b30..4ed8111 100644 (file)
@@ -93,7 +93,7 @@ static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc)
        __raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER);
 
        while (!(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB)
-                                                               && timeout--)
+                                                               && --timeout)
                mdelay(1);
 
        if (!timeout)
index ea20f62..e2a946c 100644 (file)
@@ -142,6 +142,16 @@ static int opal_get_tpo_time(struct device *dev, struct rtc_wkalrm *alarm)
 
        y_m_d = be32_to_cpu(__y_m_d);
        h_m_s_ms = ((u64)be32_to_cpu(__h_m) << 32);
+
+       /* check if no alarm is set */
+       if (y_m_d == 0 && h_m_s_ms == 0) {
+               pr_debug("No alarm is set\n");
+               rc = -ENOENT;
+               goto exit;
+       } else {
+               pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms);
+       }
+
        opal_to_tm(y_m_d, h_m_s_ms, &alarm->time);
 
 exit:
@@ -157,7 +167,14 @@ static int opal_set_tpo_time(struct device *dev, struct rtc_wkalrm *alarm)
        u32 y_m_d = 0;
        int token, rc;
 
-       tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms);
+       /* if alarm is enabled */
+       if (alarm->enabled) {
+               tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms);
+               pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms);
+
+       } else {
+               pr_debug("Alarm getting disabled\n");
+       }
 
        token = opal_async_get_token_interruptible();
        if (token < 0) {
@@ -190,6 +207,18 @@ exit:
        return rc;
 }
 
+int opal_tpo_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct rtc_wkalrm alarm = { .enabled = 0 };
+
+       /*
+        * TPO is automatically enabled when opal_set_tpo_time() is called with
+        * non-zero rtc-time. We only handle disable case which needs to be
+        * explicitly told to opal.
+        */
+       return enabled ? 0 : opal_set_tpo_time(dev, &alarm);
+}
+
 static struct rtc_class_ops opal_rtc_ops = {
        .read_time      = opal_get_rtc_time,
        .set_time       = opal_set_rtc_time,
@@ -205,6 +234,7 @@ static int opal_rtc_probe(struct platform_device *pdev)
                device_set_wakeup_capable(&pdev->dev, true);
                opal_rtc_ops.read_alarm = opal_get_tpo_time;
                opal_rtc_ops.set_alarm = opal_set_tpo_time;
+               opal_rtc_ops.alarm_irq_enable = opal_tpo_alarm_irq_enable;
        }
 
        rtc = devm_rtc_device_register(&pdev->dev, DRVNAME, &opal_rtc_ops,
index 1227cea..cea6ea4 100644 (file)
@@ -606,7 +606,7 @@ static int pcf8563_probe(struct i2c_client *client,
                err = devm_request_threaded_irq(&client->dev, client->irq,
                                NULL, pcf8563_irq,
                                IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING,
-                               pcf8563->rtc->name, client);
+                               pcf8563_driver.driver.name, client);
                if (err) {
                        dev_err(&client->dev, "unable to request IRQ %d\n",
                                                                client->irq);
index 9ad97ab..aae2576 100644 (file)
@@ -68,6 +68,7 @@ struct rv8803_data {
        struct mutex flags_lock;
        u8 ctrl;
        enum rv8803_type type;
+       struct nvmem_config nvmem_cfg;
 };
 
 static int rv8803_read_reg(const struct i2c_client *client, u8 reg)
@@ -460,48 +461,32 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        }
 }
 
-static ssize_t rv8803_nvram_write(struct file *filp, struct kobject *kobj,
-                                 struct bin_attribute *attr,
-                                 char *buf, loff_t off, size_t count)
+static int rv8803_nvram_write(void *priv, unsigned int offset, void *val,
+                             size_t bytes)
 {
-       struct device *dev = kobj_to_dev(kobj);
-       struct i2c_client *client = to_i2c_client(dev);
        int ret;
 
-       ret = rv8803_write_reg(client, RV8803_RAM, buf[0]);
+       ret = rv8803_write_reg(priv, RV8803_RAM, *(u8 *)val);
        if (ret)
                return ret;
 
-       return 1;
+       return 0;
 }
 
-static ssize_t rv8803_nvram_read(struct file *filp, struct kobject *kobj,
-                                struct bin_attribute *attr,
-                                char *buf, loff_t off, size_t count)
+static int rv8803_nvram_read(void *priv, unsigned int offset,
+                            void *val, size_t bytes)
 {
-       struct device *dev = kobj_to_dev(kobj);
-       struct i2c_client *client = to_i2c_client(dev);
        int ret;
 
-       ret = rv8803_read_reg(client, RV8803_RAM);
+       ret = rv8803_read_reg(priv, RV8803_RAM);
        if (ret < 0)
                return ret;
 
-       buf[0] = ret;
+       *(u8 *)val = ret;
 
-       return 1;
+       return 0;
 }
 
-static struct bin_attribute rv8803_nvram_attr = {
-       .attr = {
-               .name = "nvram",
-               .mode = S_IRUGO | S_IWUSR,
-       },
-       .size = 1,
-       .read = rv8803_nvram_read,
-       .write = rv8803_nvram_write,
-};
-
 static struct rtc_class_ops rv8803_rtc_ops = {
        .read_time = rv8803_get_time,
        .set_time = rv8803_set_time,
@@ -577,6 +562,11 @@ static int rv8803_probe(struct i2c_client *client,
        if (flags & RV8803_FLAG_AF)
                dev_warn(&client->dev, "An alarm maybe have been missed.\n");
 
+       rv8803->rtc = devm_rtc_allocate_device(&client->dev);
+       if (IS_ERR(rv8803->rtc)) {
+               return PTR_ERR(rv8803->rtc);
+       }
+
        if (client->irq > 0) {
                err = devm_request_threaded_irq(&client->dev, client->irq,
                                                NULL, rv8803_handle_irq,
@@ -592,12 +582,20 @@ static int rv8803_probe(struct i2c_client *client,
                }
        }
 
-       rv8803->rtc = devm_rtc_device_register(&client->dev, client->name,
-                                              &rv8803_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rv8803->rtc)) {
-               dev_err(&client->dev, "unable to register the class device\n");
-               return PTR_ERR(rv8803->rtc);
-       }
+       rv8803->nvmem_cfg.name = "rv8803_nvram",
+       rv8803->nvmem_cfg.word_size = 1,
+       rv8803->nvmem_cfg.stride = 1,
+       rv8803->nvmem_cfg.size = 1,
+       rv8803->nvmem_cfg.reg_read = rv8803_nvram_read,
+       rv8803->nvmem_cfg.reg_write = rv8803_nvram_write,
+       rv8803->nvmem_cfg.priv = client;
+
+       rv8803->rtc->ops = &rv8803_rtc_ops;
+       rv8803->rtc->nvmem_config = &rv8803->nvmem_cfg;
+       rv8803->rtc->nvram_old_abi = true;
+       err = rtc_register_device(rv8803->rtc);
+       if (err)
+               return err;
 
        err = rv8803_write_reg(rv8803->client, RV8803_EXT, RV8803_EXT_WADA);
        if (err)
@@ -609,22 +607,11 @@ static int rv8803_probe(struct i2c_client *client,
                return err;
        }
 
-       err = device_create_bin_file(&client->dev, &rv8803_nvram_attr);
-       if (err)
-               return err;
-
        rv8803->rtc->max_user_freq = 1;
 
        return 0;
 }
 
-static int rv8803_remove(struct i2c_client *client)
-{
-       device_remove_bin_file(&client->dev, &rv8803_nvram_attr);
-
-       return 0;
-}
-
 static const struct i2c_device_id rv8803_id[] = {
        { "rv8803", rv_8803 },
        { "rx8900", rx_8900 },
@@ -651,7 +638,6 @@ static struct i2c_driver rv8803_driver = {
                .of_match_table = of_match_ptr(rv8803_of_match),
        },
        .probe          = rv8803_probe,
-       .remove         = rv8803_remove,
        .id_table       = rv8803_id,
 };
 module_i2c_driver(rv8803_driver);
index d44fb34..a8992c2 100644 (file)
@@ -41,7 +41,7 @@ struct s3c_rtc {
        struct clk *rtc_src_clk;
        bool clk_disabled;
 
-       struct s3c_rtc_data *data;
+       const struct s3c_rtc_data *data;
 
        int irq_alarm;
        int irq_tick;
@@ -49,7 +49,8 @@ struct s3c_rtc {
        spinlock_t pie_lock;
        spinlock_t alarm_clk_lock;
 
-       int ticnt_save, ticnt_en_save;
+       int ticnt_save;
+       int ticnt_en_save;
        bool wake_en;
 };
 
@@ -67,18 +68,32 @@ struct s3c_rtc_data {
        void (*disable) (struct s3c_rtc *info);
 };
 
-static void s3c_rtc_enable_clk(struct s3c_rtc *info)
+static int s3c_rtc_enable_clk(struct s3c_rtc *info)
 {
        unsigned long irq_flags;
+       int ret = 0;
 
        spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
+
        if (info->clk_disabled) {
-               clk_enable(info->rtc_clk);
-               if (info->data->needs_src_clk)
-                       clk_enable(info->rtc_src_clk);
+               ret = clk_enable(info->rtc_clk);
+               if (ret)
+                       goto out;
+
+               if (info->data->needs_src_clk) {
+                       ret = clk_enable(info->rtc_src_clk);
+                       if (ret) {
+                               clk_disable(info->rtc_clk);
+                               goto out;
+                       }
+               }
                info->clk_disabled = false;
        }
+
+out:
        spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
+
+       return ret;
 }
 
 static void s3c_rtc_disable_clk(struct s3c_rtc *info)
@@ -121,10 +136,13 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
 {
        struct s3c_rtc *info = dev_get_drvdata(dev);
        unsigned int tmp;
+       int ret;
 
        dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
        tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
 
@@ -135,10 +153,13 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
 
        s3c_rtc_disable_clk(info);
 
-       if (enabled)
-               s3c_rtc_enable_clk(info);
-       else
+       if (enabled) {
+               ret = s3c_rtc_enable_clk(info);
+               if (ret)
+                       return ret;
+       } else {
                s3c_rtc_disable_clk(info);
+       }
 
        return 0;
 }
@@ -146,10 +167,14 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
 /* Set RTC frequency */
 static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
 {
+       int ret;
+
        if (!is_power_of_2(freq))
                return -EINVAL;
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
        spin_lock_irq(&info->pie_lock);
 
        if (info->data->set_freq)
@@ -166,10 +191,13 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
 {
        struct s3c_rtc *info = dev_get_drvdata(dev);
        unsigned int have_retried = 0;
+       int ret;
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
- retry_get_time:
+retry_get_time:
        rtc_tm->tm_min  = readb(info->base + S3C2410_RTCMIN);
        rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
        rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
@@ -199,8 +227,8 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
        rtc_tm->tm_year += 100;
 
        dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n",
-                1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
-                rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
+               1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
+               rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
 
        rtc_tm->tm_mon -= 1;
 
@@ -211,10 +239,11 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
 {
        struct s3c_rtc *info = dev_get_drvdata(dev);
        int year = tm->tm_year - 100;
+       int ret;
 
        dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n",
-                1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
-                tm->tm_hour, tm->tm_min, tm->tm_sec);
+               1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
 
        /* we get around y2k by simply not supporting it */
 
@@ -223,7 +252,9 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
                return -EINVAL;
        }
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
        writeb(bin2bcd(tm->tm_sec),  info->base + S3C2410_RTCSEC);
        writeb(bin2bcd(tm->tm_min),  info->base + S3C2410_RTCMIN);
@@ -242,8 +273,11 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
        struct s3c_rtc *info = dev_get_drvdata(dev);
        struct rtc_time *alm_tm = &alrm->time;
        unsigned int alm_en;
+       int ret;
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
        alm_tm->tm_sec  = readb(info->base + S3C2410_ALMSEC);
        alm_tm->tm_min  = readb(info->base + S3C2410_ALMMIN);
@@ -259,9 +293,9 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
        alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
 
        dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n",
-                alm_en,
-                1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
-                alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
+               alm_en,
+               1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
+               alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
 
        /* decode the alarm enable field */
        if (alm_en & S3C2410_RTCALM_SECEN)
@@ -292,14 +326,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        struct s3c_rtc *info = dev_get_drvdata(dev);
        struct rtc_time *tm = &alrm->time;
        unsigned int alrm_en;
+       int ret;
        int year = tm->tm_year - 100;
 
        dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
-                alrm->enabled,
-                1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
-                tm->tm_hour, tm->tm_min, tm->tm_sec);
+               alrm->enabled,
+               1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
        alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
        writeb(0x00, info->base + S3C2410_RTCALM);
@@ -348,8 +385,11 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
 {
        struct s3c_rtc *info = dev_get_drvdata(dev);
+       int ret;
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
        if (info->data->enable_tick)
                info->data->enable_tick(info, seq);
@@ -378,8 +418,7 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info)
                dev_info(info->dev, "rtc disabled, re-enabling\n");
 
                tmp = readw(info->base + S3C2410_RTCCON);
-               writew(tmp | S3C2410_RTCCON_RTCEN,
-                       info->base + S3C2410_RTCCON);
+               writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON);
        }
 
        if (con & S3C2410_RTCCON_CNTSEL) {
@@ -387,7 +426,7 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info)
 
                tmp = readw(info->base + S3C2410_RTCCON);
                writew(tmp & ~S3C2410_RTCCON_CNTSEL,
-                       info->base + S3C2410_RTCCON);
+                      info->base + S3C2410_RTCCON);
        }
 
        if (con & S3C2410_RTCCON_CLKRST) {
@@ -395,7 +434,7 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info)
 
                tmp = readw(info->base + S3C2410_RTCCON);
                writew(tmp & ~S3C2410_RTCCON_CLKRST,
-                       info->base + S3C2410_RTCCON);
+                      info->base + S3C2410_RTCCON);
        }
 }
 
@@ -437,12 +476,12 @@ static int s3c_rtc_remove(struct platform_device *pdev)
 
 static const struct of_device_id s3c_rtc_dt_match[];
 
-static struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
+static const struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
 {
        const struct of_device_id *match;
 
        match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
-       return (struct s3c_rtc_data *)match->data;
+       return match->data;
 }
 
 static int s3c_rtc_probe(struct platform_device *pdev)
@@ -481,7 +520,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
        }
 
        dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n",
-                info->irq_tick, info->irq_alarm);
+               info->irq_tick, info->irq_alarm);
 
        /* get the memory region */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -498,7 +537,9 @@ static int s3c_rtc_probe(struct platform_device *pdev)
                        dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n");
                return ret;
        }
-       clk_prepare_enable(info->rtc_clk);
+       ret = clk_prepare_enable(info->rtc_clk);
+       if (ret)
+               return ret;
 
        if (info->data->needs_src_clk) {
                info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
@@ -510,10 +551,11 @@ static int s3c_rtc_probe(struct platform_device *pdev)
                        else
                                dev_dbg(&pdev->dev,
                                        "probe deferred due to missing rtc src clk\n");
-                       clk_disable_unprepare(info->rtc_clk);
-                       return ret;
+                       goto err_src_clk;
                }
-               clk_prepare_enable(info->rtc_src_clk);
+               ret = clk_prepare_enable(info->rtc_src_clk);
+               if (ret)
+                       goto err_src_clk;
        }
 
        /* check to see if everything is setup correctly */
@@ -521,7 +563,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
                info->data->enable(info);
 
        dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
-                readw(info->base + S3C2410_RTCCON));
+               readw(info->base + S3C2410_RTCCON));
 
        device_init_wakeup(&pdev->dev, 1);
 
@@ -541,7 +583,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 
        /* register RTC and exit */
        info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
-                                 THIS_MODULE);
+                                            THIS_MODULE);
        if (IS_ERR(info->rtc)) {
                dev_err(&pdev->dev, "cannot attach rtc\n");
                ret = PTR_ERR(info->rtc);
@@ -549,14 +591,14 @@ static int s3c_rtc_probe(struct platform_device *pdev)
        }
 
        ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
-                         0,  "s3c2410-rtc alarm", info);
+                              0, "s3c2410-rtc alarm", info);
        if (ret) {
                dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret);
                goto err_nortc;
        }
 
        ret = devm_request_irq(&pdev->dev, info->irq_tick, s3c_rtc_tickirq,
-                         0,  "s3c2410-rtc tick", info);
+                              0, "s3c2410-rtc tick", info);
        if (ret) {
                dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_tick, ret);
                goto err_nortc;
@@ -569,12 +611,13 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 
        return 0;
 
- err_nortc:
+err_nortc:
        if (info->data->disable)
                info->data->disable(info);
 
        if (info->data->needs_src_clk)
                clk_disable_unprepare(info->rtc_src_clk);
+err_src_clk:
        clk_disable_unprepare(info->rtc_clk);
 
        return ret;
@@ -585,8 +628,11 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 static int s3c_rtc_suspend(struct device *dev)
 {
        struct s3c_rtc *info = dev_get_drvdata(dev);
+       int ret;
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
        /* save TICNT for anyone using periodic interrupts */
        if (info->data->save_tick_cnt)
@@ -747,8 +793,7 @@ static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info)
        writel(info->ticnt_save, info->base + S3C2410_TICNT);
        if (info->ticnt_en_save) {
                con = readw(info->base + S3C2410_RTCCON);
-               writew(con | info->ticnt_en_save,
-                               info->base + S3C2410_RTCCON);
+               writew(con | info->ticnt_en_save, info->base + S3C2410_RTCCON);
        }
 }
 
@@ -802,19 +847,19 @@ static struct s3c_rtc_data const s3c6410_rtc_data = {
 static const struct of_device_id s3c_rtc_dt_match[] = {
        {
                .compatible = "samsung,s3c2410-rtc",
-               .data = (void *)&s3c2410_rtc_data,
+               .data = &s3c2410_rtc_data,
        }, {
                .compatible = "samsung,s3c2416-rtc",
-               .data = (void *)&s3c2416_rtc_data,
+               .data = &s3c2416_rtc_data,
        }, {
                .compatible = "samsung,s3c2443-rtc",
-               .data = (void *)&s3c2443_rtc_data,
+               .data = &s3c2443_rtc_data,
        }, {
                .compatible = "samsung,s3c6410-rtc",
-               .data = (void *)&s3c6410_rtc_data,
+               .data = &s3c6410_rtc_data,
        }, {
                .compatible = "samsung,exynos3250-rtc",
-               .data = (void *)&s3c6410_rtc_data,
+               .data = &s3c6410_rtc_data,
        },
        { /* sentinel */ },
 };
index 74c0a33..82b0af1 100644 (file)
@@ -99,7 +99,7 @@ static int st_rtc_read_time(struct device *dev, struct rtc_time *tm)
 
        lpt = ((unsigned long long)lpt_msb << 32) | lpt_lsb;
        do_div(lpt, rtc->clkrate);
-       rtc_time_to_tm(lpt, tm);
+       rtc_time64_to_tm(lpt, tm);
 
        return 0;
 }
@@ -107,13 +107,10 @@ static int st_rtc_read_time(struct device *dev, struct rtc_time *tm)
 static int st_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        struct st_rtc *rtc = dev_get_drvdata(dev);
-       unsigned long long lpt;
-       unsigned long secs, flags;
-       int ret;
+       unsigned long long lpt, secs;
+       unsigned long flags;
 
-       ret = rtc_tm_to_time(tm, &secs);
-       if (ret)
-               return ret;
+       secs = rtc_tm_to_time64(tm);
 
        lpt = (unsigned long long)secs * rtc->clkrate;
 
@@ -161,13 +158,13 @@ static int st_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
        struct st_rtc *rtc = dev_get_drvdata(dev);
        struct rtc_time now;
-       unsigned long now_secs;
-       unsigned long alarm_secs;
+       unsigned long long now_secs;
+       unsigned long long alarm_secs;
        unsigned long long lpa;
 
        st_rtc_read_time(dev, &now);
-       rtc_tm_to_time(&now, &now_secs);
-       rtc_tm_to_time(&t->time, &alarm_secs);
+       now_secs = rtc_tm_to_time64(&now);
+       alarm_secs = rtc_tm_to_time64(&t->time);
 
        /* Invalid alarm time */
        if (now_secs > alarm_secs)
index bd57eb1..3a5c3d7 100644 (file)
 /* STM32_PWR_CR bit field */
 #define PWR_CR_DBP                     BIT(8)
 
+struct stm32_rtc_data {
+       bool has_pclk;
+};
+
 struct stm32_rtc {
        struct rtc_device *rtc_dev;
        void __iomem *base;
        struct regmap *dbp;
-       struct clk *ck_rtc;
+       struct stm32_rtc_data *data;
+       struct clk *pclk;
+       struct clk *rtc_ck;
        int irq_alarm;
 };
 
@@ -122,9 +128,9 @@ static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
                writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
 
                /*
-                * It takes around 2 ck_rtc clock cycles to enter in
+                * It takes around 2 rtc_ck clock cycles to enter in
                 * initialization phase mode (and have INITF flag set). As
-                * slowest ck_rtc frequency may be 32kHz and highest should be
+                * slowest rtc_ck frequency may be 32kHz and highest should be
                 * 1MHz, we poll every 10 us with a timeout of 100ms.
                 */
                return readl_relaxed_poll_timeout_atomic(
@@ -153,7 +159,7 @@ static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
 
        /*
         * Wait for RSF to be set to ensure the calendar registers are
-        * synchronised, it takes around 2 ck_rtc clock cycles
+        * synchronised, it takes around 2 rtc_ck clock cycles
         */
        return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
                                                 isr,
@@ -456,7 +462,7 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 
        /*
         * Poll Alarm write flag to be sure that Alarm update is allowed: it
-        * takes around 2 ck_rtc clock cycles
+        * takes around 2 rtc_ck clock cycles
         */
        ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
                                                isr,
@@ -490,8 +496,17 @@ static const struct rtc_class_ops stm32_rtc_ops = {
        .alarm_irq_enable = stm32_rtc_alarm_irq_enable,
 };
 
+static const struct stm32_rtc_data stm32_rtc_data = {
+       .has_pclk = false,
+};
+
+static const struct stm32_rtc_data stm32h7_rtc_data = {
+       .has_pclk = true,
+};
+
 static const struct of_device_id stm32_rtc_of_match[] = {
-       { .compatible = "st,stm32-rtc" },
+       { .compatible = "st,stm32-rtc", .data = &stm32_rtc_data },
+       { .compatible = "st,stm32h7-rtc", .data = &stm32h7_rtc_data },
        {}
 };
 MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
@@ -503,7 +518,7 @@ static int stm32_rtc_init(struct platform_device *pdev,
        unsigned int rate;
        int ret = 0;
 
-       rate = clk_get_rate(rtc->ck_rtc);
+       rate = clk_get_rate(rtc->rtc_ck);
 
        /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
        pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
@@ -524,7 +539,7 @@ static int stm32_rtc_init(struct platform_device *pdev,
                pred_a = pred_a_max;
                pred_s = (rate / (pred_a + 1)) - 1;
 
-               dev_warn(&pdev->dev, "ck_rtc is %s\n",
+               dev_warn(&pdev->dev, "rtc_ck is %s\n",
                         (rate < ((pred_a + 1) * (pred_s + 1))) ?
                         "fast" : "slow");
        }
@@ -561,6 +576,7 @@ static int stm32_rtc_probe(struct platform_device *pdev)
 {
        struct stm32_rtc *rtc;
        struct resource *res;
+       const struct of_device_id *match;
        int ret;
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
@@ -579,15 +595,34 @@ static int stm32_rtc_probe(struct platform_device *pdev)
                return PTR_ERR(rtc->dbp);
        }
 
-       rtc->ck_rtc = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(rtc->ck_rtc)) {
-               dev_err(&pdev->dev, "no ck_rtc clock");
-               return PTR_ERR(rtc->ck_rtc);
+       match = of_match_device(stm32_rtc_of_match, &pdev->dev);
+       rtc->data = (struct stm32_rtc_data *)match->data;
+
+       if (!rtc->data->has_pclk) {
+               rtc->pclk = NULL;
+               rtc->rtc_ck = devm_clk_get(&pdev->dev, NULL);
+       } else {
+               rtc->pclk = devm_clk_get(&pdev->dev, "pclk");
+               if (IS_ERR(rtc->pclk)) {
+                       dev_err(&pdev->dev, "no pclk clock");
+                       return PTR_ERR(rtc->pclk);
+               }
+               rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck");
+       }
+       if (IS_ERR(rtc->rtc_ck)) {
+               dev_err(&pdev->dev, "no rtc_ck clock");
+               return PTR_ERR(rtc->rtc_ck);
+       }
+
+       if (rtc->data->has_pclk) {
+               ret = clk_prepare_enable(rtc->pclk);
+               if (ret)
+                       return ret;
        }
 
-       ret = clk_prepare_enable(rtc->ck_rtc);
+       ret = clk_prepare_enable(rtc->rtc_ck);
        if (ret)
-               return ret;
+               goto err;
 
        regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
 
@@ -595,7 +630,7 @@ static int stm32_rtc_probe(struct platform_device *pdev)
         * After a system reset, RTC_ISR.INITS flag can be read to check if
         * the calendar has been initalized or not. INITS flag is reset by a
         * power-on reset (no vbat, no power-supply). It is not reset if
-        * ck_rtc parent clock has changed (so RTC prescalers need to be
+        * rtc_ck parent clock has changed (so RTC prescalers need to be
         * changed). That's why we cannot rely on this flag to know if RTC
         * init has to be done.
         */
@@ -646,7 +681,9 @@ static int stm32_rtc_probe(struct platform_device *pdev)
 
        return 0;
 err:
-       clk_disable_unprepare(rtc->ck_rtc);
+       if (rtc->data->has_pclk)
+               clk_disable_unprepare(rtc->pclk);
+       clk_disable_unprepare(rtc->rtc_ck);
 
        regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0);
 
@@ -667,7 +704,9 @@ static int stm32_rtc_remove(struct platform_device *pdev)
        writel_relaxed(cr, rtc->base + STM32_RTC_CR);
        stm32_rtc_wpr_lock(rtc);
 
-       clk_disable_unprepare(rtc->ck_rtc);
+       clk_disable_unprepare(rtc->rtc_ck);
+       if (rtc->data->has_pclk)
+               clk_disable_unprepare(rtc->pclk);
 
        /* Enable backup domain write protection */
        regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0);
@@ -682,6 +721,9 @@ static int stm32_rtc_suspend(struct device *dev)
 {
        struct stm32_rtc *rtc = dev_get_drvdata(dev);
 
+       if (rtc->data->has_pclk)
+               clk_disable_unprepare(rtc->pclk);
+
        if (device_may_wakeup(dev))
                return enable_irq_wake(rtc->irq_alarm);
 
@@ -693,6 +735,12 @@ static int stm32_rtc_resume(struct device *dev)
        struct stm32_rtc *rtc = dev_get_drvdata(dev);
        int ret = 0;
 
+       if (rtc->data->has_pclk) {
+               ret = clk_prepare_enable(rtc->pclk);
+               if (ret)
+                       return ret;
+       }
+
        ret = stm32_rtc_wait_sync(rtc);
        if (ret < 0)
                return ret;
index 1218d5d..e364550 100644 (file)
@@ -27,7 +27,8 @@
 static ssize_t
 name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
+       return sprintf(buf, "%s %s\n", dev_driver_string(dev->parent),
+                      dev_name(dev->parent));
 }
 static DEVICE_ATTR_RO(name);
 
index 65f5a79..98749fa 100644 (file)
@@ -98,7 +98,7 @@ vmcp_write(struct file *file, const char __user *buff, size_t count,
        }
        if (!session->response)
                session->response = (char *)__get_free_pages(GFP_KERNEL
-                                               | __GFP_REPEAT | GFP_DMA,
+                                               | __GFP_RETRY_MAYFAIL | GFP_DMA,
                                                get_order(session->bufsize));
        if (!session->response) {
                mutex_unlock(&session->mutex);
index 7e0d4f7..432fc40 100644 (file)
@@ -559,6 +559,7 @@ static void chp_process_crw(struct crw *crw0, struct crw *crw1,
        chpid.id = crw0->rsid;
        switch (crw0->erc) {
        case CRW_ERC_IPARM: /* Path has come. */
+       case CRW_ERC_INIT:
                if (!chp_is_registered(chpid))
                        chp_new(chpid);
                chsc_chp_online(chpid);
index 1563b14..2ade613 100644 (file)
@@ -1115,7 +1115,7 @@ static const struct net_device_ops ctcm_mpc_netdev_ops = {
        .ndo_start_xmit         = ctcmpc_tx,
 };
 
-void static ctcm_dev_setup(struct net_device *dev)
+static void ctcm_dev_setup(struct net_device *dev)
 {
        dev->type = ARPHRD_SLIP;
        dev->tx_queue_len = 100;
index 3062cde..8975cd3 100644 (file)
@@ -2408,7 +2408,7 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        return rc;
 }
 
-int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
+inline int qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
 {
        int cast_type = RTN_UNSPEC;
        struct neighbour *n = NULL;
index 077f62e..6a4367c 100644 (file)
@@ -3401,9 +3401,10 @@ static int cxlflash_afu_debug(struct cxlflash_cfg *cfg,
                if (is_write) {
                        req_flags |= SISL_REQ_FLAGS_HOST_WRITE;
 
-                       rc = copy_from_user(kbuf, ubuf, ulen);
-                       if (unlikely(rc))
+                       if (copy_from_user(kbuf, ubuf, ulen)) {
+                               rc = -EFAULT;
                                goto out;
+                       }
                }
        }
 
@@ -3431,8 +3432,10 @@ static int cxlflash_afu_debug(struct cxlflash_cfg *cfg,
                goto out;
        }
 
-       if (ulen && !is_write)
-               rc = copy_to_user(ubuf, kbuf, ulen);
+       if (ulen && !is_write) {
+               if (copy_to_user(ubuf, kbuf, ulen))
+                       rc = -EFAULT;
+       }
 out:
        kfree(buf);
        dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
index 551d103..2bfea70 100644 (file)
@@ -1693,7 +1693,7 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
 
 static int parse_trans_tx_err_code_v2_hw(u32 err_msk)
 {
-       const u8 trans_tx_err_code_prio[] = {
+       static const u8 trans_tx_err_code_prio[] = {
                TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS,
                TRANS_TX_ERR_PHY_NOT_ENABLE,
                TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION,
@@ -1738,7 +1738,7 @@ static int parse_trans_tx_err_code_v2_hw(u32 err_msk)
 
 static int parse_trans_rx_err_code_v2_hw(u32 err_msk)
 {
-       const u8 trans_rx_err_code_prio[] = {
+       static const u8 trans_rx_err_code_prio[] = {
                TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR,
                TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR,
                TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM,
@@ -1784,7 +1784,7 @@ static int parse_trans_rx_err_code_v2_hw(u32 err_msk)
 
 static int parse_dma_tx_err_code_v2_hw(u32 err_msk)
 {
-       const u8 dma_tx_err_code_prio[] = {
+       static const u8 dma_tx_err_code_prio[] = {
                DMA_TX_UNEXP_XFER_ERR,
                DMA_TX_UNEXP_RETRANS_ERR,
                DMA_TX_XFER_LEN_OVERFLOW,
@@ -1810,7 +1810,7 @@ static int parse_dma_tx_err_code_v2_hw(u32 err_msk)
 
 static int parse_sipc_rx_err_code_v2_hw(u32 err_msk)
 {
-       const u8 sipc_rx_err_code_prio[] = {
+       static const u8 sipc_rx_err_code_prio[] = {
                SIPC_RX_FIS_STATUS_ERR_BIT_VLD,
                SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR,
                SIPC_RX_FIS_STATUS_BSY_BIT_ERR,
@@ -1836,7 +1836,7 @@ static int parse_sipc_rx_err_code_v2_hw(u32 err_msk)
 
 static int parse_dma_rx_err_code_v2_hw(u32 err_msk)
 {
-       const u8 dma_rx_err_code_prio[] = {
+       static const u8 dma_rx_err_code_prio[] = {
                DMA_RX_UNKNOWN_FRM_ERR,
                DMA_RX_DATA_LEN_OVERFLOW,
                DMA_RX_DATA_LEN_UNDERFLOW,
index 8914eab..4f7cdb2 100644 (file)
@@ -938,7 +938,7 @@ static struct scsi_host_template hpsa_driver_template = {
 #endif
        .sdev_attrs = hpsa_sdev_attrs,
        .shost_attrs = hpsa_shost_attrs,
-       .max_sectors = 8192,
+       .max_sectors = 1024,
        .no_write_same = 1,
 };
 
index 659ab48..1f75d03 100644 (file)
@@ -155,6 +155,9 @@ static long ibmvscsis_unregister_command_q(struct scsi_info *vscsi)
                qrc = h_free_crq(vscsi->dds.unit_id);
                switch (qrc) {
                case H_SUCCESS:
+                       spin_lock_bh(&vscsi->intr_lock);
+                       vscsi->flags &= ~PREP_FOR_SUSPEND_FLAGS;
+                       spin_unlock_bh(&vscsi->intr_lock);
                        break;
 
                case H_HARDWARE:
@@ -422,6 +425,9 @@ static void ibmvscsis_disconnect(struct work_struct *work)
        new_state = vscsi->new_state;
        vscsi->new_state = 0;
 
+       vscsi->flags |= DISCONNECT_SCHEDULED;
+       vscsi->flags &= ~SCHEDULE_DISCONNECT;
+
        pr_debug("disconnect: flags 0x%x, state 0x%hx\n", vscsi->flags,
                 vscsi->state);
 
@@ -802,6 +808,13 @@ static long ibmvscsis_establish_new_q(struct scsi_info *vscsi)
        long rc = ADAPT_SUCCESS;
        uint format;
 
+       rc = h_vioctl(vscsi->dds.unit_id, H_ENABLE_PREPARE_FOR_SUSPEND, 30000,
+                     0, 0, 0, 0);
+       if (rc == H_SUCCESS)
+               vscsi->flags |= PREP_FOR_SUSPEND_ENABLED;
+       else if (rc != H_NOT_FOUND)
+               pr_err("Error from Enable Prepare for Suspend: %ld\n", rc);
+
        vscsi->flags &= PRESERVE_FLAG_FIELDS;
        vscsi->rsp_q_timer.timer_pops = 0;
        vscsi->debit = 0;
@@ -951,6 +964,63 @@ static void ibmvscsis_free_cmd_resources(struct scsi_info *vscsi,
 }
 
 /**
+ * ibmvscsis_ready_for_suspend() - Helper function to call VIOCTL
+ * @vscsi:     Pointer to our adapter structure
+ * @idle:      Indicates whether we were called from adapter_idle.  This
+ *             is important to know if we need to do a disconnect, since if
+ *             we're called from adapter_idle, we're still processing the
+ *             current disconnect, so we can't just call post_disconnect.
+ *
+ * This function is called when the adapter is idle when phyp has sent
+ * us a Prepare for Suspend Transport Event.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Process or interrupt environment called with interrupt lock held
+ */
+static long ibmvscsis_ready_for_suspend(struct scsi_info *vscsi, bool idle)
+{
+       long rc = 0;
+       struct viosrp_crq *crq;
+
+       /* See if there is a Resume event in the queue */
+       crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
+
+       pr_debug("ready_suspend: flags 0x%x, state 0x%hx crq_valid:%x\n",
+                vscsi->flags, vscsi->state, (int)crq->valid);
+
+       if (!(vscsi->flags & PREP_FOR_SUSPEND_ABORTED) && !(crq->valid)) {
+               rc = h_vioctl(vscsi->dds.unit_id, H_READY_FOR_SUSPEND, 0, 0, 0,
+                             0, 0);
+               if (rc) {
+                       pr_err("Ready for Suspend Vioctl failed: %ld\n", rc);
+                       rc = 0;
+               }
+       } else if (((vscsi->flags & PREP_FOR_SUSPEND_OVERWRITE) &&
+                   (vscsi->flags & PREP_FOR_SUSPEND_ABORTED)) ||
+                  ((crq->valid) && ((crq->valid != VALID_TRANS_EVENT) ||
+                                    (crq->format != RESUME_FROM_SUSP)))) {
+               if (idle) {
+                       vscsi->state = ERR_DISCONNECT_RECONNECT;
+                       ibmvscsis_reset_queue(vscsi);
+                       rc = -1;
+               } else if (vscsi->state == CONNECTED) {
+                       ibmvscsis_post_disconnect(vscsi,
+                                                 ERR_DISCONNECT_RECONNECT, 0);
+               }
+
+               vscsi->flags &= ~PREP_FOR_SUSPEND_OVERWRITE;
+
+               if ((crq->valid) && ((crq->valid != VALID_TRANS_EVENT) ||
+                                    (crq->format != RESUME_FROM_SUSP)))
+                       pr_err("Invalid element in CRQ after Prepare for Suspend");
+       }
+
+       vscsi->flags &= ~(PREP_FOR_SUSPEND_PENDING | PREP_FOR_SUSPEND_ABORTED);
+
+       return rc;
+}
+
+/**
  * ibmvscsis_trans_event() - Handle a Transport Event
  * @vscsi:     Pointer to our adapter structure
  * @crq:       Pointer to CRQ entry containing the Transport Event
@@ -974,18 +1044,8 @@ static long ibmvscsis_trans_event(struct scsi_info *vscsi,
        case PARTNER_FAILED:
        case PARTNER_DEREGISTER:
                ibmvscsis_delete_client_info(vscsi, true);
-               break;
-
-       default:
-               rc = ERROR;
-               dev_err(&vscsi->dev, "trans_event: invalid format %d\n",
-                       (uint)crq->format);
-               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT,
-                                         RESPONSE_Q_DOWN);
-               break;
-       }
-
-       if (rc == ADAPT_SUCCESS) {
+               if (crq->format == MIGRATED)
+                       vscsi->flags &= ~PREP_FOR_SUSPEND_OVERWRITE;
                switch (vscsi->state) {
                case NO_QUEUE:
                case ERR_DISCONNECTED:
@@ -1034,6 +1094,60 @@ static long ibmvscsis_trans_event(struct scsi_info *vscsi,
                        vscsi->flags |= (RESPONSE_Q_DOWN | TRANS_EVENT);
                        break;
                }
+               break;
+
+       case PREPARE_FOR_SUSPEND:
+               pr_debug("Prep for Suspend, crq status = 0x%x\n",
+                        (int)crq->status);
+               switch (vscsi->state) {
+               case ERR_DISCONNECTED:
+               case WAIT_CONNECTION:
+               case CONNECTED:
+                       ibmvscsis_ready_for_suspend(vscsi, false);
+                       break;
+               case SRP_PROCESSING:
+                       vscsi->resume_state = vscsi->state;
+                       vscsi->flags |= PREP_FOR_SUSPEND_PENDING;
+                       if (crq->status == CRQ_ENTRY_OVERWRITTEN)
+                               vscsi->flags |= PREP_FOR_SUSPEND_OVERWRITE;
+                       ibmvscsis_post_disconnect(vscsi, WAIT_IDLE, 0);
+                       break;
+               case NO_QUEUE:
+               case UNDEFINED:
+               case UNCONFIGURING:
+               case WAIT_ENABLED:
+               case ERR_DISCONNECT:
+               case ERR_DISCONNECT_RECONNECT:
+               case WAIT_IDLE:
+                       pr_err("Invalid state for Prepare for Suspend Trans Event: 0x%x\n",
+                              vscsi->state);
+                       break;
+               }
+               break;
+
+       case RESUME_FROM_SUSP:
+               pr_debug("Resume from Suspend, crq status = 0x%x\n",
+                        (int)crq->status);
+               if (vscsi->flags & PREP_FOR_SUSPEND_PENDING) {
+                       vscsi->flags |= PREP_FOR_SUSPEND_ABORTED;
+               } else {
+                       if ((crq->status == CRQ_ENTRY_OVERWRITTEN) ||
+                           (vscsi->flags & PREP_FOR_SUSPEND_OVERWRITE)) {
+                               ibmvscsis_post_disconnect(vscsi,
+                                                         ERR_DISCONNECT_RECONNECT,
+                                                         0);
+                               vscsi->flags &= ~PREP_FOR_SUSPEND_OVERWRITE;
+                       }
+               }
+               break;
+
+       default:
+               rc = ERROR;
+               dev_err(&vscsi->dev, "trans_event: invalid format %d\n",
+                       (uint)crq->format);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT,
+                                         RESPONSE_Q_DOWN);
+               break;
        }
 
        rc = vscsi->flags & SCHEDULE_DISCONNECT;
@@ -1201,6 +1315,7 @@ static struct ibmvscsis_cmd *ibmvscsis_get_free_cmd(struct scsi_info *vscsi)
 static void ibmvscsis_adapter_idle(struct scsi_info *vscsi)
 {
        int free_qs = false;
+       long rc = 0;
 
        pr_debug("adapter_idle: flags 0x%x, state 0x%hx\n", vscsi->flags,
                 vscsi->state);
@@ -1240,7 +1355,14 @@ static void ibmvscsis_adapter_idle(struct scsi_info *vscsi)
                vscsi->rsp_q_timer.timer_pops = 0;
                vscsi->debit = 0;
                vscsi->credit = 0;
-               if (vscsi->flags & TRANS_EVENT) {
+               if (vscsi->flags & PREP_FOR_SUSPEND_PENDING) {
+                       vscsi->state = vscsi->resume_state;
+                       vscsi->resume_state = 0;
+                       rc = ibmvscsis_ready_for_suspend(vscsi, true);
+                       vscsi->flags &= ~DISCONNECT_SCHEDULED;
+                       if (rc)
+                               break;
+               } else if (vscsi->flags & TRANS_EVENT) {
                        vscsi->state = WAIT_CONNECTION;
                        vscsi->flags &= PRESERVE_FLAG_FIELDS;
                } else {
@@ -3792,8 +3914,16 @@ static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
 {
        struct ibmvscsis_tport *tport =
                container_of(wwn, struct ibmvscsis_tport, tport_wwn);
+       u16 tpgt;
        int rc;
 
+       if (strstr(name, "tpgt_") != name)
+               return ERR_PTR(-EINVAL);
+       rc = kstrtou16(name + 5, 0, &tpgt);
+       if (rc)
+               return ERR_PTR(rc);
+       tport->tport_tpgt = tpgt;
+
        tport->releasing = false;
 
        rc = core_tpg_register(&tport->tport_wwn, &tport->se_tpg,
index b4391a8..cc96c27 100644 (file)
@@ -262,6 +262,14 @@ struct scsi_info {
 #define DISCONNECT_SCHEDULED          0x00800
        /* remove function is sleeping */
 #define CFG_SLEEPING                  0x01000
+       /* Register for Prepare for Suspend Transport Events */
+#define PREP_FOR_SUSPEND_ENABLED      0x02000
+       /* Prepare for Suspend event sent */
+#define PREP_FOR_SUSPEND_PENDING      0x04000
+       /* Resume from Suspend event sent */
+#define PREP_FOR_SUSPEND_ABORTED      0x08000
+       /* Prepare for Suspend event overwrote another CRQ entry */
+#define PREP_FOR_SUSPEND_OVERWRITE    0x10000
        u32 flags;
        /* adapter lock */
        spinlock_t intr_lock;
@@ -272,6 +280,7 @@ struct scsi_info {
        /* used in crq, to tag what iu the response is for */
        u64  empty_iu_tag;
        uint new_state;
+       uint resume_state;
        /* control block for the response queue timer */
        struct timer_cb rsp_q_timer;
        /* keep last client to enable proper accounting */
@@ -324,8 +333,13 @@ struct scsi_info {
 #define TARGET_STOP(VSCSI) (long)(((VSCSI)->state & DONT_PROCESS_STATE) | \
                                  ((VSCSI)->flags & BLOCK))
 
+#define PREP_FOR_SUSPEND_FLAGS  (PREP_FOR_SUSPEND_ENABLED | \
+                                PREP_FOR_SUSPEND_PENDING | \
+                                PREP_FOR_SUSPEND_ABORTED | \
+                                PREP_FOR_SUSPEND_OVERWRITE)
+
 /* flag bit that are not reset during disconnect */
-#define PRESERVE_FLAG_FIELDS 0
+#define PRESERVE_FLAG_FIELDS (PREP_FOR_SUSPEND_FLAGS)
 
 #define vio_iu(IUE) ((union viosrp_iu *)((IUE)->sbuf->buf))
 
@@ -333,8 +347,15 @@ struct scsi_info {
 #define WRITE_CMD(cdb) (((cdb)[0] & 0x1F) == 0xA)
 
 #ifndef H_GET_PARTNER_INFO
-#define H_GET_PARTNER_INFO      0x0000000000000008LL
+#define H_GET_PARTNER_INFO              0x0000000000000008LL
+#endif
+#ifndef H_ENABLE_PREPARE_FOR_SUSPEND
+#define H_ENABLE_PREPARE_FOR_SUSPEND    0x000000000000001DLL
 #endif
+#ifndef H_READY_FOR_SUSPEND
+#define H_READY_FOR_SUSPEND             0x000000000000001ELL
+#endif
+
 
 #define h_copy_rdma(l, sa, sb, da, db) \
                plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db)
index 4696f33..9fec55b 100644 (file)
@@ -30,10 +30,13 @@ enum srp_trans_event {
        UNUSED_FORMAT = 0,
        PARTNER_FAILED = 1,
        PARTNER_DEREGISTER = 2,
-       MIGRATED = 6
+       MIGRATED = 6,
+       PREPARE_FOR_SUSPEND = 9,
+       RESUME_FROM_SUSP = 0xA
 };
 
 enum srp_status {
+       CRQ_ENTRY_OVERWRITTEN = 0x20,
        HEADER_DESCRIPTOR = 0xF1,
        PING = 0xF5,
        PING_RESPONSE = 0xF6
index 47f66e9..ed197bc 100644 (file)
@@ -213,7 +213,7 @@ static void sci_task_request_build_ssp_task_iu(struct isci_request *ireq)
  * @task_context:
  *
  */
-static void scu_ssp_reqeust_construct_task_context(
+static void scu_ssp_request_construct_task_context(
        struct isci_request *ireq,
        struct scu_task_context *task_context)
 {
@@ -425,7 +425,7 @@ static void scu_ssp_io_request_construct_task_context(struct isci_request *ireq,
        u8 prot_type = scsi_get_prot_type(scmd);
        u8 prot_op = scsi_get_prot_op(scmd);
 
-       scu_ssp_reqeust_construct_task_context(ireq, task_context);
+       scu_ssp_request_construct_task_context(ireq, task_context);
 
        task_context->ssp_command_iu_length =
                sizeof(struct ssp_cmd_iu) / sizeof(u32);
@@ -472,7 +472,7 @@ static void scu_ssp_task_request_construct_task_context(struct isci_request *ire
 {
        struct scu_task_context *task_context = ireq->tc;
 
-       scu_ssp_reqeust_construct_task_context(ireq, task_context);
+       scu_ssp_request_construct_task_context(ireq, task_context);
 
        task_context->control_frame                = 1;
        task_context->priority                     = SCU_TASK_PRIORITY_HIGH;
@@ -495,7 +495,7 @@ static void scu_ssp_task_request_construct_task_context(struct isci_request *ire
  * the command buffer is complete. none Revisit task context construction to
  * determine what is common for SSP/SMP/STP task context structures.
  */
-static void scu_sata_reqeust_construct_task_context(
+static void scu_sata_request_construct_task_context(
        struct isci_request *ireq,
        struct scu_task_context *task_context)
 {
@@ -562,7 +562,7 @@ static void scu_stp_raw_request_construct_task_context(struct isci_request *ireq
 {
        struct scu_task_context *task_context = ireq->tc;
 
-       scu_sata_reqeust_construct_task_context(ireq, task_context);
+       scu_sata_request_construct_task_context(ireq, task_context);
 
        task_context->control_frame         = 0;
        task_context->priority              = SCU_TASK_PRIORITY_NORMAL;
@@ -613,7 +613,7 @@ static void sci_stp_optimized_request_construct(struct isci_request *ireq,
        struct scu_task_context *task_context = ireq->tc;
 
        /* Build the STP task context structure */
-       scu_sata_reqeust_construct_task_context(ireq, task_context);
+       scu_sata_request_construct_task_context(ireq, task_context);
 
        /* Copy over the SGL elements */
        sci_request_build_sgl(ireq);
@@ -1401,7 +1401,7 @@ static enum sci_status sci_stp_request_pio_data_out_transmit_data(struct isci_re
  * @data_buffer: The buffer of data to be copied.
  * @length: The length of the data transfer.
  *
- * Copy the data from the buffer for the length specified to the IO reqeust SGL
+ * Copy the data from the buffer for the length specified to the IO request SGL
  * specified data region. enum sci_status
  */
 static enum sci_status
index fd501f8..8660f92 100644 (file)
@@ -573,7 +573,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,
                event = DISC_EV_FAILED;
        }
        if (error)
-               fc_disc_error(disc, fp);
+               fc_disc_error(disc, ERR_PTR(error));
        else if (event != DISC_EV_NONE)
                fc_disc_done(disc, event);
        fc_frame_free(fp);
index b58bba4..7786c97 100644 (file)
@@ -1227,7 +1227,7 @@ static void qedf_rport_event_handler(struct fc_lport *lport,
 
                if (rdata->spp_type != FC_TYPE_FCP) {
                        QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
-                           "Not offlading since since spp type isn't FCP\n");
+                           "Not offloading since spp type isn't FCP\n");
                        break;
                }
                if (!(rdata->ids.roles & FC_RPORT_ROLE_FCP_TARGET)) {
index 32632c9..91d2f51 100644 (file)
 #include <linux/qed/qed_iscsi_if.h>
 #include <linux/qed/qed_ll2_if.h>
 #include "qedi_version.h"
+#include "qedi_nvm_iscsi_cfg.h"
 
 #define QEDI_MODULE_NAME               "qedi"
 
 struct qedi_endpoint;
 
+#ifndef GET_FIELD2
+#define GET_FIELD2(value, name) \
+       (((value) & (name ## _MASK)) >> (name ## _OFFSET))
+#endif
+
 /*
  * PCI function probe defines
  */
@@ -66,6 +72,11 @@ struct qedi_endpoint;
 #define QEDI_HW_DMA_BOUNDARY   0xfff
 #define QEDI_PATH_HANDLE       0xFE0000000UL
 
+enum qedi_nvm_tgts {
+       QEDI_NVM_TGT_PRI,
+       QEDI_NVM_TGT_SEC,
+};
+
 struct qedi_uio_ctrl {
        /* meta data */
        u32 uio_hsi_version;
@@ -283,6 +294,8 @@ struct qedi_ctx {
        void *bdq_pbl_list;
        dma_addr_t bdq_pbl_list_dma;
        u8 bdq_pbl_list_num_entries;
+       struct nvm_iscsi_cfg *iscsi_cfg;
+       dma_addr_t nvm_buf_dma;
        void __iomem *bdq_primary_prod;
        void __iomem *bdq_secondary_prod;
        u16 bdq_prod_idx;
@@ -337,6 +350,10 @@ struct qedi_ctx {
        bool use_fast_sge;
 
        atomic_t num_offloads;
+#define SYSFS_FLAG_FW_SEL_BOOT 2
+#define IPV6_LEN       41
+#define IPV4_LEN       17
+       struct iscsi_boot_kset *boot_kset;
 };
 
 struct qedi_work {
index 19254bd..93d54ac 100644 (file)
@@ -1411,7 +1411,7 @@ static void qedi_tmf_work(struct work_struct *work)
 
        list_work = kzalloc(sizeof(*list_work), GFP_ATOMIC);
        if (!list_work) {
-               QEDI_ERR(&qedi->dbg_ctx, "Memory alloction failed\n");
+               QEDI_ERR(&qedi->dbg_ctx, "Memory allocation failed\n");
                goto abort_ret;
        }
 
index 5f5a4ef..2c37836 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mm.h>
 #include <linux/if_vlan.h>
 #include <linux/cpu.h>
+#include <linux/iscsi_boot_sysfs.h>
 
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -1143,6 +1144,30 @@ exit_setup_int:
        return rc;
 }
 
+static void qedi_free_nvm_iscsi_cfg(struct qedi_ctx *qedi)
+{
+       if (qedi->iscsi_cfg)
+               dma_free_coherent(&qedi->pdev->dev,
+                                 sizeof(struct nvm_iscsi_cfg),
+                                 qedi->iscsi_cfg, qedi->nvm_buf_dma);
+}
+
+static int qedi_alloc_nvm_iscsi_cfg(struct qedi_ctx *qedi)
+{
+       qedi->iscsi_cfg = dma_zalloc_coherent(&qedi->pdev->dev,
+                                            sizeof(struct nvm_iscsi_cfg),
+                                            &qedi->nvm_buf_dma, GFP_KERNEL);
+       if (!qedi->iscsi_cfg) {
+               QEDI_ERR(&qedi->dbg_ctx, "Could not allocate NVM BUF.\n");
+               return -ENOMEM;
+       }
+       QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+                 "NVM BUF addr=0x%p dma=0x%llx.\n", qedi->iscsi_cfg,
+                 qedi->nvm_buf_dma);
+
+       return 0;
+}
+
 static void qedi_free_bdq(struct qedi_ctx *qedi)
 {
        int i;
@@ -1183,6 +1208,7 @@ static void qedi_free_global_queues(struct qedi_ctx *qedi)
                kfree(gl[i]);
        }
        qedi_free_bdq(qedi);
+       qedi_free_nvm_iscsi_cfg(qedi);
 }
 
 static int qedi_alloc_bdq(struct qedi_ctx *qedi)
@@ -1309,6 +1335,11 @@ static int qedi_alloc_global_queues(struct qedi_ctx *qedi)
        if (rc)
                goto mem_alloc_failure;
 
+       /* Allocate DMA coherent buffers for NVM_ISCSI_CFG */
+       rc = qedi_alloc_nvm_iscsi_cfg(qedi);
+       if (rc)
+               goto mem_alloc_failure;
+
        /* Allocate a CQ and an associated PBL for each MSI-X
         * vector.
         */
@@ -1671,6 +1702,387 @@ void qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu)
        qedi_ops->ll2->start(qedi->cdev, &params);
 }
 
+/**
+ * qedi_get_nvram_block: - Scan through the iSCSI NVRAM block (while accounting
+ * for gaps) for the matching absolute-pf-id of the QEDI device.
+ */
+static struct nvm_iscsi_block *
+qedi_get_nvram_block(struct qedi_ctx *qedi)
+{
+       int i;
+       u8 pf;
+       u32 flags;
+       struct nvm_iscsi_block *block;
+
+       pf = qedi->dev_info.common.abs_pf_id;
+       block = &qedi->iscsi_cfg->block[0];
+       for (i = 0; i < NUM_OF_ISCSI_PF_SUPPORTED; i++, block++) {
+               flags = ((block->id) & NVM_ISCSI_CFG_BLK_CTRL_FLAG_MASK) >>
+                       NVM_ISCSI_CFG_BLK_CTRL_FLAG_OFFSET;
+               if (flags & (NVM_ISCSI_CFG_BLK_CTRL_FLAG_IS_NOT_EMPTY |
+                               NVM_ISCSI_CFG_BLK_CTRL_FLAG_PF_MAPPED) &&
+                       (pf == (block->id & NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_MASK)
+                               >> NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_OFFSET))
+                       return block;
+       }
+       return NULL;
+}
+
+static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf)
+{
+       struct qedi_ctx *qedi = data;
+       struct nvm_iscsi_initiator *initiator;
+       char *str = buf;
+       int rc = 1;
+       u32 ipv6_en, dhcp_en, ip_len;
+       struct nvm_iscsi_block *block;
+       char *fmt, *ip, *sub, *gw;
+
+       block = qedi_get_nvram_block(qedi);
+       if (!block)
+               return 0;
+
+       initiator = &block->initiator;
+       ipv6_en = block->generic.ctrl_flags &
+                 NVM_ISCSI_CFG_GEN_IPV6_ENABLED;
+       dhcp_en = block->generic.ctrl_flags &
+                 NVM_ISCSI_CFG_GEN_DHCP_TCPIP_CONFIG_ENABLED;
+       /* Static IP assignments. */
+       fmt = ipv6_en ? "%pI6\n" : "%pI4\n";
+       ip = ipv6_en ? initiator->ipv6.addr.byte : initiator->ipv4.addr.byte;
+       ip_len = ipv6_en ? IPV6_LEN : IPV4_LEN;
+       sub = ipv6_en ? initiator->ipv6.subnet_mask.byte :
+             initiator->ipv4.subnet_mask.byte;
+       gw = ipv6_en ? initiator->ipv6.gateway.byte :
+            initiator->ipv4.gateway.byte;
+       /* DHCP IP adjustments. */
+       fmt = dhcp_en ? "%s\n" : fmt;
+       if (dhcp_en) {
+               ip = ipv6_en ? "0::0" : "0.0.0.0";
+               sub = ip;
+               gw = ip;
+               ip_len = ipv6_en ? 5 : 8;
+       }
+
+       switch (type) {
+       case ISCSI_BOOT_ETH_IP_ADDR:
+               rc = snprintf(str, ip_len, fmt, ip);
+               break;
+       case ISCSI_BOOT_ETH_SUBNET_MASK:
+               rc = snprintf(str, ip_len, fmt, sub);
+               break;
+       case ISCSI_BOOT_ETH_GATEWAY:
+               rc = snprintf(str, ip_len, fmt, gw);
+               break;
+       case ISCSI_BOOT_ETH_FLAGS:
+               rc = snprintf(str, 3, "%hhd\n",
+                             SYSFS_FLAG_FW_SEL_BOOT);
+               break;
+       case ISCSI_BOOT_ETH_INDEX:
+               rc = snprintf(str, 3, "0\n");
+               break;
+       case ISCSI_BOOT_ETH_MAC:
+               rc = sysfs_format_mac(str, qedi->mac, ETH_ALEN);
+               break;
+       case ISCSI_BOOT_ETH_VLAN:
+               rc = snprintf(str, 12, "%d\n",
+                             GET_FIELD2(initiator->generic_cont0,
+                                        NVM_ISCSI_CFG_INITIATOR_VLAN));
+               break;
+       case ISCSI_BOOT_ETH_ORIGIN:
+               if (dhcp_en)
+                       rc = snprintf(str, 3, "3\n");
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+
+       return rc;
+}
+
+static umode_t qedi_eth_get_attr_visibility(void *data, int type)
+{
+       int rc = 1;
+
+       switch (type) {
+       case ISCSI_BOOT_ETH_FLAGS:
+       case ISCSI_BOOT_ETH_MAC:
+       case ISCSI_BOOT_ETH_INDEX:
+       case ISCSI_BOOT_ETH_IP_ADDR:
+       case ISCSI_BOOT_ETH_SUBNET_MASK:
+       case ISCSI_BOOT_ETH_GATEWAY:
+       case ISCSI_BOOT_ETH_ORIGIN:
+       case ISCSI_BOOT_ETH_VLAN:
+               rc = 0444;
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+       return rc;
+}
+
+static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf)
+{
+       struct qedi_ctx *qedi = data;
+       struct nvm_iscsi_initiator *initiator;
+       char *str = buf;
+       int rc;
+       struct nvm_iscsi_block *block;
+
+       block = qedi_get_nvram_block(qedi);
+       if (!block)
+               return 0;
+
+       initiator = &block->initiator;
+
+       switch (type) {
+       case ISCSI_BOOT_INI_INITIATOR_NAME:
+               rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n",
+                             initiator->initiator_name.byte);
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+       return rc;
+}
+
+static umode_t qedi_ini_get_attr_visibility(void *data, int type)
+{
+       int rc;
+
+       switch (type) {
+       case ISCSI_BOOT_INI_INITIATOR_NAME:
+               rc = 0444;
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+       return rc;
+}
+
+static ssize_t
+qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type,
+                       char *buf, enum qedi_nvm_tgts idx)
+{
+       char *str = buf;
+       int rc = 1;
+       u32 ctrl_flags, ipv6_en, chap_en, mchap_en, ip_len;
+       struct nvm_iscsi_block *block;
+       char *chap_name, *chap_secret;
+       char *mchap_name, *mchap_secret;
+
+       block = qedi_get_nvram_block(qedi);
+       if (!block)
+               goto exit_show_tgt_info;
+
+       QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_EVT,
+                 "Port:%d, tgt_idx:%d\n",
+                 GET_FIELD2(block->id, NVM_ISCSI_CFG_BLK_MAPPED_PF_ID), idx);
+
+       ctrl_flags = block->target[idx].ctrl_flags &
+                    NVM_ISCSI_CFG_TARGET_ENABLED;
+
+       if (!ctrl_flags) {
+               QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_EVT,
+                         "Target disabled\n");
+               goto exit_show_tgt_info;
+       }
+
+       ipv6_en = block->generic.ctrl_flags &
+                 NVM_ISCSI_CFG_GEN_IPV6_ENABLED;
+       ip_len = ipv6_en ? IPV6_LEN : IPV4_LEN;
+       chap_en = block->generic.ctrl_flags &
+                 NVM_ISCSI_CFG_GEN_CHAP_ENABLED;
+       chap_name = chap_en ? block->initiator.chap_name.byte : NULL;
+       chap_secret = chap_en ? block->initiator.chap_password.byte : NULL;
+
+       mchap_en = block->generic.ctrl_flags &
+                 NVM_ISCSI_CFG_GEN_CHAP_MUTUAL_ENABLED;
+       mchap_name = mchap_en ? block->target[idx].chap_name.byte : NULL;
+       mchap_secret = mchap_en ? block->target[idx].chap_password.byte : NULL;
+
+       switch (type) {
+       case ISCSI_BOOT_TGT_NAME:
+               rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n",
+                             block->target[idx].target_name.byte);
+               break;
+       case ISCSI_BOOT_TGT_IP_ADDR:
+               if (ipv6_en)
+                       rc = snprintf(str, ip_len, "%pI6\n",
+                                     block->target[idx].ipv6_addr.byte);
+               else
+                       rc = snprintf(str, ip_len, "%pI4\n",
+                                     block->target[idx].ipv4_addr.byte);
+               break;
+       case ISCSI_BOOT_TGT_PORT:
+               rc = snprintf(str, 12, "%d\n",
+                             GET_FIELD2(block->target[idx].generic_cont0,
+                                        NVM_ISCSI_CFG_TARGET_TCP_PORT));
+               break;
+       case ISCSI_BOOT_TGT_LUN:
+               rc = snprintf(str, 22, "%.*d\n",
+                             block->target[idx].lun.value[1],
+                             block->target[idx].lun.value[0]);
+               break;
+       case ISCSI_BOOT_TGT_CHAP_NAME:
+               rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n",
+                             chap_name);
+               break;
+       case ISCSI_BOOT_TGT_CHAP_SECRET:
+               rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n",
+                             chap_secret);
+               break;
+       case ISCSI_BOOT_TGT_REV_CHAP_NAME:
+               rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n",
+                             mchap_name);
+               break;
+       case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
+               rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n",
+                             mchap_secret);
+               break;
+       case ISCSI_BOOT_TGT_FLAGS:
+               rc = snprintf(str, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT);
+               break;
+       case ISCSI_BOOT_TGT_NIC_ASSOC:
+               rc = snprintf(str, 3, "0\n");
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+
+exit_show_tgt_info:
+       return rc;
+}
+
+static ssize_t qedi_show_boot_tgt_pri_info(void *data, int type, char *buf)
+{
+       struct qedi_ctx *qedi = data;
+
+       return qedi_show_boot_tgt_info(qedi, type, buf, QEDI_NVM_TGT_PRI);
+}
+
+static ssize_t qedi_show_boot_tgt_sec_info(void *data, int type, char *buf)
+{
+       struct qedi_ctx *qedi = data;
+
+       return qedi_show_boot_tgt_info(qedi, type, buf, QEDI_NVM_TGT_SEC);
+}
+
+static umode_t qedi_tgt_get_attr_visibility(void *data, int type)
+{
+       int rc;
+
+       switch (type) {
+       case ISCSI_BOOT_TGT_NAME:
+       case ISCSI_BOOT_TGT_IP_ADDR:
+       case ISCSI_BOOT_TGT_PORT:
+       case ISCSI_BOOT_TGT_LUN:
+       case ISCSI_BOOT_TGT_CHAP_NAME:
+       case ISCSI_BOOT_TGT_CHAP_SECRET:
+       case ISCSI_BOOT_TGT_REV_CHAP_NAME:
+       case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
+       case ISCSI_BOOT_TGT_NIC_ASSOC:
+       case ISCSI_BOOT_TGT_FLAGS:
+               rc = 0444;
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+       return rc;
+}
+
+static void qedi_boot_release(void *data)
+{
+       struct qedi_ctx *qedi = data;
+
+       scsi_host_put(qedi->shost);
+}
+
+static int qedi_get_boot_info(struct qedi_ctx *qedi)
+{
+       int ret = 1;
+       u16 len;
+
+       len = sizeof(struct nvm_iscsi_cfg);
+
+       QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+                 "Get NVM iSCSI CFG image\n");
+       ret = qedi_ops->common->nvm_get_image(qedi->cdev,
+                                             QED_NVM_IMAGE_ISCSI_CFG,
+                                             (char *)qedi->iscsi_cfg, len);
+       if (ret)
+               QEDI_ERR(&qedi->dbg_ctx,
+                        "Could not get NVM image. ret = %d\n", ret);
+
+       return ret;
+}
+
+static int qedi_setup_boot_info(struct qedi_ctx *qedi)
+{
+       struct iscsi_boot_kobj *boot_kobj;
+
+       if (qedi_get_boot_info(qedi))
+               return -EPERM;
+
+       qedi->boot_kset = iscsi_boot_create_host_kset(qedi->shost->host_no);
+       if (!qedi->boot_kset)
+               goto kset_free;
+
+       if (!scsi_host_get(qedi->shost))
+               goto kset_free;
+
+       boot_kobj = iscsi_boot_create_target(qedi->boot_kset, 0, qedi,
+                                            qedi_show_boot_tgt_pri_info,
+                                            qedi_tgt_get_attr_visibility,
+                                            qedi_boot_release);
+       if (!boot_kobj)
+               goto put_host;
+
+       if (!scsi_host_get(qedi->shost))
+               goto kset_free;
+
+       boot_kobj = iscsi_boot_create_target(qedi->boot_kset, 1, qedi,
+                                            qedi_show_boot_tgt_sec_info,
+                                            qedi_tgt_get_attr_visibility,
+                                            qedi_boot_release);
+       if (!boot_kobj)
+               goto put_host;
+
+       if (!scsi_host_get(qedi->shost))
+               goto kset_free;
+
+       boot_kobj = iscsi_boot_create_initiator(qedi->boot_kset, 0, qedi,
+                                               qedi_show_boot_ini_info,
+                                               qedi_ini_get_attr_visibility,
+                                               qedi_boot_release);
+       if (!boot_kobj)
+               goto put_host;
+
+       if (!scsi_host_get(qedi->shost))
+               goto kset_free;
+
+       boot_kobj = iscsi_boot_create_ethernet(qedi->boot_kset, 0, qedi,
+                                              qedi_show_boot_eth_info,
+                                              qedi_eth_get_attr_visibility,
+                                              qedi_boot_release);
+       if (!boot_kobj)
+               goto put_host;
+
+       return 0;
+
+put_host:
+       scsi_host_put(qedi->shost);
+kset_free:
+       iscsi_boot_destroy_kset(qedi->boot_kset);
+       return -ENOMEM;
+}
+
 static void __qedi_remove(struct pci_dev *pdev, int mode)
 {
        struct qedi_ctx *qedi = pci_get_drvdata(pdev);
@@ -1724,6 +2136,9 @@ static void __qedi_remove(struct pci_dev *pdev, int mode)
                        qedi->ll2_recv_thread = NULL;
                }
                qedi_ll2_free_skbs(qedi);
+
+               if (qedi->boot_kset)
+                       iscsi_boot_destroy_kset(qedi->boot_kset);
        }
 }
 
@@ -1967,6 +2382,10 @@ static int __qedi_probe(struct pci_dev *pdev, int mode)
                /* F/w needs 1st task context memory entry for performance */
                set_bit(QEDI_RESERVE_TASK_ID, qedi->task_idx_map);
                atomic_set(&qedi->num_offloads, 0);
+
+               if (qedi_setup_boot_info(qedi))
+                       QEDI_ERR(&qedi->dbg_ctx,
+                                "No iSCSI boot target configured\n");
        }
 
        return 0;
diff --git a/drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h b/drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h
new file mode 100644 (file)
index 0000000..df39b69
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * QLogic iSCSI Offload Driver
+ * Copyright (c) 2016 Cavium Inc.
+ *
+ * This software is available under the terms of the GNU General Public License
+ * (GPL) Version 2, available from the file COPYING in the main directory of
+ * this source tree.
+ */
+
+#ifndef NVM_ISCSI_CFG_H
+#define NVM_ISCSI_CFG_H
+
+#define NUM_OF_ISCSI_TARGET_PER_PF    4   /* Defined as per the
+                                          * ISCSI IBFT constraint
+                                          */
+#define NUM_OF_ISCSI_PF_SUPPORTED     4   /* One PF per Port -
+                                          * assuming 4 port card
+                                          */
+
+#define NVM_ISCSI_CFG_DHCP_NAME_MAX_LEN  256
+
+union nvm_iscsi_dhcp_vendor_id {
+       u32 value[NVM_ISCSI_CFG_DHCP_NAME_MAX_LEN / 4];
+       u8  byte[NVM_ISCSI_CFG_DHCP_NAME_MAX_LEN];
+};
+
+#define NVM_ISCSI_IPV4_ADDR_BYTE_LEN 4
+union nvm_iscsi_ipv4_addr {
+       u32 addr;
+       u8  byte[NVM_ISCSI_IPV4_ADDR_BYTE_LEN];
+};
+
+#define NVM_ISCSI_IPV6_ADDR_BYTE_LEN 16
+union nvm_iscsi_ipv6_addr {
+       u32 addr[4];
+       u8  byte[NVM_ISCSI_IPV6_ADDR_BYTE_LEN];
+};
+
+struct nvm_iscsi_initiator_ipv4 {
+       union nvm_iscsi_ipv4_addr addr;                         /* 0x0 */
+       union nvm_iscsi_ipv4_addr subnet_mask;                  /* 0x4 */
+       union nvm_iscsi_ipv4_addr gateway;                      /* 0x8 */
+       union nvm_iscsi_ipv4_addr primary_dns;                  /* 0xC */
+       union nvm_iscsi_ipv4_addr secondary_dns;                /* 0x10 */
+       union nvm_iscsi_ipv4_addr dhcp_addr;                    /* 0x14 */
+
+       union nvm_iscsi_ipv4_addr isns_server;                  /* 0x18 */
+       union nvm_iscsi_ipv4_addr slp_server;                   /* 0x1C */
+       union nvm_iscsi_ipv4_addr primay_radius_server;         /* 0x20 */
+       union nvm_iscsi_ipv4_addr secondary_radius_server;      /* 0x24 */
+
+       union nvm_iscsi_ipv4_addr rsvd[4];                      /* 0x28 */
+};
+
+struct nvm_iscsi_initiator_ipv6 {
+       union nvm_iscsi_ipv6_addr addr;                         /* 0x0 */
+       union nvm_iscsi_ipv6_addr subnet_mask;                  /* 0x10 */
+       union nvm_iscsi_ipv6_addr gateway;                      /* 0x20 */
+       union nvm_iscsi_ipv6_addr primary_dns;                  /* 0x30 */
+       union nvm_iscsi_ipv6_addr secondary_dns;                /* 0x40 */
+       union nvm_iscsi_ipv6_addr dhcp_addr;                    /* 0x50 */
+
+       union nvm_iscsi_ipv6_addr isns_server;                  /* 0x60 */
+       union nvm_iscsi_ipv6_addr slp_server;                   /* 0x70 */
+       union nvm_iscsi_ipv6_addr primay_radius_server;         /* 0x80 */
+       union nvm_iscsi_ipv6_addr secondary_radius_server;      /* 0x90 */
+
+       union nvm_iscsi_ipv6_addr rsvd[3];                      /* 0xA0 */
+
+       u32   config;                                           /* 0xD0 */
+#define NVM_ISCSI_CFG_INITIATOR_IPV6_SUBNET_MASK_PREFIX_MASK      0x000000FF
+#define NVM_ISCSI_CFG_INITIATOR_IPV6_SUBNET_MASK_PREFIX_OFFSET    0
+
+       u32   rsvd_1[3];
+};
+
+#define NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN  256
+union nvm_iscsi_name {
+       u32 value[NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN / 4];
+       u8  byte[NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN];
+};
+
+#define NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN  256
+union nvm_iscsi_chap_name {
+       u32 value[NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN / 4];
+       u8  byte[NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN];
+};
+
+#define NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN  16 /* md5 need per RFC1996
+                                           * is 16 octets
+                                           */
+union nvm_iscsi_chap_password {
+       u32 value[NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN / 4];
+       u8 byte[NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN];
+};
+
+union nvm_iscsi_lun {
+       u8  byte[8];
+       u32 value[2];
+};
+
+struct nvm_iscsi_generic {
+       u32 ctrl_flags;                                         /* 0x0 */
+#define NVM_ISCSI_CFG_GEN_CHAP_ENABLED                 BIT(0)
+#define NVM_ISCSI_CFG_GEN_DHCP_TCPIP_CONFIG_ENABLED    BIT(1)
+#define NVM_ISCSI_CFG_GEN_DHCP_ISCSI_CONFIG_ENABLED    BIT(2)
+#define NVM_ISCSI_CFG_GEN_IPV6_ENABLED                 BIT(3)
+#define NVM_ISCSI_CFG_GEN_IPV4_FALLBACK_ENABLED        BIT(4)
+#define NVM_ISCSI_CFG_GEN_ISNS_WORLD_LOGIN             BIT(5)
+#define NVM_ISCSI_CFG_GEN_ISNS_SELECTIVE_LOGIN         BIT(6)
+#define NVM_ISCSI_CFG_GEN_ADDR_REDIRECT_ENABLED               BIT(7)
+#define NVM_ISCSI_CFG_GEN_CHAP_MUTUAL_ENABLED          BIT(8)
+
+       u32 timeout;                                            /* 0x4 */
+#define NVM_ISCSI_CFG_GEN_DHCP_REQUEST_TIMEOUT_MASK       0x0000FFFF
+#define NVM_ISCSI_CFG_GEN_DHCP_REQUEST_TIMEOUT_OFFSET     0
+#define NVM_ISCSI_CFG_GEN_PORT_LOGIN_TIMEOUT_MASK         0xFFFF0000
+#define NVM_ISCSI_CFG_GEN_PORT_LOGIN_TIMEOUT_OFFSET       16
+
+       union nvm_iscsi_dhcp_vendor_id  dhcp_vendor_id;         /* 0x8  */
+       u32 rsvd[62];                                           /* 0x108 */
+};
+
+struct nvm_iscsi_initiator {
+       struct nvm_iscsi_initiator_ipv4 ipv4;                   /* 0x0 */
+       struct nvm_iscsi_initiator_ipv6 ipv6;                   /* 0x38 */
+
+       union nvm_iscsi_name           initiator_name;          /* 0x118 */
+       union nvm_iscsi_chap_name      chap_name;               /* 0x218 */
+       union nvm_iscsi_chap_password  chap_password;           /* 0x318 */
+
+       u32 generic_cont0;                                      /* 0x398 */
+#define NVM_ISCSI_CFG_INITIATOR_VLAN_MASK              0x0000FFFF
+#define NVM_ISCSI_CFG_INITIATOR_VLAN_OFFSET            0
+#define NVM_ISCSI_CFG_INITIATOR_IP_VERSION_MASK                0x00030000
+#define NVM_ISCSI_CFG_INITIATOR_IP_VERSION_OFFSET      16
+#define NVM_ISCSI_CFG_INITIATOR_IP_VERSION_4           1
+#define NVM_ISCSI_CFG_INITIATOR_IP_VERSION_6           2
+#define NVM_ISCSI_CFG_INITIATOR_IP_VERSION_4_AND_6     3
+
+       u32 ctrl_flags;
+#define NVM_ISCSI_CFG_INITIATOR_IP_VERSION_PRIORITY_V6     BIT(0)
+#define NVM_ISCSI_CFG_INITIATOR_VLAN_ENABLED               BIT(1)
+
+       u32 rsvd[116];                                          /* 0x32C */
+};
+
+struct nvm_iscsi_target {
+       u32 ctrl_flags;                                         /* 0x0 */
+#define NVM_ISCSI_CFG_TARGET_ENABLED            BIT(0)
+#define NVM_ISCSI_CFG_BOOT_TIME_LOGIN_STATUS    BIT(1)
+
+       u32 generic_cont0;                                      /* 0x4 */
+#define NVM_ISCSI_CFG_TARGET_TCP_PORT_MASK      0x0000FFFF
+#define NVM_ISCSI_CFG_TARGET_TCP_PORT_OFFSET    0
+
+       u32 ip_ver;
+#define NVM_ISCSI_CFG_IPv4       4
+#define NVM_ISCSI_CFG_IPv6       6
+
+       u32 rsvd_1[7];                                          /* 0x24 */
+       union nvm_iscsi_ipv4_addr ipv4_addr;                    /* 0x28 */
+       union nvm_iscsi_ipv6_addr ipv6_addr;                    /* 0x2C */
+       union nvm_iscsi_lun lun;                                /* 0x3C */
+
+       union nvm_iscsi_name           target_name;             /* 0x44 */
+       union nvm_iscsi_chap_name      chap_name;               /* 0x144 */
+       union nvm_iscsi_chap_password  chap_password;           /* 0x244 */
+
+       u32 rsvd_2[107];                                        /* 0x2C4 */
+};
+
+struct nvm_iscsi_block {
+       u32 id;                                                 /* 0x0 */
+#define NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_MASK         0x0000000F
+#define NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_OFFSET       0
+#define NVM_ISCSI_CFG_BLK_CTRL_FLAG_MASK            0x00000FF0
+#define NVM_ISCSI_CFG_BLK_CTRL_FLAG_OFFSET          4
+#define NVM_ISCSI_CFG_BLK_CTRL_FLAG_IS_NOT_EMPTY    BIT(0)
+#define NVM_ISCSI_CFG_BLK_CTRL_FLAG_PF_MAPPED       BIT(1)
+
+       u32 rsvd_1[5];                                          /* 0x4 */
+
+       struct nvm_iscsi_generic     generic;                   /* 0x18 */
+       struct nvm_iscsi_initiator   initiator;                 /* 0x218 */
+       struct nvm_iscsi_target      target[NUM_OF_ISCSI_TARGET_PER_PF];
+                                                               /* 0x718 */
+
+       u32 rsvd_2[58];                                         /* 0x1718 */
+       /* total size - 0x1800 - 6K block */
+};
+
+struct nvm_iscsi_cfg {
+       u32 id;                                                 /* 0x0 */
+#define NVM_ISCSI_CFG_BLK_VERSION_MINOR_MASK     0x000000FF
+#define NVM_ISCSI_CFG_BLK_VERSION_MAJOR_MASK     0x0000FF00
+#define NVM_ISCSI_CFG_BLK_SIGNATURE_MASK         0xFFFF0000
+#define NVM_ISCSI_CFG_BLK_SIGNATURE              0x49430000 /* IC - Iscsi
+                                                            * Config
+                                                            */
+
+#define NVM_ISCSI_CFG_BLK_VERSION_MAJOR          0
+#define NVM_ISCSI_CFG_BLK_VERSION_MINOR          10
+#define NVM_ISCSI_CFG_BLK_VERSION ((NVM_ISCSI_CFG_BLK_VERSION_MAJOR << 8) | \
+                                  NVM_ISCSI_CFG_BLK_VERSION_MINOR)
+
+       struct nvm_iscsi_block  block[NUM_OF_ISCSI_PF_SUPPORTED]; /* 0x4 */
+};
+
+#endif
index 2a0173e..e101cd3 100644 (file)
@@ -1874,36 +1874,13 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
        struct abts_recv_from_24xx *abts, struct fc_port *sess)
 {
        struct qla_hw_data *ha = vha->hw;
-       struct se_session *se_sess = sess->se_sess;
        struct qla_tgt_mgmt_cmd *mcmd;
-       struct qla_tgt_cmd *cmd;
-       struct se_cmd *se_cmd;
        int rc;
-       bool found_lun = false;
-       unsigned long flags;
-
-       spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
-       list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) {
-               if (se_cmd->tag == abts->exchange_addr_to_abort) {
-                       found_lun = true;
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
-       /* cmd not in LIO lists, look in qla list */
-       if (!found_lun) {
-               if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) {
-                       /* send TASK_ABORT response immediately */
-                       qlt_24xx_send_abts_resp(ha->base_qpair, abts,
-                           FCP_TMF_CMPL, false);
-                       return 0;
-               } else {
-                       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf081,
-                           "unable to find cmd in driver or LIO for tag 0x%x\n",
-                           abts->exchange_addr_to_abort);
-                       return -ENOENT;
-               }
+       if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) {
+               /* send TASK_ABORT response immediately */
+               qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_CMPL, false);
+               return 0;
        }
 
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f,
@@ -1919,14 +1896,17 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
        }
        memset(mcmd, 0, sizeof(*mcmd));
 
-       cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd);
        mcmd->sess = sess;
        memcpy(&mcmd->orig_iocb.abts, abts, sizeof(mcmd->orig_iocb.abts));
        mcmd->reset_count = ha->base_qpair->chip_reset;
        mcmd->tmr_func = QLA_TGT_ABTS;
        mcmd->qpair = ha->base_qpair;
 
-       rc = ha->tgt.tgt_ops->handle_tmr(mcmd, cmd->unpacked_lun, mcmd->tmr_func,
+       /*
+        * LUN is looked up by target-core internally based on the passed
+        * abts->exchange_addr_to_abort tag.
+        */
+       rc = ha->tgt.tgt_ops->handle_tmr(mcmd, 0, mcmd->tmr_func,
            abts->exchange_addr_to_abort);
        if (rc != 0) {
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf052,
@@ -3747,7 +3727,7 @@ static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha,
        h &= QLA_CMD_HANDLE_MASK;
 
        if (h != QLA_TGT_NULL_HANDLE) {
-               if (unlikely(h > req->num_outstanding_cmds)) {
+               if (unlikely(h >= req->num_outstanding_cmds)) {
                        ql_dbg(ql_dbg_tgt, vha, 0xe052,
                            "qla_target(%d): Wrong handle %x received\n",
                            vha->vp_idx, handle);
index c4b4148..b20da0d 100644 (file)
@@ -600,11 +600,13 @@ static int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, u64 lun,
        struct fc_port *sess = mcmd->sess;
        struct se_cmd *se_cmd = &mcmd->se_cmd;
        int transl_tmr_func = 0;
+       int flags = TARGET_SCF_ACK_KREF;
 
        switch (tmr_func) {
        case QLA_TGT_ABTS:
                pr_debug("%ld: ABTS received\n", sess->vha->host_no);
                transl_tmr_func = TMR_ABORT_TASK;
+               flags |= TARGET_SCF_LOOKUP_LUN_FROM_TAG;
                break;
        case QLA_TGT_2G_ABORT_TASK:
                pr_debug("%ld: 2G Abort Task received\n", sess->vha->host_no);
@@ -637,7 +639,7 @@ static int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, u64 lun,
        }
 
        return target_submit_tmr(se_cmd, sess->se_sess, NULL, lun, mcmd,
-           transl_tmr_func, GFP_ATOMIC, tag, TARGET_SCF_ACK_KREF);
+           transl_tmr_func, GFP_ATOMIC, tag, flags);
 }
 
 static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
index 21225d6..4fe606b 100644 (file)
@@ -758,8 +758,14 @@ static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
                if (hp->dxferp || hp->dxfer_len > 0)
                        return false;
                return true;
-       case SG_DXFER_TO_DEV:
        case SG_DXFER_FROM_DEV:
+               /*
+                * for SG_DXFER_FROM_DEV we always set dxfer_len to > 0. dxferp
+                * can either be NULL or != NULL so there's no point in checking
+                * it either. So just return true.
+                */
+               return true;
+       case SG_DXFER_TO_DEV:
        case SG_DXFER_TO_FROM_DEV:
                if (!hp->dxferp || hp->dxfer_len == 0)
                        return false;
index 07ec8a8..e164ffa 100644 (file)
@@ -690,7 +690,7 @@ struct pqi_config_table_heartbeat {
 
 #define PQI_MAX_OUTSTANDING_REQUESTS           ((u32)~0)
 #define PQI_MAX_OUTSTANDING_REQUESTS_KDUMP     32
-#define PQI_MAX_TRANSFER_SIZE                  (4 * 1024U * 1024U)
+#define PQI_MAX_TRANSFER_SIZE                  (1024U * 1024U)
 #define PQI_MAX_TRANSFER_SIZE_KDUMP            (512 * 1024U)
 
 #define RAID_MAP_MAX_ENTRIES           1024
index 8b93197..9be211d 100644 (file)
@@ -837,6 +837,7 @@ static struct scsi_host_template virtscsi_host_template_multi = {
        .eh_abort_handler = virtscsi_abort,
        .eh_device_reset_handler = virtscsi_device_reset,
        .eh_timed_out = virtscsi_eh_timed_out,
+       .slave_alloc = virtscsi_device_alloc,
 
        .can_queue = 1024,
        .dma_boundary = UINT_MAX,
index 2afe359..f4b7a98 100644 (file)
@@ -134,7 +134,6 @@ struct apid_data {
  * @spmic:             SPMI controller object
  * @ver_ops:           version dependent operations.
  * @ppid_to_apid       in-memory copy of PPID -> channel (APID) mapping table.
- *                     v2 only.
  */
 struct spmi_pmic_arb {
        void __iomem            *rd_base;
@@ -1016,6 +1015,13 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
                goto err_put_ctrl;
        }
 
+       pa->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID,
+                                       sizeof(*pa->ppid_to_apid), GFP_KERNEL);
+       if (!pa->ppid_to_apid) {
+               err = -ENOMEM;
+               goto err_put_ctrl;
+       }
+
        hw_ver = readl_relaxed(core + PMIC_ARB_VERSION);
 
        if (hw_ver < PMIC_ARB_VERSION_V2_MIN) {
@@ -1048,15 +1054,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
                        err = PTR_ERR(pa->wr_base);
                        goto err_put_ctrl;
                }
-
-               pa->ppid_to_apid = devm_kcalloc(&ctrl->dev,
-                                               PMIC_ARB_MAX_PPID,
-                                               sizeof(*pa->ppid_to_apid),
-                                               GFP_KERNEL);
-               if (!pa->ppid_to_apid) {
-                       err = -ENOMEM;
-                       goto err_put_ctrl;
-               }
        }
 
        dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
index 2b9b094..6d23226 100644 (file)
@@ -365,11 +365,23 @@ static int spmi_drv_remove(struct device *dev)
        return 0;
 }
 
+static int spmi_drv_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       int ret;
+
+       ret = of_device_uevent_modalias(dev, env);
+       if (ret != -ENODEV)
+               return ret;
+
+       return 0;
+}
+
 static struct bus_type spmi_bus_type = {
        .name           = "spmi",
        .match          = spmi_device_match,
        .probe          = spmi_drv_probe,
        .remove         = spmi_drv_remove,
+       .uevent         = spmi_drv_uevent,
 };
 
 /**
index 268d4e6..ef28a1c 100644 (file)
@@ -110,4 +110,6 @@ source "drivers/staging/ccree/Kconfig"
 
 source "drivers/staging/typec/Kconfig"
 
+source "drivers/staging/vboxvideo/Kconfig"
+
 endif # STAGING
index b93e6f5..2918580 100644 (file)
@@ -44,3 +44,4 @@ obj-$(CONFIG_KS7010)          += ks7010/
 obj-$(CONFIG_GREYBUS)          += greybus/
 obj-$(CONFIG_BCM2835_VCHIQ)    += vc04_services/
 obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/
+obj-$(CONFIG_DRM_VBOXVIDEO)    += vboxvideo/
index b2e3828..2f7bfc1 100644 (file)
@@ -3116,8 +3116,7 @@ static void ni_ao_cmd_set_update(struct comedi_device *dev,
                /* following line: 2-1 per STC */
                ni_stc_writel(dev, 1, NISTC_AO_UI_LOADA_REG);
                ni_stc_writew(dev, NISTC_AO_CMD1_UI_LOAD, NISTC_AO_CMD1_REG);
-               /* following line: N-1 per STC */
-               ni_stc_writel(dev, trigvar - 1, NISTC_AO_UI_LOADA_REG);
+               ni_stc_writel(dev, trigvar, NISTC_AO_UI_LOADA_REG);
        } else { /* TRIG_EXT */
                /* FIXME:  assert scan_begin_arg != 0, ret failure otherwise */
                devpriv->ao_cmd2  |= NISTC_AO_CMD2_BC_GATE_ENA;
index 85b242e..8fc191d 100644 (file)
@@ -1640,8 +1640,13 @@ kiblnd_send(struct lnet_ni *ni, void *private, struct lnet_msg *lntmsg)
        ibmsg = tx->tx_msg;
        ibmsg->ibm_u.immediate.ibim_hdr = *hdr;
 
-       copy_from_iter(&ibmsg->ibm_u.immediate.ibim_payload, IBLND_MSG_SIZE,
-                      &from);
+       rc = copy_from_iter(&ibmsg->ibm_u.immediate.ibim_payload, payload_nob,
+                           &from);
+       if (rc != payload_nob) {
+               kiblnd_pool_free_node(&tx->tx_pool->tpo_pool, &tx->tx_list);
+               return -EFAULT;
+       }
+
        nob = offsetof(struct kib_immediate_msg, ibim_payload[payload_nob]);
        kiblnd_init_tx_msg(ni, tx, IBLND_MSG_IMMEDIATE, nob);
 
@@ -1741,8 +1746,14 @@ kiblnd_recv(struct lnet_ni *ni, void *private, struct lnet_msg *lntmsg,
                        break;
                }
 
-               copy_to_iter(&rxmsg->ibm_u.immediate.ibim_payload,
-                            IBLND_MSG_SIZE, to);
+               rc = copy_to_iter(&rxmsg->ibm_u.immediate.ibim_payload, rlen,
+                                 to);
+               if (rc != rlen) {
+                       rc = -EFAULT;
+                       break;
+               }
+
+               rc = 0;
                lnet_finalize(ni, lntmsg, 0);
                break;
 
index e389009..a4e3ae8 100644 (file)
@@ -915,6 +915,8 @@ static int spinand_probe(struct spi_device *spi_nand)
        chip->waitfunc  = spinand_wait;
        chip->options   |= NAND_CACHEPRG;
        chip->select_chip = spinand_select_chip;
+       chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+       chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
 
        mtd = nand_to_mtd(chip);
 
index 002d091..a69007e 100644 (file)
@@ -132,7 +132,7 @@ void rtw_free_cmd_obj(struct cmd_obj *pcmd)
                kfree(pcmd->parmbuf);
        }
 
-       if (!pcmd->rsp) {
+       if (pcmd->rsp) {
                if (pcmd->rspsz != 0) {
                        /* free rsp in cmd_obj */
                        kfree(pcmd->rsp);
index 963235f..d283341 100644 (file)
@@ -43,6 +43,7 @@ static struct usb_device_id rtw_usb_id_tbl[] = {
        {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */
        {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */
        {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */
+       {USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */
        {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */
        {}      /* Terminating entry */
 };
index 944dd25..4754f7a 100644 (file)
@@ -40,7 +40,7 @@ static unsigned int get_mxclk_freq(void)
 
        pll_reg = peek32(MXCLK_PLL_CTRL);
        M = (pll_reg & PLL_CTRL_M_MASK) >> PLL_CTRL_M_SHIFT;
-       N = (pll_reg & PLL_CTRL_N_MASK) >> PLL_CTRL_M_SHIFT;
+       N = (pll_reg & PLL_CTRL_N_MASK) >> PLL_CTRL_N_SHIFT;
        OD = (pll_reg & PLL_CTRL_OD_MASK) >> PLL_CTRL_OD_SHIFT;
        POD = (pll_reg & PLL_CTRL_POD_MASK) >> PLL_CTRL_POD_SHIFT;
 
index 3aa4128..67207b0 100644 (file)
@@ -1053,6 +1053,26 @@ release_fb:
        return err;
 }
 
+static int lynxfb_kick_out_firmware_fb(struct pci_dev *pdev)
+{
+       struct apertures_struct *ap;
+       bool primary = false;
+
+       ap = alloc_apertures(1);
+       if (!ap)
+               return -ENOMEM;
+
+       ap->ranges[0].base = pci_resource_start(pdev, 0);
+       ap->ranges[0].size = pci_resource_len(pdev, 0);
+#ifdef CONFIG_X86
+       primary = pdev->resource[PCI_ROM_RESOURCE].flags &
+                                       IORESOURCE_ROM_SHADOW;
+#endif
+       remove_conflicting_framebuffers(ap, "sm750_fb1", primary);
+       kfree(ap);
+       return 0;
+}
+
 static int lynxfb_pci_probe(struct pci_dev *pdev,
                            const struct pci_device_id *ent)
 {
@@ -1061,6 +1081,10 @@ static int lynxfb_pci_probe(struct pci_dev *pdev,
        int fbidx;
        int err;
 
+       err = lynxfb_kick_out_firmware_fb(pdev);
+       if (err)
+               return err;
+
        /* enable device */
        err = pcim_enable_device(pdev);
        if (err)
index 82e5de2..67956e2 100644 (file)
@@ -2314,6 +2314,7 @@ static void __exit speakup_exit(void)
        mutex_lock(&spk_mutex);
        synth_release();
        mutex_unlock(&spk_mutex);
+       spk_ttyio_unregister_ldisc();
 
        speakup_kobj_exit();
 
@@ -2376,6 +2377,7 @@ static int __init speakup_init(void)
        if (err)
                goto error_kobjects;
 
+       spk_ttyio_register_ldisc();
        synth_init(synth_name);
        speakup_register_devsynth();
        /*
index 87b6a0a..046040a 100644 (file)
@@ -48,6 +48,8 @@ void spk_stop_serial_interrupt(void);
 int spk_wait_for_xmitr(struct spk_synth *in_synth);
 void spk_serial_release(void);
 void spk_ttyio_release(void);
+void spk_ttyio_register_ldisc(void);
+void spk_ttyio_unregister_ldisc(void);
 
 void synth_buffer_skip_nonlatin1(void);
 u16 synth_buffer_getc(void);
index ed8e96b..fe340b0 100644 (file)
@@ -154,12 +154,6 @@ static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
        struct ktermios tmp_termios;
        dev_t dev;
 
-       ret = tty_register_ldisc(N_SPEAKUP, &spk_ttyio_ldisc_ops);
-       if (ret) {
-               pr_err("Error registering line discipline.\n");
-               return ret;
-       }
-
        ret = get_dev_to_use(synth, &dev);
        if (ret)
                return ret;
@@ -196,10 +190,24 @@ static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
        tty_unlock(tty);
 
        ret = tty_set_ldisc(tty, N_SPEAKUP);
+       if (ret)
+               pr_err("speakup: Failed to set N_SPEAKUP on tty\n");
 
        return ret;
 }
 
+void spk_ttyio_register_ldisc(void)
+{
+       if (tty_register_ldisc(N_SPEAKUP, &spk_ttyio_ldisc_ops))
+               pr_warn("speakup: Error registering line discipline. Most synths won't work.\n");
+}
+
+void spk_ttyio_unregister_ldisc(void)
+{
+       if (tty_unregister_ldisc(N_SPEAKUP))
+               pr_warn("speakup: Couldn't unregister ldisc\n");
+}
+
 static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
 {
        if (in_synth->alive && speakup_tty && speakup_tty->ops->write) {
@@ -300,7 +308,7 @@ void spk_ttyio_release(void)
 
        tty_ldisc_flush(speakup_tty);
        tty_unlock(speakup_tty);
-       tty_ldisc_release(speakup_tty);
+       tty_release_struct(speakup_tty, speakup_tty->index);
 }
 EXPORT_SYMBOL_GPL(spk_ttyio_release);
 
diff --git a/drivers/staging/vboxvideo/Kconfig b/drivers/staging/vboxvideo/Kconfig
new file mode 100644 (file)
index 0000000..a52746f
--- /dev/null
@@ -0,0 +1,12 @@
+config DRM_VBOXVIDEO
+       tristate "Virtual Box Graphics Card"
+       depends on DRM && X86 && PCI
+       select DRM_KMS_HELPER
+       help
+         This is a KMS driver for the virtual Graphics Card used in
+         Virtual Box virtual machines.
+
+         Although it is possible to builtin this module, it is advised
+         to build this driver as a module, so that it can be updated
+         independently of the kernel. Select M to built this driver as a
+         module and add support for these devices via drm/kms interfaces.
diff --git a/drivers/staging/vboxvideo/Makefile b/drivers/staging/vboxvideo/Makefile
new file mode 100644 (file)
index 0000000..2d0b3bc
--- /dev/null
@@ -0,0 +1,7 @@
+ccflags-y := -Iinclude/drm
+
+vboxvideo-y :=  hgsmi_base.o modesetting.o vbva_base.o \
+               vbox_drv.o vbox_fb.o vbox_hgsmi.o vbox_irq.o vbox_main.o \
+               vbox_mode.o vbox_prime.o vbox_ttm.o
+
+obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo.o
diff --git a/drivers/staging/vboxvideo/TODO b/drivers/staging/vboxvideo/TODO
new file mode 100644 (file)
index 0000000..ce76430
--- /dev/null
@@ -0,0 +1,9 @@
+TODO:
+-Move the driver over to the atomic API
+-Stop using old load / unload drm_driver hooks
+-Get a full review from the drm-maintainers on dri-devel done on this driver
+-Extend this TODO with the results of that review
+
+Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
+Hans de Goede <hdegoede@redhat.com> and
+Michael Thayer <michael.thayer@oracle.com>.
diff --git a/drivers/staging/vboxvideo/hgsmi_base.c b/drivers/staging/vboxvideo/hgsmi_base.c
new file mode 100644 (file)
index 0000000..15ff5f4
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "vbox_drv.h"
+#include "vbox_err.h"
+#include "vboxvideo_guest.h"
+#include "vboxvideo_vbe.h"
+#include "hgsmi_channels.h"
+#include "hgsmi_ch_setup.h"
+
+/**
+ * Inform the host of the location of the host flags in VRAM via an HGSMI cmd.
+ * @param    ctx          the context of the guest heap to use.
+ * @param    location     the offset chosen for the flags within guest VRAM.
+ * @returns 0 on success, -errno on failure
+ */
+int hgsmi_report_flags_location(struct gen_pool *ctx, u32 location)
+{
+       struct hgsmi_buffer_location *p;
+
+       p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_HGSMI,
+                              HGSMI_CC_HOST_FLAGS_LOCATION);
+       if (!p)
+               return -ENOMEM;
+
+       p->buf_location = location;
+       p->buf_len = sizeof(struct hgsmi_host_flags);
+
+       hgsmi_buffer_submit(ctx, p);
+       hgsmi_buffer_free(ctx, p);
+
+       return 0;
+}
+
+/**
+ * Notify the host of HGSMI-related guest capabilities via an HGSMI command.
+ * @param    ctx                 the context of the guest heap to use.
+ * @param    caps                the capabilities to report, see vbva_caps.
+ * @returns 0 on success, -errno on failure
+ */
+int hgsmi_send_caps_info(struct gen_pool *ctx, u32 caps)
+{
+       struct vbva_caps *p;
+
+       p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA, VBVA_INFO_CAPS);
+       if (!p)
+               return -ENOMEM;
+
+       p->rc = VERR_NOT_IMPLEMENTED;
+       p->caps = caps;
+
+       hgsmi_buffer_submit(ctx, p);
+
+       WARN_ON_ONCE(RT_FAILURE(p->rc));
+
+       hgsmi_buffer_free(ctx, p);
+
+       return 0;
+}
+
+int hgsmi_test_query_conf(struct gen_pool *ctx)
+{
+       u32 value = 0;
+       int ret;
+
+       ret = hgsmi_query_conf(ctx, U32_MAX, &value);
+       if (ret)
+               return ret;
+
+       return value == U32_MAX ? 0 : -EIO;
+}
+
+/**
+ * Query the host for an HGSMI configuration parameter via an HGSMI command.
+ * @param  ctx        the context containing the heap used
+ * @param  index      the index of the parameter to query,
+ *                    @see vbva_conf32::index
+ * @param  value_ret  where to store the value of the parameter on success
+ * @returns 0 on success, -errno on failure
+ */
+int hgsmi_query_conf(struct gen_pool *ctx, u32 index, u32 *value_ret)
+{
+       struct vbva_conf32 *p;
+
+       p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
+                              VBVA_QUERY_CONF32);
+       if (!p)
+               return -ENOMEM;
+
+       p->index = index;
+       p->value = U32_MAX;
+
+       hgsmi_buffer_submit(ctx, p);
+
+       *value_ret = p->value;
+
+       hgsmi_buffer_free(ctx, p);
+
+       return 0;
+}
+
+/**
+ * Pass the host a new mouse pointer shape via an HGSMI command.
+ *
+ * @param  ctx      the context containing the heap to be used
+ * @param  flags    cursor flags, @see VMMDevReqMousePointer::flags
+ * @param  hot_x    horizontal position of the hot spot
+ * @param  hot_y    vertical position of the hot spot
+ * @param  width    width in pixels of the cursor
+ * @param  height   height in pixels of the cursor
+ * @param  pixels   pixel data, @see VMMDevReqMousePointer for the format
+ * @param  len      size in bytes of the pixel data
+ * @returns 0 on success, -errno on failure
+ */
+int hgsmi_update_pointer_shape(struct gen_pool *ctx, u32 flags,
+                              u32 hot_x, u32 hot_y, u32 width, u32 height,
+                              u8 *pixels, u32 len)
+{
+       struct vbva_mouse_pointer_shape *p;
+       u32 pixel_len = 0;
+       int rc;
+
+       if (flags & VBOX_MOUSE_POINTER_SHAPE) {
+               /*
+                * Size of the pointer data:
+                * sizeof (AND mask) + sizeof (XOR_MASK)
+                */
+               pixel_len = ((((width + 7) / 8) * height + 3) & ~3) +
+                        width * 4 * height;
+               if (pixel_len > len)
+                       return -EINVAL;
+
+               /*
+                * If shape is supplied, then always create the pointer visible.
+                * See comments in 'vboxUpdatePointerShape'
+                */
+               flags |= VBOX_MOUSE_POINTER_VISIBLE;
+       }
+
+       p = hgsmi_buffer_alloc(ctx, sizeof(*p) + pixel_len, HGSMI_CH_VBVA,
+                              VBVA_MOUSE_POINTER_SHAPE);
+       if (!p)
+               return -ENOMEM;
+
+       p->result = VINF_SUCCESS;
+       p->flags = flags;
+       p->hot_X = hot_x;
+       p->hot_y = hot_y;
+       p->width = width;
+       p->height = height;
+       if (pixel_len)
+               memcpy(p->data, pixels, pixel_len);
+
+       hgsmi_buffer_submit(ctx, p);
+
+       switch (p->result) {
+       case VINF_SUCCESS:
+               rc = 0;
+               break;
+       case VERR_NO_MEMORY:
+               rc = -ENOMEM;
+               break;
+       case VERR_NOT_SUPPORTED:
+               rc = -EBUSY;
+               break;
+       default:
+               rc = -EINVAL;
+       }
+
+       hgsmi_buffer_free(ctx, p);
+
+       return rc;
+}
+
+/**
+ * Report the guest cursor position.  The host may wish to use this information
+ * to re-position its own cursor (though this is currently unlikely).  The
+ * current host cursor position is returned.
+ * @param  ctx              The context containing the heap used.
+ * @param  report_position  Are we reporting a position?
+ * @param  x                Guest cursor X position.
+ * @param  y                Guest cursor Y position.
+ * @param  x_host           Host cursor X position is stored here.  Optional.
+ * @param  y_host           Host cursor Y position is stored here.  Optional.
+ * @returns 0 on success, -errno on failure
+ */
+int hgsmi_cursor_position(struct gen_pool *ctx, bool report_position,
+                         u32 x, u32 y, u32 *x_host, u32 *y_host)
+{
+       struct vbva_cursor_position *p;
+
+       p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
+                              VBVA_CURSOR_POSITION);
+       if (!p)
+               return -ENOMEM;
+
+       p->report_position = report_position;
+       p->x = x;
+       p->y = y;
+
+       hgsmi_buffer_submit(ctx, p);
+
+       *x_host = p->x;
+       *y_host = p->y;
+
+       hgsmi_buffer_free(ctx, p);
+
+       return 0;
+}
+
+/**
+ * @todo Mouse pointer position to be read from VMMDev memory, address of the
+ * memory region can be queried from VMMDev via an IOCTL. This VMMDev memory
+ * region will contain host information which is needed by the guest.
+ *
+ * Reading will not cause a switch to the host.
+ *
+ * Have to take into account:
+ *  * synchronization: host must write to the memory only from EMT,
+ *    large structures must be read under flag, which tells the host
+ *    that the guest is currently reading the memory (OWNER flag?).
+ *  * guest writes: may be allocate a page for the host info and make
+ *    the page readonly for the guest.
+ *  * the information should be available only for additions drivers.
+ *  * VMMDev additions driver will inform the host which version of the info
+ *    it expects, host must support all versions.
+ */
diff --git a/drivers/staging/vboxvideo/hgsmi_ch_setup.h b/drivers/staging/vboxvideo/hgsmi_ch_setup.h
new file mode 100644 (file)
index 0000000..8e6d9e1
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __HGSMI_CH_SETUP_H__
+#define __HGSMI_CH_SETUP_H__
+
+/*
+ * Tell the host the location of hgsmi_host_flags structure, where the host
+ * can write information about pending buffers, etc, and which can be quickly
+ * polled by the guest without a need to port IO.
+ */
+#define HGSMI_CC_HOST_FLAGS_LOCATION 0
+
+struct hgsmi_buffer_location {
+       u32 buf_location;
+       u32 buf_len;
+} __packed;
+
+/* HGSMI setup and configuration data structures. */
+/* host->guest commands pending, should be accessed under FIFO lock only */
+#define HGSMIHOSTFLAGS_COMMANDS_PENDING    0x01u
+/* IRQ is fired, should be accessed under VGAState::lock only  */
+#define HGSMIHOSTFLAGS_IRQ                 0x02u
+/* vsync interrupt flag, should be accessed under VGAState::lock only */
+#define HGSMIHOSTFLAGS_VSYNC               0x10u
+/** monitor hotplug flag, should be accessed under VGAState::lock only */
+#define HGSMIHOSTFLAGS_HOTPLUG             0x20u
+/**
+ * Cursor capability state change flag, should be accessed under
+ * VGAState::lock only. @see vbva_conf32.
+ */
+#define HGSMIHOSTFLAGS_CURSOR_CAPABILITIES 0x40u
+
+struct hgsmi_host_flags {
+       /*
+        * Host flags can be accessed and modified in multiple threads
+        * concurrently, e.g. CrOpenGL HGCM and GUI threads when completing
+        * HGSMI 3D and Video Accel respectively, EMT thread when dealing with
+        * HGSMI command processing, etc.
+        * Besides settings/cleaning flags atomically, some flags have their
+        * own special sync restrictions, see comments for flags above.
+        */
+       u32 host_flags;
+       u32 reserved[3];
+} __packed;
+
+#endif
diff --git a/drivers/staging/vboxvideo/hgsmi_channels.h b/drivers/staging/vboxvideo/hgsmi_channels.h
new file mode 100644 (file)
index 0000000..a2a34b2
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __HGSMI_CHANNELS_H__
+#define __HGSMI_CHANNELS_H__
+
+/*
+ * Each channel has an 8 bit identifier. There are a number of predefined
+ * (hardcoded) channels.
+ *
+ * HGSMI_CH_HGSMI channel can be used to map a string channel identifier
+ * to a free 16 bit numerical value. values are allocated in range
+ * [HGSMI_CH_STRING_FIRST;HGSMI_CH_STRING_LAST].
+ */
+
+/* A reserved channel value */
+#define HGSMI_CH_RESERVED                              0x00
+/* HGCMI: setup and configuration */
+#define HGSMI_CH_HGSMI                                 0x01
+/* Graphics: VBVA */
+#define HGSMI_CH_VBVA                                  0x02
+/* Graphics: Seamless with a single guest region */
+#define HGSMI_CH_SEAMLESS                              0x03
+/* Graphics: Seamless with separate host windows */
+#define HGSMI_CH_SEAMLESS2                             0x04
+/* Graphics: OpenGL HW acceleration */
+#define HGSMI_CH_OPENGL                                        0x05
+
+/* The first channel index to be used for string mappings (inclusive) */
+#define HGSMI_CH_STRING_FIRST                          0x20
+/* The last channel index for string mappings (inclusive) */
+#define HGSMI_CH_STRING_LAST                           0xff
+
+#endif
diff --git a/drivers/staging/vboxvideo/hgsmi_defs.h b/drivers/staging/vboxvideo/hgsmi_defs.h
new file mode 100644 (file)
index 0000000..5b21fb9
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __HGSMI_DEFS_H__
+#define __HGSMI_DEFS_H__
+
+/* Buffer sequence type mask. */
+#define HGSMI_BUFFER_HEADER_F_SEQ_MASK     0x03
+/* Single buffer, not a part of a sequence. */
+#define HGSMI_BUFFER_HEADER_F_SEQ_SINGLE   0x00
+/* The first buffer in a sequence. */
+#define HGSMI_BUFFER_HEADER_F_SEQ_START    0x01
+/* A middle buffer in a sequence. */
+#define HGSMI_BUFFER_HEADER_F_SEQ_CONTINUE 0x02
+/* The last buffer in a sequence. */
+#define HGSMI_BUFFER_HEADER_F_SEQ_END      0x03
+
+/* 16 bytes buffer header. */
+struct hgsmi_buffer_header {
+       u32 data_size;          /* Size of data that follows the header. */
+       u8 flags;               /* HGSMI_BUFFER_HEADER_F_* */
+       u8 channel;             /* The channel the data must be routed to. */
+       u16 channel_info;       /* Opaque to the HGSMI, used by the channel. */
+
+       union {
+               /* Opaque placeholder to make the union 8 bytes. */
+               u8 header_data[8];
+
+               /* HGSMI_BUFFER_HEADER_F_SEQ_SINGLE */
+               struct {
+                       u32 reserved1;  /* A reserved field, initialize to 0. */
+                       u32 reserved2;  /* A reserved field, initialize to 0. */
+               } buffer;
+
+               /* HGSMI_BUFFER_HEADER_F_SEQ_START */
+               struct {
+                       /* Must be the same for all buffers in the sequence. */
+                       u32 sequence_number;
+                       /* The total size of the sequence. */
+                       u32 sequence_size;
+               } sequence_start;
+
+               /*
+                * HGSMI_BUFFER_HEADER_F_SEQ_CONTINUE and
+                * HGSMI_BUFFER_HEADER_F_SEQ_END
+                */
+               struct {
+                       /* Must be the same for all buffers in the sequence. */
+                       u32 sequence_number;
+                       /* Data offset in the entire sequence. */
+                       u32 sequence_offset;
+               } sequence_continue;
+       } u;
+} __packed;
+
+/* 8 bytes buffer tail. */
+struct hgsmi_buffer_tail {
+       /* Reserved, must be initialized to 0. */
+       u32 reserved;
+       /*
+        * One-at-a-Time Hash: http://www.burtleburtle.net/bob/hash/doobs.html
+        * Over the header, offset and for first 4 bytes of the tail.
+        */
+       u32 checksum;
+} __packed;
+
+/*
+ * The size of the array of channels. Array indexes are u8.
+ * Note: the value must not be changed.
+ */
+#define HGSMI_NUMBER_OF_CHANNELS 0x100
+
+#endif
diff --git a/drivers/staging/vboxvideo/modesetting.c b/drivers/staging/vboxvideo/modesetting.c
new file mode 100644 (file)
index 0000000..7616b8a
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "vbox_drv.h"
+#include "vbox_err.h"
+#include "vboxvideo_guest.h"
+#include "vboxvideo_vbe.h"
+#include "hgsmi_channels.h"
+
+/**
+ * Set a video mode via an HGSMI request.  The views must have been
+ * initialised first using @a VBoxHGSMISendViewInfo and if the mode is being
+ * set on the first display then it must be set first using registers.
+ * @param  ctx           The context containing the heap to use
+ * @param  display       The screen number
+ * @param  origin_x      The horizontal displacement relative to the first scrn
+ * @param  origin_y      The vertical displacement relative to the first screen
+ * @param  start_offset  The offset of the visible area of the framebuffer
+ *                       relative to the framebuffer start
+ * @param  pitch         The offset in bytes between the starts of two adjecent
+ *                       scan lines in video RAM
+ * @param  width         The mode width
+ * @param  height        The mode height
+ * @param  bpp           The colour depth of the mode
+ * @param  flags         Flags
+ */
+void hgsmi_process_display_info(struct gen_pool *ctx, u32 display,
+                               s32 origin_x, s32 origin_y, u32 start_offset,
+                               u32 pitch, u32 width, u32 height,
+                               u16 bpp, u16 flags)
+{
+       struct vbva_infoscreen *p;
+
+       p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
+                              VBVA_INFO_SCREEN);
+       if (!p)
+               return;
+
+       p->view_index = display;
+       p->origin_x = origin_x;
+       p->origin_y = origin_y;
+       p->start_offset = start_offset;
+       p->line_size = pitch;
+       p->width = width;
+       p->height = height;
+       p->bits_per_pixel = bpp;
+       p->flags = flags;
+
+       hgsmi_buffer_submit(ctx, p);
+       hgsmi_buffer_free(ctx, p);
+}
+
+/**
+ * Report the rectangle relative to which absolute pointer events should be
+ * expressed.  This information remains valid until the next VBVA resize event
+ * for any screen, at which time it is reset to the bounding rectangle of all
+ * virtual screens.
+ * @param  ctx       The context containing the heap to use.
+ * @param  origin_x  Upper left X co-ordinate relative to the first screen.
+ * @param  origin_y  Upper left Y co-ordinate relative to the first screen.
+ * @param  width     Rectangle width.
+ * @param  height    Rectangle height.
+ * @returns 0 on success, -errno on failure
+ */
+int hgsmi_update_input_mapping(struct gen_pool *ctx, s32 origin_x, s32 origin_y,
+                              u32 width, u32 height)
+{
+       struct vbva_report_input_mapping *p;
+
+       p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
+                              VBVA_REPORT_INPUT_MAPPING);
+       if (!p)
+               return -ENOMEM;
+
+       p->x = origin_x;
+       p->y = origin_y;
+       p->cx = width;
+       p->cy = height;
+
+       hgsmi_buffer_submit(ctx, p);
+       hgsmi_buffer_free(ctx, p);
+
+       return 0;
+}
+
+/**
+ * Get most recent video mode hints.
+ * @param  ctx      The context containing the heap to use.
+ * @param  screens  The number of screens to query hints for, starting at 0.
+ * @param  hints    Array of vbva_modehint structures for receiving the hints.
+ * @returns 0 on success, -errno on failure
+ */
+int hgsmi_get_mode_hints(struct gen_pool *ctx, unsigned int screens,
+                        struct vbva_modehint *hints)
+{
+       struct vbva_query_mode_hints *p;
+       size_t size;
+
+       if (WARN_ON(!hints))
+               return -EINVAL;
+
+       size = screens * sizeof(struct vbva_modehint);
+       p = hgsmi_buffer_alloc(ctx, sizeof(*p) + size, HGSMI_CH_VBVA,
+                              VBVA_QUERY_MODE_HINTS);
+       if (!p)
+               return -ENOMEM;
+
+       p->hints_queried_count = screens;
+       p->hint_structure_guest_size = sizeof(struct vbva_modehint);
+       p->rc = VERR_NOT_SUPPORTED;
+
+       hgsmi_buffer_submit(ctx, p);
+
+       if (RT_FAILURE(p->rc)) {
+               hgsmi_buffer_free(ctx, p);
+               return -EIO;
+       }
+
+       memcpy(hints, ((u8 *)p) + sizeof(struct vbva_query_mode_hints), size);
+       hgsmi_buffer_free(ctx, p);
+
+       return 0;
+}
diff --git a/drivers/staging/vboxvideo/vbox_drv.c b/drivers/staging/vboxvideo/vbox_drv.c
new file mode 100644 (file)
index 0000000..92ae156
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2013-2017 Oracle Corporation
+ * This file is based on ast_drv.c
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * Authors: Dave Airlie <airlied@redhat.com>
+ *          Michael Thayer <michael.thayer@oracle.com,
+ *          Hans de Goede <hdegoede@redhat.com>
+ */
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/vt_kern.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "vbox_drv.h"
+
+int vbox_modeset = -1;
+
+MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
+module_param_named(modeset, vbox_modeset, int, 0400);
+
+static struct drm_driver driver;
+
+static const struct pci_device_id pciidlist[] = {
+       { 0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { 0, 0, 0},
+};
+MODULE_DEVICE_TABLE(pci, pciidlist);
+
+static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       return drm_get_pci_dev(pdev, ent, &driver);
+}
+
+static void vbox_pci_remove(struct pci_dev *pdev)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+
+       drm_put_dev(dev);
+}
+
+static int vbox_drm_freeze(struct drm_device *dev)
+{
+       struct vbox_private *vbox = dev->dev_private;
+
+       drm_kms_helper_poll_disable(dev);
+
+       pci_save_state(dev->pdev);
+
+       drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, true);
+
+       return 0;
+}
+
+static int vbox_drm_thaw(struct drm_device *dev)
+{
+       struct vbox_private *vbox = dev->dev_private;
+
+       drm_mode_config_reset(dev);
+       drm_helper_resume_force_mode(dev);
+       drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, false);
+
+       return 0;
+}
+
+static int vbox_drm_resume(struct drm_device *dev)
+{
+       int ret;
+
+       if (pci_enable_device(dev->pdev))
+               return -EIO;
+
+       ret = vbox_drm_thaw(dev);
+       if (ret)
+               return ret;
+
+       drm_kms_helper_poll_enable(dev);
+
+       return 0;
+}
+
+static int vbox_pm_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *ddev = pci_get_drvdata(pdev);
+       int error;
+
+       error = vbox_drm_freeze(ddev);
+       if (error)
+               return error;
+
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+
+       return 0;
+}
+
+static int vbox_pm_resume(struct device *dev)
+{
+       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+
+       return vbox_drm_resume(ddev);
+}
+
+static int vbox_pm_freeze(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *ddev = pci_get_drvdata(pdev);
+
+       if (!ddev || !ddev->dev_private)
+               return -ENODEV;
+
+       return vbox_drm_freeze(ddev);
+}
+
+static int vbox_pm_thaw(struct device *dev)
+{
+       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+
+       return vbox_drm_thaw(ddev);
+}
+
+static int vbox_pm_poweroff(struct device *dev)
+{
+       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+
+       return vbox_drm_freeze(ddev);
+}
+
+static const struct dev_pm_ops vbox_pm_ops = {
+       .suspend = vbox_pm_suspend,
+       .resume = vbox_pm_resume,
+       .freeze = vbox_pm_freeze,
+       .thaw = vbox_pm_thaw,
+       .poweroff = vbox_pm_poweroff,
+       .restore = vbox_pm_resume,
+};
+
+static struct pci_driver vbox_pci_driver = {
+       .name = DRIVER_NAME,
+       .id_table = pciidlist,
+       .probe = vbox_pci_probe,
+       .remove = vbox_pci_remove,
+       .driver.pm = &vbox_pm_ops,
+};
+
+static const struct file_operations vbox_fops = {
+       .owner = THIS_MODULE,
+       .open = drm_open,
+       .release = drm_release,
+       .unlocked_ioctl = drm_ioctl,
+       .mmap = vbox_mmap,
+       .poll = drm_poll,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = drm_compat_ioctl,
+#endif
+       .read = drm_read,
+};
+
+static int vbox_master_set(struct drm_device *dev,
+                          struct drm_file *file_priv, bool from_open)
+{
+       struct vbox_private *vbox = dev->dev_private;
+
+       /*
+        * We do not yet know whether the new owner can handle hotplug, so we
+        * do not advertise dynamic modes on the first query and send a
+        * tentative hotplug notification after that to see if they query again.
+        */
+       vbox->initial_mode_queried = false;
+
+       mutex_lock(&vbox->hw_mutex);
+       /*
+        * Disable VBVA when someone releases master in case the next person
+        * tries tries to do VESA.
+        */
+       /** @todo work out if anyone is likely to and whether it will work. */
+       /*
+        * Update: we also disable it because if the new master does not do
+        * dirty rectangle reporting (e.g. old versions of Plymouth) then at
+        * least the first screen will still be updated. We enable it as soon
+        * as we receive a dirty rectangle report.
+        */
+       vbox_disable_accel(vbox);
+       mutex_unlock(&vbox->hw_mutex);
+
+       return 0;
+}
+
+static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
+{
+       struct vbox_private *vbox = dev->dev_private;
+
+       /* See vbox_master_set() */
+       vbox->initial_mode_queried = false;
+
+       mutex_lock(&vbox->hw_mutex);
+       vbox_disable_accel(vbox);
+       mutex_unlock(&vbox->hw_mutex);
+}
+
+static struct drm_driver driver = {
+       .driver_features =
+           DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
+           DRIVER_PRIME,
+       .dev_priv_size = 0,
+
+       .load = vbox_driver_load,
+       .unload = vbox_driver_unload,
+       .lastclose = vbox_driver_lastclose,
+       .master_set = vbox_master_set,
+       .master_drop = vbox_master_drop,
+       .set_busid = drm_pci_set_busid,
+
+       .fops = &vbox_fops,
+       .irq_handler = vbox_irq_handler,
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+       .date = DRIVER_DATE,
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+       .patchlevel = DRIVER_PATCHLEVEL,
+
+       .gem_free_object = vbox_gem_free_object,
+       .dumb_create = vbox_dumb_create,
+       .dumb_map_offset = vbox_dumb_mmap_offset,
+       .dumb_destroy = drm_gem_dumb_destroy,
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+       .gem_prime_export = drm_gem_prime_export,
+       .gem_prime_import = drm_gem_prime_import,
+       .gem_prime_pin = vbox_gem_prime_pin,
+       .gem_prime_unpin = vbox_gem_prime_unpin,
+       .gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
+       .gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
+       .gem_prime_vmap = vbox_gem_prime_vmap,
+       .gem_prime_vunmap = vbox_gem_prime_vunmap,
+       .gem_prime_mmap = vbox_gem_prime_mmap,
+};
+
+static int __init vbox_init(void)
+{
+#ifdef CONFIG_VGA_CONSOLE
+       if (vgacon_text_force() && vbox_modeset == -1)
+               return -EINVAL;
+#endif
+
+       if (vbox_modeset == 0)
+               return -EINVAL;
+
+       return drm_pci_init(&driver, &vbox_pci_driver);
+}
+
+static void __exit vbox_exit(void)
+{
+       drm_pci_exit(&driver, &vbox_pci_driver);
+}
+
+module_init(vbox_init);
+module_exit(vbox_exit);
+
+MODULE_AUTHOR("Oracle Corporation");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/staging/vboxvideo/vbox_drv.h b/drivers/staging/vboxvideo/vbox_drv.h
new file mode 100644 (file)
index 0000000..4b93027
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2013-2017 Oracle Corporation
+ * This file is based on ast_drv.h
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * Authors: Dave Airlie <airlied@redhat.com>
+ *          Michael Thayer <michael.thayer@oracle.com,
+ *          Hans de Goede <hdegoede@redhat.com>
+ */
+#ifndef __VBOX_DRV_H__
+#define __VBOX_DRV_H__
+
+#include <linux/genalloc.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/version.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem.h>
+
+#include <drm/ttm/ttm_bo_api.h>
+#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_placement.h>
+#include <drm/ttm/ttm_memory.h>
+#include <drm/ttm/ttm_module.h>
+
+#include "vboxvideo_guest.h"
+#include "vboxvideo_vbe.h"
+#include "hgsmi_ch_setup.h"
+
+#define DRIVER_NAME         "vboxvideo"
+#define DRIVER_DESC         "Oracle VM VirtualBox Graphics Card"
+#define DRIVER_DATE         "20130823"
+
+#define DRIVER_MAJOR        1
+#define DRIVER_MINOR        0
+#define DRIVER_PATCHLEVEL   0
+
+#define VBOX_MAX_CURSOR_WIDTH  64
+#define VBOX_MAX_CURSOR_HEIGHT 64
+#define CURSOR_PIXEL_COUNT (VBOX_MAX_CURSOR_WIDTH * VBOX_MAX_CURSOR_HEIGHT)
+#define CURSOR_DATA_SIZE (CURSOR_PIXEL_COUNT * 4 + CURSOR_PIXEL_COUNT / 8)
+
+#define VBOX_MAX_SCREENS  32
+
+#define GUEST_HEAP_OFFSET(vbox) ((vbox)->full_vram_size - \
+                                VBVA_ADAPTER_INFORMATION_SIZE)
+#define GUEST_HEAP_SIZE   VBVA_ADAPTER_INFORMATION_SIZE
+#define GUEST_HEAP_USABLE_SIZE (VBVA_ADAPTER_INFORMATION_SIZE - \
+                               sizeof(struct hgsmi_host_flags))
+#define HOST_FLAGS_OFFSET GUEST_HEAP_USABLE_SIZE
+
+struct vbox_fbdev;
+
+struct vbox_private {
+       struct drm_device *dev;
+
+       u8 __iomem *guest_heap;
+       u8 __iomem *vbva_buffers;
+       struct gen_pool *guest_pool;
+       struct vbva_buf_ctx *vbva_info;
+       bool any_pitch;
+       u32 num_crtcs;
+       /** Amount of available VRAM, including space used for buffers. */
+       u32 full_vram_size;
+       /** Amount of available VRAM, not including space used for buffers. */
+       u32 available_vram_size;
+       /** Array of structures for receiving mode hints. */
+       struct vbva_modehint *last_mode_hints;
+
+       struct vbox_fbdev *fbdev;
+
+       int fb_mtrr;
+
+       struct {
+               struct drm_global_reference mem_global_ref;
+               struct ttm_bo_global_ref bo_global_ref;
+               struct ttm_bo_device bdev;
+       } ttm;
+
+       struct mutex hw_mutex; /* protects modeset and accel/vbva accesses */
+       /**
+        * We decide whether or not user-space supports display hot-plug
+        * depending on whether they react to a hot-plug event after the initial
+        * mode query.
+        */
+       bool initial_mode_queried;
+       struct work_struct hotplug_work;
+       u32 input_mapping_width;
+       u32 input_mapping_height;
+       /**
+        * Is user-space using an X.Org-style layout of one large frame-buffer
+        * encompassing all screen ones or is the fbdev console active?
+        */
+       bool single_framebuffer;
+       u32 cursor_width;
+       u32 cursor_height;
+       u32 cursor_hot_x;
+       u32 cursor_hot_y;
+       size_t cursor_data_size;
+       u8 cursor_data[CURSOR_DATA_SIZE];
+};
+
+#undef CURSOR_PIXEL_COUNT
+#undef CURSOR_DATA_SIZE
+
+int vbox_driver_load(struct drm_device *dev, unsigned long flags);
+void vbox_driver_unload(struct drm_device *dev);
+void vbox_driver_lastclose(struct drm_device *dev);
+
+struct vbox_gem_object;
+
+struct vbox_connector {
+       struct drm_connector base;
+       char name[32];
+       struct vbox_crtc *vbox_crtc;
+       struct {
+               u16 width;
+               u16 height;
+               bool disconnected;
+       } mode_hint;
+};
+
+struct vbox_crtc {
+       struct drm_crtc base;
+       bool blanked;
+       bool disconnected;
+       unsigned int crtc_id;
+       u32 fb_offset;
+       bool cursor_enabled;
+       u16 x_hint;
+       u16 y_hint;
+};
+
+struct vbox_encoder {
+       struct drm_encoder base;
+};
+
+struct vbox_framebuffer {
+       struct drm_framebuffer base;
+       struct drm_gem_object *obj;
+};
+
+struct vbox_fbdev {
+       struct drm_fb_helper helper;
+       struct vbox_framebuffer afb;
+       int size;
+       struct ttm_bo_kmap_obj mapping;
+       int x1, y1, x2, y2;     /* dirty rect */
+       spinlock_t dirty_lock;
+};
+
+#define to_vbox_crtc(x) container_of(x, struct vbox_crtc, base)
+#define to_vbox_connector(x) container_of(x, struct vbox_connector, base)
+#define to_vbox_encoder(x) container_of(x, struct vbox_encoder, base)
+#define to_vbox_framebuffer(x) container_of(x, struct vbox_framebuffer, base)
+
+int vbox_mode_init(struct drm_device *dev);
+void vbox_mode_fini(struct drm_device *dev);
+
+#define DRM_MODE_FB_CMD drm_mode_fb_cmd2
+#define CRTC_FB(crtc) ((crtc)->primary->fb)
+
+void vbox_enable_accel(struct vbox_private *vbox);
+void vbox_disable_accel(struct vbox_private *vbox);
+void vbox_report_caps(struct vbox_private *vbox);
+
+void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb,
+                                      struct drm_clip_rect *rects,
+                                      unsigned int num_rects);
+
+int vbox_framebuffer_init(struct drm_device *dev,
+                         struct vbox_framebuffer *vbox_fb,
+                         const struct DRM_MODE_FB_CMD *mode_cmd,
+                         struct drm_gem_object *obj);
+
+int vbox_fbdev_init(struct drm_device *dev);
+void vbox_fbdev_fini(struct drm_device *dev);
+void vbox_fbdev_set_base(struct vbox_private *vbox, unsigned long gpu_addr);
+
+struct vbox_bo {
+       struct ttm_buffer_object bo;
+       struct ttm_placement placement;
+       struct ttm_bo_kmap_obj kmap;
+       struct drm_gem_object gem;
+       struct ttm_place placements[3];
+       int pin_count;
+};
+
+#define gem_to_vbox_bo(gobj) container_of((gobj), struct vbox_bo, gem)
+
+static inline struct vbox_bo *vbox_bo(struct ttm_buffer_object *bo)
+{
+       return container_of(bo, struct vbox_bo, bo);
+}
+
+#define to_vbox_obj(x) container_of(x, struct vbox_gem_object, base)
+
+int vbox_dumb_create(struct drm_file *file,
+                    struct drm_device *dev,
+                    struct drm_mode_create_dumb *args);
+
+void vbox_gem_free_object(struct drm_gem_object *obj);
+int vbox_dumb_mmap_offset(struct drm_file *file,
+                         struct drm_device *dev,
+                         u32 handle, u64 *offset);
+
+#define DRM_FILE_PAGE_OFFSET (0x10000000ULL >> PAGE_SHIFT)
+
+int vbox_mm_init(struct vbox_private *vbox);
+void vbox_mm_fini(struct vbox_private *vbox);
+
+int vbox_bo_create(struct drm_device *dev, int size, int align,
+                  u32 flags, struct vbox_bo **pvboxbo);
+
+int vbox_gem_create(struct drm_device *dev,
+                   u32 size, bool iskernel, struct drm_gem_object **obj);
+
+int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag, u64 *gpu_addr);
+int vbox_bo_unpin(struct vbox_bo *bo);
+
+static inline int vbox_bo_reserve(struct vbox_bo *bo, bool no_wait)
+{
+       int ret;
+
+       ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL);
+       if (ret) {
+               if (ret != -ERESTARTSYS && ret != -EBUSY)
+                       DRM_ERROR("reserve failed %p\n", bo);
+               return ret;
+       }
+       return 0;
+}
+
+static inline void vbox_bo_unreserve(struct vbox_bo *bo)
+{
+       ttm_bo_unreserve(&bo->bo);
+}
+
+void vbox_ttm_placement(struct vbox_bo *bo, int domain);
+int vbox_bo_push_sysram(struct vbox_bo *bo);
+int vbox_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/* vbox_prime.c */
+int vbox_gem_prime_pin(struct drm_gem_object *obj);
+void vbox_gem_prime_unpin(struct drm_gem_object *obj);
+struct sg_table *vbox_gem_prime_get_sg_table(struct drm_gem_object *obj);
+struct drm_gem_object *vbox_gem_prime_import_sg_table(
+       struct drm_device *dev, struct dma_buf_attachment *attach,
+       struct sg_table *table);
+void *vbox_gem_prime_vmap(struct drm_gem_object *obj);
+void vbox_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+int vbox_gem_prime_mmap(struct drm_gem_object *obj,
+                       struct vm_area_struct *area);
+
+/* vbox_irq.c */
+int vbox_irq_init(struct vbox_private *vbox);
+void vbox_irq_fini(struct vbox_private *vbox);
+void vbox_report_hotplug(struct vbox_private *vbox);
+irqreturn_t vbox_irq_handler(int irq, void *arg);
+
+/* vbox_hgsmi.c */
+void *hgsmi_buffer_alloc(struct gen_pool *guest_pool, size_t size,
+                        u8 channel, u16 channel_info);
+void hgsmi_buffer_free(struct gen_pool *guest_pool, void *buf);
+int hgsmi_buffer_submit(struct gen_pool *guest_pool, void *buf);
+
+static inline void vbox_write_ioport(u16 index, u16 data)
+{
+       outw(index, VBE_DISPI_IOPORT_INDEX);
+       outw(data, VBE_DISPI_IOPORT_DATA);
+}
+
+#endif
diff --git a/drivers/staging/vboxvideo/vbox_err.h b/drivers/staging/vboxvideo/vbox_err.h
new file mode 100644 (file)
index 0000000..562db86
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 Oracle Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __VBOX_ERR_H__
+#define __VBOX_ERR_H__
+
+/**
+ * @name VirtualBox virtual-hardware error macros
+ * @{
+ */
+
+#define VINF_SUCCESS                        0
+#define VERR_INVALID_PARAMETER              (-2)
+#define VERR_INVALID_POINTER                (-6)
+#define VERR_NO_MEMORY                      (-8)
+#define VERR_NOT_IMPLEMENTED                (-12)
+#define VERR_INVALID_FUNCTION               (-36)
+#define VERR_NOT_SUPPORTED                  (-37)
+#define VERR_TOO_MUCH_DATA                  (-42)
+#define VERR_INVALID_STATE                  (-79)
+#define VERR_OUT_OF_RESOURCES               (-80)
+#define VERR_ALREADY_EXISTS                 (-105)
+#define VERR_INTERNAL_ERROR                 (-225)
+
+#define RT_SUCCESS_NP(rc)   ((int)(rc) >= VINF_SUCCESS)
+#define RT_SUCCESS(rc)      (likely(RT_SUCCESS_NP(rc)))
+#define RT_FAILURE(rc)      (unlikely(!RT_SUCCESS_NP(rc)))
+
+/** @}  */
+
+#endif
diff --git a/drivers/staging/vboxvideo/vbox_fb.c b/drivers/staging/vboxvideo/vbox_fb.c
new file mode 100644 (file)
index 0000000..35f6d9f
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2013-2017 Oracle Corporation
+ * This file is based on ast_fb.c
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * Authors: Dave Airlie <airlied@redhat.com>
+ *          Michael Thayer <michael.thayer@oracle.com,
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "vbox_drv.h"
+#include "vboxvideo.h"
+
+#define VBOX_DIRTY_DELAY (HZ / 30)
+/**
+ * Tell the host about dirty rectangles to update.
+ */
+static void vbox_dirty_update(struct vbox_fbdev *fbdev,
+                             int x, int y, int width, int height)
+{
+       struct drm_gem_object *obj;
+       struct vbox_bo *bo;
+       int ret = -EBUSY;
+       bool store_for_later = false;
+       int x2, y2;
+       unsigned long flags;
+       struct drm_clip_rect rect;
+
+       obj = fbdev->afb.obj;
+       bo = gem_to_vbox_bo(obj);
+
+       /*
+        * try and reserve the BO, if we fail with busy
+        * then the BO is being moved and we should
+        * store up the damage until later.
+        */
+       if (drm_can_sleep())
+               ret = vbox_bo_reserve(bo, true);
+       if (ret) {
+               if (ret != -EBUSY)
+                       return;
+
+               store_for_later = true;
+       }
+
+       x2 = x + width - 1;
+       y2 = y + height - 1;
+       spin_lock_irqsave(&fbdev->dirty_lock, flags);
+
+       if (fbdev->y1 < y)
+               y = fbdev->y1;
+       if (fbdev->y2 > y2)
+               y2 = fbdev->y2;
+       if (fbdev->x1 < x)
+               x = fbdev->x1;
+       if (fbdev->x2 > x2)
+               x2 = fbdev->x2;
+
+       if (store_for_later) {
+               fbdev->x1 = x;
+               fbdev->x2 = x2;
+               fbdev->y1 = y;
+               fbdev->y2 = y2;
+               spin_unlock_irqrestore(&fbdev->dirty_lock, flags);
+               return;
+       }
+
+       fbdev->x1 = INT_MAX;
+       fbdev->y1 = INT_MAX;
+       fbdev->x2 = 0;
+       fbdev->y2 = 0;
+
+       spin_unlock_irqrestore(&fbdev->dirty_lock, flags);
+
+       /*
+        * Not sure why the original code subtracted 1 here, but I will keep
+        * it that way to avoid unnecessary differences.
+        */
+       rect.x1 = x;
+       rect.x2 = x2 + 1;
+       rect.y1 = y;
+       rect.y2 = y2 + 1;
+       vbox_framebuffer_dirty_rectangles(&fbdev->afb.base, &rect, 1);
+
+       vbox_bo_unreserve(bo);
+}
+
+#ifdef CONFIG_FB_DEFERRED_IO
+static void vbox_deferred_io(struct fb_info *info, struct list_head *pagelist)
+{
+       struct vbox_fbdev *fbdev = info->par;
+       unsigned long start, end, min, max;
+       struct page *page;
+       int y1, y2;
+
+       min = ULONG_MAX;
+       max = 0;
+       list_for_each_entry(page, pagelist, lru) {
+               start = page->index << PAGE_SHIFT;
+               end = start + PAGE_SIZE - 1;
+               min = min(min, start);
+               max = max(max, end);
+       }
+
+       if (min < max) {
+               y1 = min / info->fix.line_length;
+               y2 = (max / info->fix.line_length) + 1;
+               DRM_INFO("%s: Calling dirty update: 0, %d, %d, %d\n",
+                        __func__, y1, info->var.xres, y2 - y1 - 1);
+               vbox_dirty_update(fbdev, 0, y1, info->var.xres, y2 - y1 - 1);
+       }
+}
+
+static struct fb_deferred_io vbox_defio = {
+       .delay = VBOX_DIRTY_DELAY,
+       .deferred_io = vbox_deferred_io,
+};
+#endif
+
+static void vbox_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+       struct vbox_fbdev *fbdev = info->par;
+
+       sys_fillrect(info, rect);
+       vbox_dirty_update(fbdev, rect->dx, rect->dy, rect->width, rect->height);
+}
+
+static void vbox_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+       struct vbox_fbdev *fbdev = info->par;
+
+       sys_copyarea(info, area);
+       vbox_dirty_update(fbdev, area->dx, area->dy, area->width, area->height);
+}
+
+static void vbox_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       struct vbox_fbdev *fbdev = info->par;
+
+       sys_imageblit(info, image);
+       vbox_dirty_update(fbdev, image->dx, image->dy, image->width,
+                         image->height);
+}
+
+static struct fb_ops vboxfb_ops = {
+       .owner = THIS_MODULE,
+       .fb_check_var = drm_fb_helper_check_var,
+       .fb_set_par = drm_fb_helper_set_par,
+       .fb_fillrect = vbox_fillrect,
+       .fb_copyarea = vbox_copyarea,
+       .fb_imageblit = vbox_imageblit,
+       .fb_pan_display = drm_fb_helper_pan_display,
+       .fb_blank = drm_fb_helper_blank,
+       .fb_setcmap = drm_fb_helper_setcmap,
+       .fb_debug_enter = drm_fb_helper_debug_enter,
+       .fb_debug_leave = drm_fb_helper_debug_leave,
+};
+
+static int vboxfb_create_object(struct vbox_fbdev *fbdev,
+                               struct DRM_MODE_FB_CMD *mode_cmd,
+                               struct drm_gem_object **gobj_p)
+{
+       struct drm_device *dev = fbdev->helper.dev;
+       u32 size;
+       struct drm_gem_object *gobj;
+       u32 pitch = mode_cmd->pitches[0];
+       int ret;
+
+       size = pitch * mode_cmd->height;
+       ret = vbox_gem_create(dev, size, true, &gobj);
+       if (ret)
+               return ret;
+
+       *gobj_p = gobj;
+
+       return 0;
+}
+
+static int vboxfb_create(struct drm_fb_helper *helper,
+                        struct drm_fb_helper_surface_size *sizes)
+{
+       struct vbox_fbdev *fbdev =
+           container_of(helper, struct vbox_fbdev, helper);
+       struct drm_device *dev = fbdev->helper.dev;
+       struct DRM_MODE_FB_CMD mode_cmd;
+       struct drm_framebuffer *fb;
+       struct fb_info *info;
+       struct device *device = &dev->pdev->dev;
+       struct drm_gem_object *gobj;
+       struct vbox_bo *bo;
+       int size, ret;
+       u32 pitch;
+
+       mode_cmd.width = sizes->surface_width;
+       mode_cmd.height = sizes->surface_height;
+       pitch = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
+       mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+                                                         sizes->surface_depth);
+       mode_cmd.pitches[0] = pitch;
+
+       size = pitch * mode_cmd.height;
+
+       ret = vboxfb_create_object(fbdev, &mode_cmd, &gobj);
+       if (ret) {
+               DRM_ERROR("failed to create fbcon backing object %d\n", ret);
+               return ret;
+       }
+
+       ret = vbox_framebuffer_init(dev, &fbdev->afb, &mode_cmd, gobj);
+       if (ret)
+               return ret;
+
+       bo = gem_to_vbox_bo(gobj);
+
+       ret = vbox_bo_reserve(bo, false);
+       if (ret)
+               return ret;
+
+       ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
+       if (ret) {
+               vbox_bo_unreserve(bo);
+               return ret;
+       }
+
+       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+       vbox_bo_unreserve(bo);
+       if (ret) {
+               DRM_ERROR("failed to kmap fbcon\n");
+               return ret;
+       }
+
+       info = framebuffer_alloc(0, device);
+       if (!info)
+               return -ENOMEM;
+       info->par = fbdev;
+
+       fbdev->size = size;
+
+       fb = &fbdev->afb.base;
+       fbdev->helper.fb = fb;
+       fbdev->helper.fbdev = info;
+
+       strcpy(info->fix.id, "vboxdrmfb");
+
+       /*
+        * The last flag forces a mode set on VT switches even if the kernel
+        * does not think it is needed.
+        */
+       info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT |
+                     FBINFO_MISC_ALWAYS_SETPAR;
+       info->fbops = &vboxfb_ops;
+
+       ret = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (ret)
+               return -ENOMEM;
+
+       /*
+        * This seems to be done for safety checking that the framebuffer
+        * is not registered twice by different drivers.
+        */
+       info->apertures = alloc_apertures(1);
+       if (!info->apertures)
+               return -ENOMEM;
+       info->apertures->ranges[0].base = pci_resource_start(dev->pdev, 0);
+       info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
+
+       drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
+       drm_fb_helper_fill_var(info, &fbdev->helper, sizes->fb_width,
+                              sizes->fb_height);
+
+       info->screen_base = bo->kmap.virtual;
+       info->screen_size = size;
+
+#ifdef CONFIG_FB_DEFERRED_IO
+       info->fbdefio = &vbox_defio;
+       fb_deferred_io_init(info);
+#endif
+
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+       DRM_DEBUG_KMS("allocated %dx%d\n", fb->width, fb->height);
+
+       return 0;
+}
+
+static void vbox_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+                             u16 blue, int regno)
+{
+}
+
+static void vbox_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+                             u16 *blue, int regno)
+{
+       *red = regno;
+       *green = regno;
+       *blue = regno;
+}
+
+static struct drm_fb_helper_funcs vbox_fb_helper_funcs = {
+       .gamma_set = vbox_fb_gamma_set,
+       .gamma_get = vbox_fb_gamma_get,
+       .fb_probe = vboxfb_create,
+};
+
+void vbox_fbdev_fini(struct drm_device *dev)
+{
+       struct vbox_private *vbox = dev->dev_private;
+       struct vbox_fbdev *fbdev = vbox->fbdev;
+       struct vbox_framebuffer *afb = &fbdev->afb;
+
+       drm_fb_helper_unregister_fbi(&fbdev->helper);
+
+       if (afb->obj) {
+               struct vbox_bo *bo = gem_to_vbox_bo(afb->obj);
+
+               if (!vbox_bo_reserve(bo, false)) {
+                       if (bo->kmap.virtual)
+                               ttm_bo_kunmap(&bo->kmap);
+                       /*
+                        * QXL does this, but is it really needed before
+                        * freeing?
+                        */
+                       if (bo->pin_count)
+                               vbox_bo_unpin(bo);
+                       vbox_bo_unreserve(bo);
+               }
+               drm_gem_object_unreference_unlocked(afb->obj);
+               afb->obj = NULL;
+       }
+       drm_fb_helper_fini(&fbdev->helper);
+
+       drm_framebuffer_unregister_private(&afb->base);
+       drm_framebuffer_cleanup(&afb->base);
+}
+
+int vbox_fbdev_init(struct drm_device *dev)
+{
+       struct vbox_private *vbox = dev->dev_private;
+       struct vbox_fbdev *fbdev;
+       int ret;
+
+       fbdev = devm_kzalloc(dev->dev, sizeof(*fbdev), GFP_KERNEL);
+       if (!fbdev)
+               return -ENOMEM;
+
+       vbox->fbdev = fbdev;
+       spin_lock_init(&fbdev->dirty_lock);
+
+       drm_fb_helper_prepare(dev, &fbdev->helper, &vbox_fb_helper_funcs);
+       ret = drm_fb_helper_init(dev, &fbdev->helper, vbox->num_crtcs);
+       if (ret)
+               return ret;
+
+       ret = drm_fb_helper_single_add_all_connectors(&fbdev->helper);
+       if (ret)
+               goto err_fini;
+
+       /* disable all the possible outputs/crtcs before entering KMS mode */
+       drm_helper_disable_unused_functions(dev);
+
+       ret = drm_fb_helper_initial_config(&fbdev->helper, 32);
+       if (ret)
+               goto err_fini;
+
+       return 0;
+
+err_fini:
+       drm_fb_helper_fini(&fbdev->helper);
+       return ret;
+}
+
+void vbox_fbdev_set_base(struct vbox_private *vbox, unsigned long gpu_addr)
+{
+       struct fb_info *fbdev = vbox->fbdev->helper.fbdev;
+
+       fbdev->fix.smem_start = fbdev->apertures->ranges[0].base + gpu_addr;
+       fbdev->fix.smem_len = vbox->available_vram_size - gpu_addr;
+}
diff --git a/drivers/staging/vboxvideo/vbox_hgsmi.c b/drivers/staging/vboxvideo/vbox_hgsmi.c
new file mode 100644 (file)
index 0000000..822fd31
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 Oracle Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * Authors: Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include "vbox_drv.h"
+#include "vboxvideo_vbe.h"
+#include "hgsmi_defs.h"
+
+/* One-at-a-Time Hash from http://www.burtleburtle.net/bob/hash/doobs.html */
+static u32 hgsmi_hash_process(u32 hash, const u8 *data, int size)
+{
+       while (size--) {
+               hash += *data++;
+               hash += (hash << 10);
+               hash ^= (hash >> 6);
+       }
+
+       return hash;
+}
+
+static u32 hgsmi_hash_end(u32 hash)
+{
+       hash += (hash << 3);
+       hash ^= (hash >> 11);
+       hash += (hash << 15);
+
+       return hash;
+}
+
+/* Not really a checksum but that is the naming used in all vbox code */
+static u32 hgsmi_checksum(u32 offset,
+                         const struct hgsmi_buffer_header *header,
+                         const struct hgsmi_buffer_tail *tail)
+{
+       u32 checksum;
+
+       checksum = hgsmi_hash_process(0, (u8 *)&offset, sizeof(offset));
+       checksum = hgsmi_hash_process(checksum, (u8 *)header, sizeof(*header));
+       /* 4 -> Do not checksum the checksum itself */
+       checksum = hgsmi_hash_process(checksum, (u8 *)tail, 4);
+
+       return hgsmi_hash_end(checksum);
+}
+
+void *hgsmi_buffer_alloc(struct gen_pool *guest_pool, size_t size,
+                        u8 channel, u16 channel_info)
+{
+       struct hgsmi_buffer_header *h;
+       struct hgsmi_buffer_tail *t;
+       size_t total_size;
+       dma_addr_t offset;
+
+       total_size = size + sizeof(*h) + sizeof(*t);
+       h = gen_pool_dma_alloc(guest_pool, total_size, &offset);
+       if (!h)
+               return NULL;
+
+       t = (struct hgsmi_buffer_tail *)((u8 *)h + sizeof(*h) + size);
+
+       h->flags = HGSMI_BUFFER_HEADER_F_SEQ_SINGLE;
+       h->data_size = size;
+       h->channel = channel;
+       h->channel_info = channel_info;
+       memset(&h->u.header_data, 0, sizeof(h->u.header_data));
+
+       t->reserved = 0;
+       t->checksum = hgsmi_checksum(offset, h, t);
+
+       return (u8 *)h + sizeof(*h);
+}
+
+void hgsmi_buffer_free(struct gen_pool *guest_pool, void *buf)
+{
+       struct hgsmi_buffer_header *h =
+               (struct hgsmi_buffer_header *)((u8 *)buf - sizeof(*h));
+       size_t total_size = h->data_size + sizeof(*h) +
+                                            sizeof(struct hgsmi_buffer_tail);
+
+       gen_pool_free(guest_pool, (unsigned long)h, total_size);
+}
+
+int hgsmi_buffer_submit(struct gen_pool *guest_pool, void *buf)
+{
+       phys_addr_t offset;
+
+       offset = gen_pool_virt_to_phys(guest_pool, (unsigned long)buf -
+                                      sizeof(struct hgsmi_buffer_header));
+       outl(offset, VGA_PORT_HGSMI_GUEST);
+       /* Make the compiler aware that the host has changed memory. */
+       mb();
+
+       return 0;
+}
diff --git a/drivers/staging/vboxvideo/vbox_irq.c b/drivers/staging/vboxvideo/vbox_irq.c
new file mode 100644 (file)
index 0000000..3ca8bec
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2016-2017 Oracle Corporation
+ * This file is based on qxl_irq.c
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alon Levy
+ *          Michael Thayer <michael.thayer@oracle.com,
+ *          Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <drm/drm_crtc_helper.h>
+
+#include "vbox_drv.h"
+#include "vboxvideo.h"
+
+static void vbox_clear_irq(void)
+{
+       outl((u32)~0, VGA_PORT_HGSMI_HOST);
+}
+
+static u32 vbox_get_flags(struct vbox_private *vbox)
+{
+       return readl(vbox->guest_heap + HOST_FLAGS_OFFSET);
+}
+
+void vbox_report_hotplug(struct vbox_private *vbox)
+{
+       schedule_work(&vbox->hotplug_work);
+}
+
+irqreturn_t vbox_irq_handler(int irq, void *arg)
+{
+       struct drm_device *dev = (struct drm_device *)arg;
+       struct vbox_private *vbox = (struct vbox_private *)dev->dev_private;
+       u32 host_flags = vbox_get_flags(vbox);
+
+       if (!(host_flags & HGSMIHOSTFLAGS_IRQ))
+               return IRQ_NONE;
+
+       /*
+        * Due to a bug in the initial host implementation of hot-plug irqs,
+        * the hot-plug and cursor capability flags were never cleared.
+        * Fortunately we can tell when they would have been set by checking
+        * that the VSYNC flag is not set.
+        */
+       if (host_flags &
+           (HGSMIHOSTFLAGS_HOTPLUG | HGSMIHOSTFLAGS_CURSOR_CAPABILITIES) &&
+           !(host_flags & HGSMIHOSTFLAGS_VSYNC))
+               vbox_report_hotplug(vbox);
+
+       vbox_clear_irq();
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * Check that the position hints provided by the host are suitable for GNOME
+ * shell (i.e. all screens disjoint and hints for all enabled screens) and if
+ * not replace them with default ones.  Providing valid hints improves the
+ * chances that we will get a known screen layout for pointer mapping.
+ */
+static void validate_or_set_position_hints(struct vbox_private *vbox)
+{
+       struct vbva_modehint *hintsi, *hintsj;
+       bool valid = true;
+       u16 currentx = 0;
+       int i, j;
+
+       for (i = 0; i < vbox->num_crtcs; ++i) {
+               for (j = 0; j < i; ++j) {
+                       hintsi = &vbox->last_mode_hints[i];
+                       hintsj = &vbox->last_mode_hints[j];
+
+                       if (hintsi->enabled && hintsj->enabled) {
+                               if (hintsi->dx >= 0xffff ||
+                                   hintsi->dy >= 0xffff ||
+                                   hintsj->dx >= 0xffff ||
+                                   hintsj->dy >= 0xffff ||
+                                   (hintsi->dx <
+                                       hintsj->dx + (hintsj->cx & 0x8fff) &&
+                                    hintsi->dx + (hintsi->cx & 0x8fff) >
+                                       hintsj->dx) ||
+                                   (hintsi->dy <
+                                       hintsj->dy + (hintsj->cy & 0x8fff) &&
+                                    hintsi->dy + (hintsi->cy & 0x8fff) >
+                                       hintsj->dy))
+                                       valid = false;
+                       }
+               }
+       }
+       if (!valid)
+               for (i = 0; i < vbox->num_crtcs; ++i) {
+                       if (vbox->last_mode_hints[i].enabled) {
+                               vbox->last_mode_hints[i].dx = currentx;
+                               vbox->last_mode_hints[i].dy = 0;
+                               currentx +=
+                                   vbox->last_mode_hints[i].cx & 0x8fff;
+                       }
+               }
+}
+
+/**
+ * Query the host for the most recent video mode hints.
+ */
+static void vbox_update_mode_hints(struct vbox_private *vbox)
+{
+       struct drm_device *dev = vbox->dev;
+       struct drm_connector *connector;
+       struct vbox_connector *vbox_conn;
+       struct vbva_modehint *hints;
+       u16 flags;
+       bool disconnected;
+       unsigned int crtc_id;
+       int ret;
+
+       ret = hgsmi_get_mode_hints(vbox->guest_pool, vbox->num_crtcs,
+                                  vbox->last_mode_hints);
+       if (ret) {
+               DRM_ERROR("vboxvideo: hgsmi_get_mode_hints failed: %d\n", ret);
+               return;
+       }
+
+       validate_or_set_position_hints(vbox);
+       drm_modeset_lock_all(dev);
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               vbox_conn = to_vbox_connector(connector);
+
+               hints = &vbox->last_mode_hints[vbox_conn->vbox_crtc->crtc_id];
+               if (hints->magic != VBVAMODEHINT_MAGIC)
+                       continue;
+
+               disconnected = !(hints->enabled);
+               crtc_id = vbox_conn->vbox_crtc->crtc_id;
+               vbox_conn->mode_hint.width = hints->cx & 0x8fff;
+               vbox_conn->mode_hint.height = hints->cy & 0x8fff;
+               vbox_conn->vbox_crtc->x_hint = hints->dx;
+               vbox_conn->vbox_crtc->y_hint = hints->dy;
+               vbox_conn->mode_hint.disconnected = disconnected;
+
+               if (vbox_conn->vbox_crtc->disconnected == disconnected)
+                       continue;
+
+               if (disconnected)
+                       flags = VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_DISABLED;
+               else
+                       flags = VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_BLANK;
+
+               hgsmi_process_display_info(vbox->guest_pool, crtc_id, 0, 0, 0,
+                                          hints->cx * 4, hints->cx,
+                                          hints->cy, 0, flags);
+
+               vbox_conn->vbox_crtc->disconnected = disconnected;
+       }
+       drm_modeset_unlock_all(dev);
+}
+
+static void vbox_hotplug_worker(struct work_struct *work)
+{
+       struct vbox_private *vbox = container_of(work, struct vbox_private,
+                                                hotplug_work);
+
+       vbox_update_mode_hints(vbox);
+       drm_kms_helper_hotplug_event(vbox->dev);
+}
+
+int vbox_irq_init(struct vbox_private *vbox)
+{
+       INIT_WORK(&vbox->hotplug_work, vbox_hotplug_worker);
+       vbox_update_mode_hints(vbox);
+
+       return drm_irq_install(vbox->dev, vbox->dev->pdev->irq);
+}
+
+void vbox_irq_fini(struct vbox_private *vbox)
+{
+       drm_irq_uninstall(vbox->dev);
+       flush_work(&vbox->hotplug_work);
+}
diff --git a/drivers/staging/vboxvideo/vbox_main.c b/drivers/staging/vboxvideo/vbox_main.c
new file mode 100644 (file)
index 0000000..d0c6ec7
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2013-2017 Oracle Corporation
+ * This file is based on ast_main.c
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * Authors: Dave Airlie <airlied@redhat.com>,
+ *          Michael Thayer <michael.thayer@oracle.com,
+ *          Hans de Goede <hdegoede@redhat.com>
+ */
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "vbox_drv.h"
+#include "vbox_err.h"
+#include "vboxvideo_guest.h"
+#include "vboxvideo_vbe.h"
+
+static void vbox_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+       struct vbox_framebuffer *vbox_fb = to_vbox_framebuffer(fb);
+
+       if (vbox_fb->obj)
+               drm_gem_object_unreference_unlocked(vbox_fb->obj);
+
+       drm_framebuffer_cleanup(fb);
+       kfree(fb);
+}
+
+void vbox_enable_accel(struct vbox_private *vbox)
+{
+       unsigned int i;
+       struct vbva_buffer *vbva;
+
+       if (!vbox->vbva_info || !vbox->vbva_buffers) {
+               /* Should never happen... */
+               DRM_ERROR("vboxvideo: failed to set up VBVA.\n");
+               return;
+       }
+
+       for (i = 0; i < vbox->num_crtcs; ++i) {
+               if (vbox->vbva_info[i].vbva)
+                       continue;
+
+               vbva = (void *)vbox->vbva_buffers + i * VBVA_MIN_BUFFER_SIZE;
+               if (!vbva_enable(&vbox->vbva_info[i],
+                                vbox->guest_pool, vbva, i)) {
+                       /* very old host or driver error. */
+                       DRM_ERROR("vboxvideo: vbva_enable failed\n");
+                       return;
+               }
+       }
+}
+
+void vbox_disable_accel(struct vbox_private *vbox)
+{
+       unsigned int i;
+
+       for (i = 0; i < vbox->num_crtcs; ++i)
+               vbva_disable(&vbox->vbva_info[i], vbox->guest_pool, i);
+}
+
+void vbox_report_caps(struct vbox_private *vbox)
+{
+       u32 caps = VBVACAPS_DISABLE_CURSOR_INTEGRATION |
+                  VBVACAPS_IRQ | VBVACAPS_USE_VBVA_ONLY;
+
+       if (vbox->initial_mode_queried)
+               caps |= VBVACAPS_VIDEO_MODE_HINTS;
+
+       hgsmi_send_caps_info(vbox->guest_pool, caps);
+}
+
+/**
+ * Send information about dirty rectangles to VBVA.  If necessary we enable
+ * VBVA first, as this is normally disabled after a change of master in case
+ * the new master does not send dirty rectangle information (is this even
+ * allowed?)
+ */
+void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb,
+                                      struct drm_clip_rect *rects,
+                                      unsigned int num_rects)
+{
+       struct vbox_private *vbox = fb->dev->dev_private;
+       struct drm_crtc *crtc;
+       unsigned int i;
+
+       mutex_lock(&vbox->hw_mutex);
+       list_for_each_entry(crtc, &fb->dev->mode_config.crtc_list, head) {
+               if (CRTC_FB(crtc) != fb)
+                       continue;
+
+               vbox_enable_accel(vbox);
+
+               for (i = 0; i < num_rects; ++i) {
+                       struct vbva_cmd_hdr cmd_hdr;
+                       unsigned int crtc_id = to_vbox_crtc(crtc)->crtc_id;
+
+                       if ((rects[i].x1 > crtc->x + crtc->hwmode.hdisplay) ||
+                           (rects[i].y1 > crtc->y + crtc->hwmode.vdisplay) ||
+                           (rects[i].x2 < crtc->x) ||
+                           (rects[i].y2 < crtc->y))
+                               continue;
+
+                       cmd_hdr.x = (s16)rects[i].x1;
+                       cmd_hdr.y = (s16)rects[i].y1;
+                       cmd_hdr.w = (u16)rects[i].x2 - rects[i].x1;
+                       cmd_hdr.h = (u16)rects[i].y2 - rects[i].y1;
+
+                       if (!vbva_buffer_begin_update(&vbox->vbva_info[crtc_id],
+                                                     vbox->guest_pool))
+                               continue;
+
+                       vbva_write(&vbox->vbva_info[crtc_id], vbox->guest_pool,
+                                  &cmd_hdr, sizeof(cmd_hdr));
+                       vbva_buffer_end_update(&vbox->vbva_info[crtc_id]);
+               }
+       }
+       mutex_unlock(&vbox->hw_mutex);
+}
+
+static int vbox_user_framebuffer_dirty(struct drm_framebuffer *fb,
+                                      struct drm_file *file_priv,
+                                      unsigned int flags, unsigned int color,
+                                      struct drm_clip_rect *rects,
+                                      unsigned int num_rects)
+{
+       vbox_framebuffer_dirty_rectangles(fb, rects, num_rects);
+
+       return 0;
+}
+
+static const struct drm_framebuffer_funcs vbox_fb_funcs = {
+       .destroy = vbox_user_framebuffer_destroy,
+       .dirty = vbox_user_framebuffer_dirty,
+};
+
+int vbox_framebuffer_init(struct drm_device *dev,
+                         struct vbox_framebuffer *vbox_fb,
+                         const struct DRM_MODE_FB_CMD *mode_cmd,
+                         struct drm_gem_object *obj)
+{
+       int ret;
+
+       drm_helper_mode_fill_fb_struct(dev, &vbox_fb->base, mode_cmd);
+       vbox_fb->obj = obj;
+       ret = drm_framebuffer_init(dev, &vbox_fb->base, &vbox_fb_funcs);
+       if (ret) {
+               DRM_ERROR("framebuffer init failed %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct drm_framebuffer *vbox_user_framebuffer_create(
+               struct drm_device *dev,
+               struct drm_file *filp,
+               const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       struct drm_gem_object *obj;
+       struct vbox_framebuffer *vbox_fb;
+       int ret = -ENOMEM;
+
+       obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
+       if (!obj)
+               return ERR_PTR(-ENOENT);
+
+       vbox_fb = kzalloc(sizeof(*vbox_fb), GFP_KERNEL);
+       if (!vbox_fb)
+               goto err_unref_obj;
+
+       ret = vbox_framebuffer_init(dev, vbox_fb, mode_cmd, obj);
+       if (ret)
+               goto err_free_vbox_fb;
+
+       return &vbox_fb->base;
+
+err_free_vbox_fb:
+       kfree(vbox_fb);
+err_unref_obj:
+       drm_gem_object_unreference_unlocked(obj);
+       return ERR_PTR(ret);
+}
+
+static const struct drm_mode_config_funcs vbox_mode_funcs = {
+       .fb_create = vbox_user_framebuffer_create,
+};
+
+static int vbox_accel_init(struct vbox_private *vbox)
+{
+       unsigned int i;
+
+       vbox->vbva_info = devm_kcalloc(vbox->dev->dev, vbox->num_crtcs,
+                                      sizeof(*vbox->vbva_info), GFP_KERNEL);
+       if (!vbox->vbva_info)
+               return -ENOMEM;
+
+       /* Take a command buffer for each screen from the end of usable VRAM. */
+       vbox->available_vram_size -= vbox->num_crtcs * VBVA_MIN_BUFFER_SIZE;
+
+       vbox->vbva_buffers = pci_iomap_range(vbox->dev->pdev, 0,
+                                            vbox->available_vram_size,
+                                            vbox->num_crtcs *
+                                            VBVA_MIN_BUFFER_SIZE);
+       if (!vbox->vbva_buffers)
+               return -ENOMEM;
+
+       for (i = 0; i < vbox->num_crtcs; ++i)
+               vbva_setup_buffer_context(&vbox->vbva_info[i],
+                                         vbox->available_vram_size +
+                                         i * VBVA_MIN_BUFFER_SIZE,
+                                         VBVA_MIN_BUFFER_SIZE);
+
+       return 0;
+}
+
+static void vbox_accel_fini(struct vbox_private *vbox)
+{
+       vbox_disable_accel(vbox);
+       pci_iounmap(vbox->dev->pdev, vbox->vbva_buffers);
+}
+
+/** Do we support the 4.3 plus mode hint reporting interface? */
+static bool have_hgsmi_mode_hints(struct vbox_private *vbox)
+{
+       u32 have_hints, have_cursor;
+       int ret;
+
+       ret = hgsmi_query_conf(vbox->guest_pool,
+                              VBOX_VBVA_CONF32_MODE_HINT_REPORTING,
+                              &have_hints);
+       if (ret)
+               return false;
+
+       ret = hgsmi_query_conf(vbox->guest_pool,
+                              VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING,
+                              &have_cursor);
+       if (ret)
+               return false;
+
+       return have_hints == VINF_SUCCESS && have_cursor == VINF_SUCCESS;
+}
+
+static bool vbox_check_supported(u16 id)
+{
+       u16 dispi_id;
+
+       vbox_write_ioport(VBE_DISPI_INDEX_ID, id);
+       dispi_id = inw(VBE_DISPI_IOPORT_DATA);
+
+       return dispi_id == id;
+}
+
+/**
+ * Set up our heaps and data exchange buffers in VRAM before handing the rest
+ * to the memory manager.
+ */
+static int vbox_hw_init(struct vbox_private *vbox)
+{
+       int ret = -ENOMEM;
+
+       vbox->full_vram_size = inl(VBE_DISPI_IOPORT_DATA);
+       vbox->any_pitch = vbox_check_supported(VBE_DISPI_ID_ANYX);
+
+       DRM_INFO("VRAM %08x\n", vbox->full_vram_size);
+
+       /* Map guest-heap at end of vram */
+       vbox->guest_heap =
+           pci_iomap_range(vbox->dev->pdev, 0, GUEST_HEAP_OFFSET(vbox),
+                           GUEST_HEAP_SIZE);
+       if (!vbox->guest_heap)
+               return -ENOMEM;
+
+       /* Create guest-heap mem-pool use 2^4 = 16 byte chunks */
+       vbox->guest_pool = gen_pool_create(4, -1);
+       if (!vbox->guest_pool)
+               goto err_unmap_guest_heap;
+
+       ret = gen_pool_add_virt(vbox->guest_pool,
+                               (unsigned long)vbox->guest_heap,
+                               GUEST_HEAP_OFFSET(vbox),
+                               GUEST_HEAP_USABLE_SIZE, -1);
+       if (ret)
+               goto err_destroy_guest_pool;
+
+       ret = hgsmi_test_query_conf(vbox->guest_pool);
+       if (ret) {
+               DRM_ERROR("vboxvideo: hgsmi_test_query_conf failed\n");
+               goto err_destroy_guest_pool;
+       }
+
+       /* Reduce available VRAM size to reflect the guest heap. */
+       vbox->available_vram_size = GUEST_HEAP_OFFSET(vbox);
+       /* Linux drm represents monitors as a 32-bit array. */
+       hgsmi_query_conf(vbox->guest_pool, VBOX_VBVA_CONF32_MONITOR_COUNT,
+                        &vbox->num_crtcs);
+       vbox->num_crtcs = clamp_t(u32, vbox->num_crtcs, 1, VBOX_MAX_SCREENS);
+
+       if (!have_hgsmi_mode_hints(vbox)) {
+               ret = -ENOTSUPP;
+               goto err_destroy_guest_pool;
+       }
+
+       vbox->last_mode_hints = devm_kcalloc(vbox->dev->dev, vbox->num_crtcs,
+                                            sizeof(struct vbva_modehint),
+                                            GFP_KERNEL);
+       if (!vbox->last_mode_hints) {
+               ret = -ENOMEM;
+               goto err_destroy_guest_pool;
+       }
+
+       ret = vbox_accel_init(vbox);
+       if (ret)
+               goto err_destroy_guest_pool;
+
+       return 0;
+
+err_destroy_guest_pool:
+       gen_pool_destroy(vbox->guest_pool);
+err_unmap_guest_heap:
+       pci_iounmap(vbox->dev->pdev, vbox->guest_heap);
+       return ret;
+}
+
+static void vbox_hw_fini(struct vbox_private *vbox)
+{
+       vbox_accel_fini(vbox);
+       gen_pool_destroy(vbox->guest_pool);
+       pci_iounmap(vbox->dev->pdev, vbox->guest_heap);
+}
+
+int vbox_driver_load(struct drm_device *dev, unsigned long flags)
+{
+       struct vbox_private *vbox;
+       int ret = 0;
+
+       if (!vbox_check_supported(VBE_DISPI_ID_HGSMI))
+               return -ENODEV;
+
+       vbox = devm_kzalloc(dev->dev, sizeof(*vbox), GFP_KERNEL);
+       if (!vbox)
+               return -ENOMEM;
+
+       dev->dev_private = vbox;
+       vbox->dev = dev;
+
+       mutex_init(&vbox->hw_mutex);
+
+       ret = vbox_hw_init(vbox);
+       if (ret)
+               return ret;
+
+       ret = vbox_mm_init(vbox);
+       if (ret)
+               goto err_hw_fini;
+
+       drm_mode_config_init(dev);
+
+       dev->mode_config.funcs = (void *)&vbox_mode_funcs;
+       dev->mode_config.min_width = 64;
+       dev->mode_config.min_height = 64;
+       dev->mode_config.preferred_depth = 24;
+       dev->mode_config.max_width = VBE_DISPI_MAX_XRES;
+       dev->mode_config.max_height = VBE_DISPI_MAX_YRES;
+
+       ret = vbox_mode_init(dev);
+       if (ret)
+               goto err_drm_mode_cleanup;
+
+       ret = vbox_irq_init(vbox);
+       if (ret)
+               goto err_mode_fini;
+
+       ret = vbox_fbdev_init(dev);
+       if (ret)
+               goto err_irq_fini;
+
+       return 0;
+
+err_irq_fini:
+       vbox_irq_fini(vbox);
+err_mode_fini:
+       vbox_mode_fini(dev);
+err_drm_mode_cleanup:
+       drm_mode_config_cleanup(dev);
+       vbox_mm_fini(vbox);
+err_hw_fini:
+       vbox_hw_fini(vbox);
+       return ret;
+}
+
+void vbox_driver_unload(struct drm_device *dev)
+{
+       struct vbox_private *vbox = dev->dev_private;
+
+       vbox_fbdev_fini(dev);
+       vbox_irq_fini(vbox);
+       vbox_mode_fini(dev);
+       drm_mode_config_cleanup(dev);
+       vbox_mm_fini(vbox);
+       vbox_hw_fini(vbox);
+}
+
+/**
+ * @note this is described in the DRM framework documentation.  AST does not
+ * have it, but we get an oops on driver unload if it is not present.
+ */
+void vbox_driver_lastclose(struct drm_device *dev)
+{
+       struct vbox_private *vbox = dev->dev_private;
+
+       if (vbox->fbdev)
+               drm_fb_helper_restore_fbdev_mode_unlocked(&vbox->fbdev->helper);
+}
+
+int vbox_gem_create(struct drm_device *dev,
+                   u32 size, bool iskernel, struct drm_gem_object **obj)
+{
+       struct vbox_bo *vboxbo;
+       int ret;
+
+       *obj = NULL;
+
+       size = roundup(size, PAGE_SIZE);
+       if (size == 0)
+               return -EINVAL;
+
+       ret = vbox_bo_create(dev, size, 0, 0, &vboxbo);
+       if (ret) {
+               if (ret != -ERESTARTSYS)
+                       DRM_ERROR("failed to allocate GEM object\n");
+               return ret;
+       }
+
+       *obj = &vboxbo->gem;
+
+       return 0;
+}
+
+int vbox_dumb_create(struct drm_file *file,
+                    struct drm_device *dev, struct drm_mode_create_dumb *args)
+{
+       int ret;
+       struct drm_gem_object *gobj;
+       u32 handle;
+
+       args->pitch = args->width * ((args->bpp + 7) / 8);
+       args->size = args->pitch * args->height;
+
+       ret = vbox_gem_create(dev, args->size, false, &gobj);
+       if (ret)
+               return ret;
+
+       ret = drm_gem_handle_create(file, gobj, &handle);
+       drm_gem_object_unreference_unlocked(gobj);
+       if (ret)
+               return ret;
+
+       args->handle = handle;
+
+       return 0;
+}
+
+static void vbox_bo_unref(struct vbox_bo **bo)
+{
+       struct ttm_buffer_object *tbo;
+
+       if ((*bo) == NULL)
+               return;
+
+       tbo = &((*bo)->bo);
+       ttm_bo_unref(&tbo);
+       if (!tbo)
+               *bo = NULL;
+}
+
+void vbox_gem_free_object(struct drm_gem_object *obj)
+{
+       struct vbox_bo *vbox_bo = gem_to_vbox_bo(obj);
+
+       vbox_bo_unref(&vbox_bo);
+}
+
+static inline u64 vbox_bo_mmap_offset(struct vbox_bo *bo)
+{
+       return drm_vma_node_offset_addr(&bo->bo.vma_node);
+}
+
+int
+vbox_dumb_mmap_offset(struct drm_file *file,
+                     struct drm_device *dev,
+                     u32 handle, u64 *offset)
+{
+       struct drm_gem_object *obj;
+       int ret;
+       struct vbox_bo *bo;
+
+       mutex_lock(&dev->struct_mutex);
+       obj = drm_gem_object_lookup(file, handle);
+       if (!obj) {
+               ret = -ENOENT;
+               goto out_unlock;
+       }
+
+       bo = gem_to_vbox_bo(obj);
+       *offset = vbox_bo_mmap_offset(bo);
+
+       drm_gem_object_unreference(obj);
+       ret = 0;
+
+out_unlock:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
diff --git a/drivers/staging/vboxvideo/vbox_mode.c b/drivers/staging/vboxvideo/vbox_mode.c
new file mode 100644 (file)
index 0000000..f2b85f3
--- /dev/null
@@ -0,0 +1,877 @@
+/*
+ * Copyright (C) 2013-2017 Oracle Corporation
+ * This file is based on ast_mode.c
+ * Copyright 2012 Red Hat Inc.
+ * Parts based on xf86-video-ast
+ * Copyright (c) 2005 ASPEED Technology Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ *          Michael Thayer <michael.thayer@oracle.com,
+ *          Hans de Goede <hdegoede@redhat.com>
+ */
+#include <linux/export.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#include "vbox_drv.h"
+#include "vboxvideo.h"
+#include "hgsmi_channels.h"
+
+static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
+                           u32 handle, u32 width, u32 height,
+                           s32 hot_x, s32 hot_y);
+static int vbox_cursor_move(struct drm_crtc *crtc, int x, int y);
+
+/**
+ * Set a graphics mode.  Poke any required values into registers, do an HGSMI
+ * mode set and tell the host we support advanced graphics functions.
+ */
+static void vbox_do_modeset(struct drm_crtc *crtc,
+                           const struct drm_display_mode *mode)
+{
+       struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
+       struct vbox_private *vbox;
+       int width, height, bpp, pitch;
+       unsigned int crtc_id;
+       u16 flags;
+       s32 x_offset, y_offset;
+
+       vbox = crtc->dev->dev_private;
+       width = mode->hdisplay ? mode->hdisplay : 640;
+       height = mode->vdisplay ? mode->vdisplay : 480;
+       crtc_id = vbox_crtc->crtc_id;
+       bpp = crtc->enabled ? CRTC_FB(crtc)->format->cpp[0] * 8 : 32;
+       pitch = crtc->enabled ? CRTC_FB(crtc)->pitches[0] : width * bpp / 8;
+       x_offset = vbox->single_framebuffer ? crtc->x : vbox_crtc->x_hint;
+       y_offset = vbox->single_framebuffer ? crtc->y : vbox_crtc->y_hint;
+
+       /*
+        * This is the old way of setting graphics modes.  It assumed one screen
+        * and a frame-buffer at the start of video RAM.  On older versions of
+        * VirtualBox, certain parts of the code still assume that the first
+        * screen is programmed this way, so try to fake it.
+        */
+       if (vbox_crtc->crtc_id == 0 && crtc->enabled &&
+           vbox_crtc->fb_offset / pitch < 0xffff - crtc->y &&
+           vbox_crtc->fb_offset % (bpp / 8) == 0) {
+               vbox_write_ioport(VBE_DISPI_INDEX_XRES, width);
+               vbox_write_ioport(VBE_DISPI_INDEX_YRES, height);
+               vbox_write_ioport(VBE_DISPI_INDEX_VIRT_WIDTH, pitch * 8 / bpp);
+               vbox_write_ioport(VBE_DISPI_INDEX_BPP,
+                                 CRTC_FB(crtc)->format->cpp[0] * 8);
+               vbox_write_ioport(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED);
+               vbox_write_ioport(
+                       VBE_DISPI_INDEX_X_OFFSET,
+                       vbox_crtc->fb_offset % pitch / bpp * 8 + crtc->x);
+               vbox_write_ioport(VBE_DISPI_INDEX_Y_OFFSET,
+                                 vbox_crtc->fb_offset / pitch + crtc->y);
+       }
+
+       flags = VBVA_SCREEN_F_ACTIVE;
+       flags |= (crtc->enabled && !vbox_crtc->blanked) ?
+                0 : VBVA_SCREEN_F_BLANK;
+       flags |= vbox_crtc->disconnected ? VBVA_SCREEN_F_DISABLED : 0;
+       hgsmi_process_display_info(vbox->guest_pool, vbox_crtc->crtc_id,
+                                  x_offset, y_offset,
+                                  crtc->x * bpp / 8 + crtc->y * pitch,
+                                  pitch, width, height,
+                                  vbox_crtc->blanked ? 0 : bpp, flags);
+}
+
+static int vbox_set_view(struct drm_crtc *crtc)
+{
+       struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
+       struct vbox_private *vbox = crtc->dev->dev_private;
+       struct vbva_infoview *p;
+
+       /*
+        * Tell the host about the view.  This design originally targeted the
+        * Windows XP driver architecture and assumed that each screen would
+        * have a dedicated frame buffer with the command buffer following it,
+        * the whole being a "view".  The host works out which screen a command
+        * buffer belongs to by checking whether it is in the first view, then
+        * whether it is in the second and so on.  The first match wins.  We
+        * cheat around this by making the first view be the managed memory
+        * plus the first command buffer, the second the same plus the second
+        * buffer and so on.
+        */
+       p = hgsmi_buffer_alloc(vbox->guest_pool, sizeof(*p),
+                              HGSMI_CH_VBVA, VBVA_INFO_VIEW);
+       if (!p)
+               return -ENOMEM;
+
+       p->view_index = vbox_crtc->crtc_id;
+       p->view_offset = vbox_crtc->fb_offset;
+       p->view_size = vbox->available_vram_size - vbox_crtc->fb_offset +
+                      vbox_crtc->crtc_id * VBVA_MIN_BUFFER_SIZE;
+       p->max_screen_size = vbox->available_vram_size - vbox_crtc->fb_offset;
+
+       hgsmi_buffer_submit(vbox->guest_pool, p);
+       hgsmi_buffer_free(vbox->guest_pool, p);
+
+       return 0;
+}
+
+static void vbox_crtc_load_lut(struct drm_crtc *crtc)
+{
+}
+
+static void vbox_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
+       struct vbox_private *vbox = crtc->dev->dev_private;
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               vbox_crtc->blanked = false;
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               vbox_crtc->blanked = true;
+               break;
+       }
+
+       mutex_lock(&vbox->hw_mutex);
+       vbox_do_modeset(crtc, &crtc->hwmode);
+       mutex_unlock(&vbox->hw_mutex);
+}
+
+static bool vbox_crtc_mode_fixup(struct drm_crtc *crtc,
+                                const struct drm_display_mode *mode,
+                                struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+/*
+ * Try to map the layout of virtual screens to the range of the input device.
+ * Return true if we need to re-set the crtc modes due to screen offset
+ * changes.
+ */
+static bool vbox_set_up_input_mapping(struct vbox_private *vbox)
+{
+       struct drm_crtc *crtci;
+       struct drm_connector *connectori;
+       struct drm_framebuffer *fb1 = NULL;
+       bool single_framebuffer = true;
+       bool old_single_framebuffer = vbox->single_framebuffer;
+       u16 width = 0, height = 0;
+
+       /*
+        * Are we using an X.Org-style single large frame-buffer for all crtcs?
+        * If so then screen layout can be deduced from the crtc offsets.
+        * Same fall-back if this is the fbdev frame-buffer.
+        */
+       list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list, head) {
+               if (!fb1) {
+                       fb1 = CRTC_FB(crtci);
+                       if (to_vbox_framebuffer(fb1) == &vbox->fbdev->afb)
+                               break;
+               } else if (CRTC_FB(crtci) && fb1 != CRTC_FB(crtci)) {
+                       single_framebuffer = false;
+               }
+       }
+       if (single_framebuffer) {
+               list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list,
+                                   head) {
+                       if (to_vbox_crtc(crtci)->crtc_id != 0)
+                               continue;
+
+                       vbox->single_framebuffer = true;
+                       vbox->input_mapping_width = CRTC_FB(crtci)->width;
+                       vbox->input_mapping_height = CRTC_FB(crtci)->height;
+                       return old_single_framebuffer !=
+                              vbox->single_framebuffer;
+               }
+       }
+       /* Otherwise calculate the total span of all screens. */
+       list_for_each_entry(connectori, &vbox->dev->mode_config.connector_list,
+                           head) {
+               struct vbox_connector *vbox_connector =
+                   to_vbox_connector(connectori);
+               struct vbox_crtc *vbox_crtc = vbox_connector->vbox_crtc;
+
+               width = max_t(u16, width, vbox_crtc->x_hint +
+                                         vbox_connector->mode_hint.width);
+               height = max_t(u16, height, vbox_crtc->y_hint +
+                                           vbox_connector->mode_hint.height);
+       }
+
+       vbox->single_framebuffer = false;
+       vbox->input_mapping_width = width;
+       vbox->input_mapping_height = height;
+
+       return old_single_framebuffer != vbox->single_framebuffer;
+}
+
+static int vbox_crtc_do_set_base(struct drm_crtc *crtc,
+                                struct drm_framebuffer *old_fb, int x, int y)
+{
+       struct vbox_private *vbox = crtc->dev->dev_private;
+       struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
+       struct drm_gem_object *obj;
+       struct vbox_framebuffer *vbox_fb;
+       struct vbox_bo *bo;
+       int ret;
+       u64 gpu_addr;
+
+       /* Unpin the previous fb. */
+       if (old_fb) {
+               vbox_fb = to_vbox_framebuffer(old_fb);
+               obj = vbox_fb->obj;
+               bo = gem_to_vbox_bo(obj);
+               ret = vbox_bo_reserve(bo, false);
+               if (ret)
+                       return ret;
+
+               vbox_bo_unpin(bo);
+               vbox_bo_unreserve(bo);
+       }
+
+       vbox_fb = to_vbox_framebuffer(CRTC_FB(crtc));
+       obj = vbox_fb->obj;
+       bo = gem_to_vbox_bo(obj);
+
+       ret = vbox_bo_reserve(bo, false);
+       if (ret)
+               return ret;
+
+       ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+       if (ret) {
+               vbox_bo_unreserve(bo);
+               return ret;
+       }
+
+       if (&vbox->fbdev->afb == vbox_fb)
+               vbox_fbdev_set_base(vbox, gpu_addr);
+       vbox_bo_unreserve(bo);
+
+       /* vbox_set_start_address_crt1(crtc, (u32)gpu_addr); */
+       vbox_crtc->fb_offset = gpu_addr;
+       if (vbox_set_up_input_mapping(vbox)) {
+               struct drm_crtc *crtci;
+
+               list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list,
+                                   head) {
+                       vbox_set_view(crtc);
+                       vbox_do_modeset(crtci, &crtci->mode);
+               }
+       }
+
+       return 0;
+}
+
+static int vbox_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+                                  struct drm_framebuffer *old_fb)
+{
+       return vbox_crtc_do_set_base(crtc, old_fb, x, y);
+}
+
+static int vbox_crtc_mode_set(struct drm_crtc *crtc,
+                             struct drm_display_mode *mode,
+                             struct drm_display_mode *adjusted_mode,
+                             int x, int y, struct drm_framebuffer *old_fb)
+{
+       struct vbox_private *vbox = crtc->dev->dev_private;
+       int ret;
+
+       vbox_crtc_mode_set_base(crtc, x, y, old_fb);
+
+       mutex_lock(&vbox->hw_mutex);
+       ret = vbox_set_view(crtc);
+       if (!ret)
+               vbox_do_modeset(crtc, mode);
+       hgsmi_update_input_mapping(vbox->guest_pool, 0, 0,
+                                  vbox->input_mapping_width,
+                                  vbox->input_mapping_height);
+       mutex_unlock(&vbox->hw_mutex);
+
+       return ret;
+}
+
+static void vbox_crtc_disable(struct drm_crtc *crtc)
+{
+}
+
+static void vbox_crtc_prepare(struct drm_crtc *crtc)
+{
+}
+
+static void vbox_crtc_commit(struct drm_crtc *crtc)
+{
+}
+
+static const struct drm_crtc_helper_funcs vbox_crtc_helper_funcs = {
+       .dpms = vbox_crtc_dpms,
+       .mode_fixup = vbox_crtc_mode_fixup,
+       .mode_set = vbox_crtc_mode_set,
+       /* .mode_set_base = vbox_crtc_mode_set_base, */
+       .disable = vbox_crtc_disable,
+       .load_lut = vbox_crtc_load_lut,
+       .prepare = vbox_crtc_prepare,
+       .commit = vbox_crtc_commit,
+};
+
+static void vbox_crtc_reset(struct drm_crtc *crtc)
+{
+}
+
+static void vbox_crtc_destroy(struct drm_crtc *crtc)
+{
+       drm_crtc_cleanup(crtc);
+       kfree(crtc);
+}
+
+static const struct drm_crtc_funcs vbox_crtc_funcs = {
+       .cursor_move = vbox_cursor_move,
+       .cursor_set2 = vbox_cursor_set2,
+       .reset = vbox_crtc_reset,
+       .set_config = drm_crtc_helper_set_config,
+       /* .gamma_set = vbox_crtc_gamma_set, */
+       .destroy = vbox_crtc_destroy,
+};
+
+static struct vbox_crtc *vbox_crtc_init(struct drm_device *dev, unsigned int i)
+{
+       struct vbox_crtc *vbox_crtc;
+
+       vbox_crtc = kzalloc(sizeof(*vbox_crtc), GFP_KERNEL);
+       if (!vbox_crtc)
+               return NULL;
+
+       vbox_crtc->crtc_id = i;
+
+       drm_crtc_init(dev, &vbox_crtc->base, &vbox_crtc_funcs);
+       drm_mode_crtc_set_gamma_size(&vbox_crtc->base, 256);
+       drm_crtc_helper_add(&vbox_crtc->base, &vbox_crtc_helper_funcs);
+
+       return vbox_crtc;
+}
+
+static void vbox_encoder_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+       kfree(encoder);
+}
+
+static struct drm_encoder *vbox_best_single_encoder(struct drm_connector
+                                                   *connector)
+{
+       int enc_id = connector->encoder_ids[0];
+
+       /* pick the encoder ids */
+       if (enc_id)
+               return drm_encoder_find(connector->dev, enc_id);
+
+       return NULL;
+}
+
+static const struct drm_encoder_funcs vbox_enc_funcs = {
+       .destroy = vbox_encoder_destroy,
+};
+
+static void vbox_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static bool vbox_mode_fixup(struct drm_encoder *encoder,
+                           const struct drm_display_mode *mode,
+                           struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void vbox_encoder_mode_set(struct drm_encoder *encoder,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void vbox_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void vbox_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static const struct drm_encoder_helper_funcs vbox_enc_helper_funcs = {
+       .dpms = vbox_encoder_dpms,
+       .mode_fixup = vbox_mode_fixup,
+       .prepare = vbox_encoder_prepare,
+       .commit = vbox_encoder_commit,
+       .mode_set = vbox_encoder_mode_set,
+};
+
+static struct drm_encoder *vbox_encoder_init(struct drm_device *dev,
+                                            unsigned int i)
+{
+       struct vbox_encoder *vbox_encoder;
+
+       vbox_encoder = kzalloc(sizeof(*vbox_encoder), GFP_KERNEL);
+       if (!vbox_encoder)
+               return NULL;
+
+       drm_encoder_init(dev, &vbox_encoder->base, &vbox_enc_funcs,
+                        DRM_MODE_ENCODER_DAC, NULL);
+       drm_encoder_helper_add(&vbox_encoder->base, &vbox_enc_helper_funcs);
+
+       vbox_encoder->base.possible_crtcs = 1 << i;
+       return &vbox_encoder->base;
+}
+
+/**
+ * Generate EDID data with a mode-unique serial number for the virtual
+ *  monitor to try to persuade Unity that different modes correspond to
+ *  different monitors and it should not try to force the same resolution on
+ *  them.
+ */
+static void vbox_set_edid(struct drm_connector *connector, int width,
+                         int height)
+{
+       enum { EDID_SIZE = 128 };
+       unsigned char edid[EDID_SIZE] = {
+               0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, /* header */
+               0x58, 0x58,     /* manufacturer (VBX) */
+               0x00, 0x00,     /* product code */
+               0x00, 0x00, 0x00, 0x00, /* serial number goes here */
+               0x01,           /* week of manufacture */
+               0x00,           /* year of manufacture */
+               0x01, 0x03,     /* EDID version */
+               0x80,           /* capabilities - digital */
+               0x00,           /* horiz. res in cm, zero for projectors */
+               0x00,           /* vert. res in cm */
+               0x78,           /* display gamma (120 == 2.2). */
+               0xEE,           /* features (standby, suspend, off, RGB, std */
+                               /* colour space, preferred timing mode) */
+               0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54,
+               /* chromaticity for standard colour space. */
+               0x00, 0x00, 0x00,       /* no default timings */
+               0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+                   0x01, 0x01,
+               0x01, 0x01, 0x01, 0x01, /* no standard timings */
+               0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x02, 0x02,
+                   0x02, 0x02,
+               /* descriptor block 1 goes below */
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               /* descriptor block 2, monitor ranges */
+               0x00, 0x00, 0x00, 0xFD, 0x00,
+               0x00, 0xC8, 0x00, 0xC8, 0x64, 0x00, 0x0A, 0x20, 0x20, 0x20,
+                   0x20, 0x20,
+               /* 0-200Hz vertical, 0-200KHz horizontal, 1000MHz pixel clock */
+               0x20,
+               /* descriptor block 3, monitor name */
+               0x00, 0x00, 0x00, 0xFC, 0x00,
+               'V', 'B', 'O', 'X', ' ', 'm', 'o', 'n', 'i', 't', 'o', 'r',
+               '\n',
+               /* descriptor block 4: dummy data */
+               0x00, 0x00, 0x00, 0x10, 0x00,
+               0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
+               0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+               0x20,
+               0x00,           /* number of extensions */
+               0x00            /* checksum goes here */
+       };
+       int clock = (width + 6) * (height + 6) * 60 / 10000;
+       unsigned int i, sum = 0;
+
+       edid[12] = width & 0xff;
+       edid[13] = width >> 8;
+       edid[14] = height & 0xff;
+       edid[15] = height >> 8;
+       edid[54] = clock & 0xff;
+       edid[55] = clock >> 8;
+       edid[56] = width & 0xff;
+       edid[58] = (width >> 4) & 0xf0;
+       edid[59] = height & 0xff;
+       edid[61] = (height >> 4) & 0xf0;
+       for (i = 0; i < EDID_SIZE - 1; ++i)
+               sum += edid[i];
+       edid[EDID_SIZE - 1] = (0x100 - (sum & 0xFF)) & 0xFF;
+       drm_mode_connector_update_edid_property(connector, (struct edid *)edid);
+}
+
+static int vbox_get_modes(struct drm_connector *connector)
+{
+       struct vbox_connector *vbox_connector = NULL;
+       struct drm_display_mode *mode = NULL;
+       struct vbox_private *vbox = NULL;
+       unsigned int num_modes = 0;
+       int preferred_width, preferred_height;
+
+       vbox_connector = to_vbox_connector(connector);
+       vbox = connector->dev->dev_private;
+       /*
+        * Heuristic: we do not want to tell the host that we support dynamic
+        * resizing unless we feel confident that the user space client using
+        * the video driver can handle hot-plug events.  So the first time modes
+        * are queried after a "master" switch we tell the host that we do not,
+        * and immediately after we send the client a hot-plug notification as
+        * a test to see if they will respond and query again.
+        * That is also the reason why capabilities are reported to the host at
+        * this place in the code rather than elsewhere.
+        * We need to report the flags location before reporting the IRQ
+        * capability.
+        */
+       hgsmi_report_flags_location(vbox->guest_pool, GUEST_HEAP_OFFSET(vbox) +
+                                   HOST_FLAGS_OFFSET);
+       if (vbox_connector->vbox_crtc->crtc_id == 0)
+               vbox_report_caps(vbox);
+       if (!vbox->initial_mode_queried) {
+               if (vbox_connector->vbox_crtc->crtc_id == 0) {
+                       vbox->initial_mode_queried = true;
+                       vbox_report_hotplug(vbox);
+               }
+               return drm_add_modes_noedid(connector, 800, 600);
+       }
+       num_modes = drm_add_modes_noedid(connector, 2560, 1600);
+       preferred_width = vbox_connector->mode_hint.width ?
+                         vbox_connector->mode_hint.width : 1024;
+       preferred_height = vbox_connector->mode_hint.height ?
+                          vbox_connector->mode_hint.height : 768;
+       mode = drm_cvt_mode(connector->dev, preferred_width, preferred_height,
+                           60, false, false, false);
+       if (mode) {
+               mode->type |= DRM_MODE_TYPE_PREFERRED;
+               drm_mode_probed_add(connector, mode);
+               ++num_modes;
+       }
+       vbox_set_edid(connector, preferred_width, preferred_height);
+       drm_object_property_set_value(
+               &connector->base, vbox->dev->mode_config.suggested_x_property,
+               vbox_connector->vbox_crtc->x_hint);
+       drm_object_property_set_value(
+               &connector->base, vbox->dev->mode_config.suggested_y_property,
+               vbox_connector->vbox_crtc->y_hint);
+
+       return num_modes;
+}
+
+static int vbox_mode_valid(struct drm_connector *connector,
+                          struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static void vbox_connector_destroy(struct drm_connector *connector)
+{
+       struct vbox_connector *vbox_connector;
+
+       vbox_connector = to_vbox_connector(connector);
+       drm_connector_unregister(connector);
+       drm_connector_cleanup(connector);
+       kfree(connector);
+}
+
+static enum drm_connector_status
+vbox_connector_detect(struct drm_connector *connector, bool force)
+{
+       struct vbox_connector *vbox_connector;
+
+       vbox_connector = to_vbox_connector(connector);
+
+       return vbox_connector->mode_hint.disconnected ?
+           connector_status_disconnected : connector_status_connected;
+}
+
+static int vbox_fill_modes(struct drm_connector *connector, u32 max_x,
+                          u32 max_y)
+{
+       struct vbox_connector *vbox_connector;
+       struct drm_device *dev;
+       struct drm_display_mode *mode, *iterator;
+
+       vbox_connector = to_vbox_connector(connector);
+       dev = vbox_connector->base.dev;
+       list_for_each_entry_safe(mode, iterator, &connector->modes, head) {
+               list_del(&mode->head);
+               drm_mode_destroy(dev, mode);
+       }
+
+       return drm_helper_probe_single_connector_modes(connector, max_x, max_y);
+}
+
+static const struct drm_connector_helper_funcs vbox_connector_helper_funcs = {
+       .mode_valid = vbox_mode_valid,
+       .get_modes = vbox_get_modes,
+       .best_encoder = vbox_best_single_encoder,
+};
+
+static const struct drm_connector_funcs vbox_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = vbox_connector_detect,
+       .fill_modes = vbox_fill_modes,
+       .destroy = vbox_connector_destroy,
+};
+
+static int vbox_connector_init(struct drm_device *dev,
+                              struct vbox_crtc *vbox_crtc,
+                              struct drm_encoder *encoder)
+{
+       struct vbox_connector *vbox_connector;
+       struct drm_connector *connector;
+
+       vbox_connector = kzalloc(sizeof(*vbox_connector), GFP_KERNEL);
+       if (!vbox_connector)
+               return -ENOMEM;
+
+       connector = &vbox_connector->base;
+       vbox_connector->vbox_crtc = vbox_crtc;
+
+       drm_connector_init(dev, connector, &vbox_connector_funcs,
+                          DRM_MODE_CONNECTOR_VGA);
+       drm_connector_helper_add(connector, &vbox_connector_helper_funcs);
+
+       connector->interlace_allowed = 0;
+       connector->doublescan_allowed = 0;
+
+       drm_mode_create_suggested_offset_properties(dev);
+       drm_object_attach_property(&connector->base,
+                                  dev->mode_config.suggested_x_property, -1);
+       drm_object_attach_property(&connector->base,
+                                  dev->mode_config.suggested_y_property, -1);
+       drm_connector_register(connector);
+
+       drm_mode_connector_attach_encoder(connector, encoder);
+
+       return 0;
+}
+
+int vbox_mode_init(struct drm_device *dev)
+{
+       struct vbox_private *vbox = dev->dev_private;
+       struct drm_encoder *encoder;
+       struct vbox_crtc *vbox_crtc;
+       unsigned int i;
+       int ret;
+
+       /* vbox_cursor_init(dev); */
+       for (i = 0; i < vbox->num_crtcs; ++i) {
+               vbox_crtc = vbox_crtc_init(dev, i);
+               if (!vbox_crtc)
+                       return -ENOMEM;
+               encoder = vbox_encoder_init(dev, i);
+               if (!encoder)
+                       return -ENOMEM;
+               ret = vbox_connector_init(dev, vbox_crtc, encoder);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+void vbox_mode_fini(struct drm_device *dev)
+{
+       /* vbox_cursor_fini(dev); */
+}
+
+/**
+ * Copy the ARGB image and generate the mask, which is needed in case the host
+ * does not support ARGB cursors.  The mask is a 1BPP bitmap with the bit set
+ * if the corresponding alpha value in the ARGB image is greater than 0xF0.
+ */
+static void copy_cursor_image(u8 *src, u8 *dst, u32 width, u32 height,
+                             size_t mask_size)
+{
+       size_t line_size = (width + 7) / 8;
+       u32 i, j;
+
+       memcpy(dst + mask_size, src, width * height * 4);
+       for (i = 0; i < height; ++i)
+               for (j = 0; j < width; ++j)
+                       if (((u32 *)src)[i * width + j] > 0xf0000000)
+                               dst[i * line_size + j / 8] |= (0x80 >> (j % 8));
+}
+
+static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
+                           u32 handle, u32 width, u32 height,
+                           s32 hot_x, s32 hot_y)
+{
+       struct vbox_private *vbox = crtc->dev->dev_private;
+       struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
+       struct ttm_bo_kmap_obj uobj_map;
+       size_t data_size, mask_size;
+       struct drm_gem_object *obj;
+       u32 flags, caps = 0;
+       struct vbox_bo *bo;
+       bool src_isiomem;
+       u8 *dst = NULL;
+       u8 *src;
+       int ret;
+
+       /*
+        * Re-set this regularly as in 5.0.20 and earlier the information was
+        * lost on save and restore.
+        */
+       hgsmi_update_input_mapping(vbox->guest_pool, 0, 0,
+                                  vbox->input_mapping_width,
+                                  vbox->input_mapping_height);
+       if (!handle) {
+               bool cursor_enabled = false;
+               struct drm_crtc *crtci;
+
+               /* Hide cursor. */
+               vbox_crtc->cursor_enabled = false;
+               list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list,
+                                   head) {
+                       if (to_vbox_crtc(crtci)->cursor_enabled)
+                               cursor_enabled = true;
+               }
+
+               if (!cursor_enabled)
+                       hgsmi_update_pointer_shape(vbox->guest_pool, 0, 0, 0,
+                                                  0, 0, NULL, 0);
+               return 0;
+       }
+
+       vbox_crtc->cursor_enabled = true;
+
+       if (width > VBOX_MAX_CURSOR_WIDTH || height > VBOX_MAX_CURSOR_HEIGHT ||
+           width == 0 || height == 0)
+               return -EINVAL;
+
+       ret = hgsmi_query_conf(vbox->guest_pool,
+                              VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &caps);
+       if (ret)
+               return ret;
+
+       if (!(caps & VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE)) {
+               /*
+                * -EINVAL means cursor_set2() not supported, -EAGAIN means
+                * retry at once.
+                */
+               return -EBUSY;
+       }
+
+       obj = drm_gem_object_lookup(file_priv, handle);
+       if (!obj) {
+               DRM_ERROR("Cannot find cursor object %x for crtc\n", handle);
+               return -ENOENT;
+       }
+
+       bo = gem_to_vbox_bo(obj);
+       ret = vbox_bo_reserve(bo, false);
+       if (ret)
+               goto out_unref_obj;
+
+       /*
+        * The mask must be calculated based on the alpha
+        * channel, one bit per ARGB word, and must be 32-bit
+        * padded.
+        */
+       mask_size = ((width + 7) / 8 * height + 3) & ~3;
+       data_size = width * height * 4 + mask_size;
+       vbox->cursor_hot_x = min_t(u32, max(hot_x, 0), width);
+       vbox->cursor_hot_y = min_t(u32, max(hot_y, 0), height);
+       vbox->cursor_width = width;
+       vbox->cursor_height = height;
+       vbox->cursor_data_size = data_size;
+       dst = vbox->cursor_data;
+
+       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &uobj_map);
+       if (ret) {
+               vbox->cursor_data_size = 0;
+               goto out_unreserve_bo;
+       }
+
+       src = ttm_kmap_obj_virtual(&uobj_map, &src_isiomem);
+       if (src_isiomem) {
+               DRM_ERROR("src cursor bo not in main memory\n");
+               ret = -EIO;
+               goto out_unmap_bo;
+       }
+
+       copy_cursor_image(src, dst, width, height, mask_size);
+
+       flags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE |
+               VBOX_MOUSE_POINTER_ALPHA;
+       ret = hgsmi_update_pointer_shape(vbox->guest_pool, flags,
+                                        vbox->cursor_hot_x, vbox->cursor_hot_y,
+                                        width, height, dst, data_size);
+out_unmap_bo:
+       ttm_bo_kunmap(&uobj_map);
+out_unreserve_bo:
+       vbox_bo_unreserve(bo);
+out_unref_obj:
+       drm_gem_object_unreference_unlocked(obj);
+
+       return ret;
+}
+
+static int vbox_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+       struct vbox_private *vbox = crtc->dev->dev_private;
+       u32 flags = VBOX_MOUSE_POINTER_VISIBLE |
+           VBOX_MOUSE_POINTER_SHAPE | VBOX_MOUSE_POINTER_ALPHA;
+       s32 crtc_x =
+           vbox->single_framebuffer ? crtc->x : to_vbox_crtc(crtc)->x_hint;
+       s32 crtc_y =
+           vbox->single_framebuffer ? crtc->y : to_vbox_crtc(crtc)->y_hint;
+       u32 host_x, host_y;
+       u32 hot_x = 0;
+       u32 hot_y = 0;
+       int ret;
+
+       /*
+        * We compare these to unsigned later and don't
+        * need to handle negative.
+        */
+       if (x + crtc_x < 0 || y + crtc_y < 0 || vbox->cursor_data_size == 0)
+               return 0;
+
+       ret = hgsmi_cursor_position(vbox->guest_pool, true, x + crtc_x,
+                                   y + crtc_y, &host_x, &host_y);
+
+       /*
+        * The only reason we have vbox_cursor_move() is that some older clients
+        * might use DRM_IOCTL_MODE_CURSOR instead of DRM_IOCTL_MODE_CURSOR2 and
+        * use DRM_MODE_CURSOR_MOVE to set the hot-spot.
+        *
+        * However VirtualBox 5.0.20 and earlier has a bug causing it to return
+        * 0,0 as host cursor location after a save and restore.
+        *
+        * To work around this we ignore a 0, 0 return, since missing the odd
+        * time when it legitimately happens is not going to hurt much.
+        */
+       if (ret || (host_x == 0 && host_y == 0))
+               return ret;
+
+       if (x + crtc_x < host_x)
+               hot_x = min(host_x - x - crtc_x, vbox->cursor_width);
+       if (y + crtc_y < host_y)
+               hot_y = min(host_y - y - crtc_y, vbox->cursor_height);
+
+       if (hot_x == vbox->cursor_hot_x && hot_y == vbox->cursor_hot_y)
+               return 0;
+
+       vbox->cursor_hot_x = hot_x;
+       vbox->cursor_hot_y = hot_y;
+
+       return hgsmi_update_pointer_shape(vbox->guest_pool, flags,
+                       hot_x, hot_y, vbox->cursor_width, vbox->cursor_height,
+                       vbox->cursor_data, vbox->cursor_data_size);
+}
diff --git a/drivers/staging/vboxvideo/vbox_prime.c b/drivers/staging/vboxvideo/vbox_prime.c
new file mode 100644 (file)
index 0000000..b7453e4
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 Oracle Corporation
+ * Copyright 2017 Canonical
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Andreas Pokorny
+ */
+
+#include "vbox_drv.h"
+
+/*
+ * Based on qxl_prime.c:
+ * Empty Implementations as there should not be any other driver for a virtual
+ * device that might share buffers with vboxvideo
+ */
+
+int vbox_gem_prime_pin(struct drm_gem_object *obj)
+{
+       WARN_ONCE(1, "not implemented");
+       return -ENOSYS;
+}
+
+void vbox_gem_prime_unpin(struct drm_gem_object *obj)
+{
+       WARN_ONCE(1, "not implemented");
+}
+
+struct sg_table *vbox_gem_prime_get_sg_table(struct drm_gem_object *obj)
+{
+       WARN_ONCE(1, "not implemented");
+       return ERR_PTR(-ENOSYS);
+}
+
+struct drm_gem_object *vbox_gem_prime_import_sg_table(
+       struct drm_device *dev, struct dma_buf_attachment *attach,
+       struct sg_table *table)
+{
+       WARN_ONCE(1, "not implemented");
+       return ERR_PTR(-ENOSYS);
+}
+
+void *vbox_gem_prime_vmap(struct drm_gem_object *obj)
+{
+       WARN_ONCE(1, "not implemented");
+       return ERR_PTR(-ENOSYS);
+}
+
+void vbox_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+       WARN_ONCE(1, "not implemented");
+}
+
+int vbox_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *area)
+{
+       WARN_ONCE(1, "not implemented");
+       return -ENOSYS;
+}
diff --git a/drivers/staging/vboxvideo/vbox_ttm.c b/drivers/staging/vboxvideo/vbox_ttm.c
new file mode 100644 (file)
index 0000000..34a905d
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2013-2017 Oracle Corporation
+ * This file is based on ast_ttm.c
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ *
+ * Authors: Dave Airlie <airlied@redhat.com>
+ *          Michael Thayer <michael.thayer@oracle.com>
+ */
+#include "vbox_drv.h"
+#include <ttm/ttm_page_alloc.h>
+
+static inline struct vbox_private *vbox_bdev(struct ttm_bo_device *bd)
+{
+       return container_of(bd, struct vbox_private, ttm.bdev);
+}
+
+static int vbox_ttm_mem_global_init(struct drm_global_reference *ref)
+{
+       return ttm_mem_global_init(ref->object);
+}
+
+static void vbox_ttm_mem_global_release(struct drm_global_reference *ref)
+{
+       ttm_mem_global_release(ref->object);
+}
+
+/**
+ * Adds the vbox memory manager object/structures to the global memory manager.
+ */
+static int vbox_ttm_global_init(struct vbox_private *vbox)
+{
+       struct drm_global_reference *global_ref;
+       int ret;
+
+       global_ref = &vbox->ttm.mem_global_ref;
+       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
+       global_ref->size = sizeof(struct ttm_mem_global);
+       global_ref->init = &vbox_ttm_mem_global_init;
+       global_ref->release = &vbox_ttm_mem_global_release;
+       ret = drm_global_item_ref(global_ref);
+       if (ret) {
+               DRM_ERROR("Failed setting up TTM memory subsystem.\n");
+               return ret;
+       }
+
+       vbox->ttm.bo_global_ref.mem_glob = vbox->ttm.mem_global_ref.object;
+       global_ref = &vbox->ttm.bo_global_ref.ref;
+       global_ref->global_type = DRM_GLOBAL_TTM_BO;
+       global_ref->size = sizeof(struct ttm_bo_global);
+       global_ref->init = &ttm_bo_global_init;
+       global_ref->release = &ttm_bo_global_release;
+
+       ret = drm_global_item_ref(global_ref);
+       if (ret) {
+               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
+               drm_global_item_unref(&vbox->ttm.mem_global_ref);
+               return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * Removes the vbox memory manager object from the global memory manager.
+ */
+static void vbox_ttm_global_release(struct vbox_private *vbox)
+{
+       drm_global_item_unref(&vbox->ttm.bo_global_ref.ref);
+       drm_global_item_unref(&vbox->ttm.mem_global_ref);
+}
+
+static void vbox_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+       struct vbox_bo *bo;
+
+       bo = container_of(tbo, struct vbox_bo, bo);
+
+       drm_gem_object_release(&bo->gem);
+       kfree(bo);
+}
+
+static bool vbox_ttm_bo_is_vbox_bo(struct ttm_buffer_object *bo)
+{
+       if (bo->destroy == &vbox_bo_ttm_destroy)
+               return true;
+
+       return false;
+}
+
+static int
+vbox_bo_init_mem_type(struct ttm_bo_device *bdev, u32 type,
+                     struct ttm_mem_type_manager *man)
+{
+       switch (type) {
+       case TTM_PL_SYSTEM:
+               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+               man->available_caching = TTM_PL_MASK_CACHING;
+               man->default_caching = TTM_PL_FLAG_CACHED;
+               break;
+       case TTM_PL_VRAM:
+               man->func = &ttm_bo_manager_func;
+               man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE;
+               man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
+               man->default_caching = TTM_PL_FLAG_WC;
+               break;
+       default:
+               DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void
+vbox_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
+{
+       struct vbox_bo *vboxbo = vbox_bo(bo);
+
+       if (!vbox_ttm_bo_is_vbox_bo(bo))
+               return;
+
+       vbox_ttm_placement(vboxbo, TTM_PL_FLAG_SYSTEM);
+       *pl = vboxbo->placement;
+}
+
+static int vbox_bo_verify_access(struct ttm_buffer_object *bo,
+                                struct file *filp)
+{
+       return 0;
+}
+
+static int vbox_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 vbox_private *vbox = vbox_bdev(bdev);
+
+       mem->bus.addr = NULL;
+       mem->bus.offset = 0;
+       mem->bus.size = mem->num_pages << PAGE_SHIFT;
+       mem->bus.base = 0;
+       mem->bus.is_iomem = false;
+       if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+               return -EINVAL;
+       switch (mem->mem_type) {
+       case TTM_PL_SYSTEM:
+               /* system memory */
+               return 0;
+       case TTM_PL_VRAM:
+               mem->bus.offset = mem->start << PAGE_SHIFT;
+               mem->bus.base = pci_resource_start(vbox->dev->pdev, 0);
+               mem->bus.is_iomem = true;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void vbox_ttm_io_mem_free(struct ttm_bo_device *bdev,
+                                struct ttm_mem_reg *mem)
+{
+}
+
+static int vbox_bo_move(struct ttm_buffer_object *bo,
+                       bool evict, bool interruptible,
+                       bool no_wait_gpu, struct ttm_mem_reg *new_mem)
+{
+       return ttm_bo_move_memcpy(bo, interruptible, no_wait_gpu, new_mem);
+}
+
+static void vbox_ttm_backend_destroy(struct ttm_tt *tt)
+{
+       ttm_tt_fini(tt);
+       kfree(tt);
+}
+
+static struct ttm_backend_func vbox_tt_backend_func = {
+       .destroy = &vbox_ttm_backend_destroy,
+};
+
+static struct ttm_tt *vbox_ttm_tt_create(struct ttm_bo_device *bdev,
+                                        unsigned long size,
+                                        u32 page_flags,
+                                        struct page *dummy_read_page)
+{
+       struct ttm_tt *tt;
+
+       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+       if (!tt)
+               return NULL;
+
+       tt->func = &vbox_tt_backend_func;
+       if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
+               kfree(tt);
+               return NULL;
+       }
+
+       return tt;
+}
+
+static int vbox_ttm_tt_populate(struct ttm_tt *ttm)
+{
+       return ttm_pool_populate(ttm);
+}
+
+static void vbox_ttm_tt_unpopulate(struct ttm_tt *ttm)
+{
+       ttm_pool_unpopulate(ttm);
+}
+
+struct ttm_bo_driver vbox_bo_driver = {
+       .ttm_tt_create = vbox_ttm_tt_create,
+       .ttm_tt_populate = vbox_ttm_tt_populate,
+       .ttm_tt_unpopulate = vbox_ttm_tt_unpopulate,
+       .init_mem_type = vbox_bo_init_mem_type,
+       .eviction_valuable = ttm_bo_eviction_valuable,
+       .evict_flags = vbox_bo_evict_flags,
+       .move = vbox_bo_move,
+       .verify_access = vbox_bo_verify_access,
+       .io_mem_reserve = &vbox_ttm_io_mem_reserve,
+       .io_mem_free = &vbox_ttm_io_mem_free,
+       .io_mem_pfn = ttm_bo_default_io_mem_pfn,
+};
+
+int vbox_mm_init(struct vbox_private *vbox)
+{
+       int ret;
+       struct drm_device *dev = vbox->dev;
+       struct ttm_bo_device *bdev = &vbox->ttm.bdev;
+
+       ret = vbox_ttm_global_init(vbox);
+       if (ret)
+               return ret;
+
+       ret = ttm_bo_device_init(&vbox->ttm.bdev,
+                                vbox->ttm.bo_global_ref.ref.object,
+                                &vbox_bo_driver,
+                                dev->anon_inode->i_mapping,
+                                DRM_FILE_PAGE_OFFSET, true);
+       if (ret) {
+               DRM_ERROR("Error initialising bo driver; %d\n", ret);
+               goto err_ttm_global_release;
+       }
+
+       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
+                            vbox->available_vram_size >> PAGE_SHIFT);
+       if (ret) {
+               DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
+               goto err_device_release;
+       }
+
+#ifdef DRM_MTRR_WC
+       vbox->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0),
+                                    pci_resource_len(dev->pdev, 0),
+                                    DRM_MTRR_WC);
+#else
+       vbox->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
+                                        pci_resource_len(dev->pdev, 0));
+#endif
+       return 0;
+
+err_device_release:
+       ttm_bo_device_release(&vbox->ttm.bdev);
+err_ttm_global_release:
+       vbox_ttm_global_release(vbox);
+       return ret;
+}
+
+void vbox_mm_fini(struct vbox_private *vbox)
+{
+#ifdef DRM_MTRR_WC
+       drm_mtrr_del(vbox->fb_mtrr,
+                    pci_resource_start(vbox->dev->pdev, 0),
+                    pci_resource_len(vbox->dev->pdev, 0), DRM_MTRR_WC);
+#else
+       arch_phys_wc_del(vbox->fb_mtrr);
+#endif
+       ttm_bo_device_release(&vbox->ttm.bdev);
+       vbox_ttm_global_release(vbox);
+}
+
+void vbox_ttm_placement(struct vbox_bo *bo, int domain)
+{
+       unsigned int i;
+       u32 c = 0;
+
+       bo->placement.placement = bo->placements;
+       bo->placement.busy_placement = bo->placements;
+
+       if (domain & TTM_PL_FLAG_VRAM)
+               bo->placements[c++].flags =
+                   TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+       if (domain & TTM_PL_FLAG_SYSTEM)
+               bo->placements[c++].flags =
+                   TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+       if (!c)
+               bo->placements[c++].flags =
+                   TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+
+       bo->placement.num_placement = c;
+       bo->placement.num_busy_placement = c;
+
+       for (i = 0; i < c; ++i) {
+               bo->placements[i].fpfn = 0;
+               bo->placements[i].lpfn = 0;
+       }
+}
+
+int vbox_bo_create(struct drm_device *dev, int size, int align,
+                  u32 flags, struct vbox_bo **pvboxbo)
+{
+       struct vbox_private *vbox = dev->dev_private;
+       struct vbox_bo *vboxbo;
+       size_t acc_size;
+       int ret;
+
+       vboxbo = kzalloc(sizeof(*vboxbo), GFP_KERNEL);
+       if (!vboxbo)
+               return -ENOMEM;
+
+       ret = drm_gem_object_init(dev, &vboxbo->gem, size);
+       if (ret)
+               goto err_free_vboxbo;
+
+       vboxbo->bo.bdev = &vbox->ttm.bdev;
+
+       vbox_ttm_placement(vboxbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+       acc_size = ttm_bo_dma_acc_size(&vbox->ttm.bdev, size,
+                                      sizeof(struct vbox_bo));
+
+       ret = ttm_bo_init(&vbox->ttm.bdev, &vboxbo->bo, size,
+                         ttm_bo_type_device, &vboxbo->placement,
+                         align >> PAGE_SHIFT, false, NULL, acc_size,
+                         NULL, NULL, vbox_bo_ttm_destroy);
+       if (ret)
+               goto err_free_vboxbo;
+
+       *pvboxbo = vboxbo;
+
+       return 0;
+
+err_free_vboxbo:
+       kfree(vboxbo);
+       return ret;
+}
+
+static inline u64 vbox_bo_gpu_offset(struct vbox_bo *bo)
+{
+       return bo->bo.offset;
+}
+
+int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag, u64 *gpu_addr)
+{
+       int i, ret;
+
+       if (bo->pin_count) {
+               bo->pin_count++;
+               if (gpu_addr)
+                       *gpu_addr = vbox_bo_gpu_offset(bo);
+
+               return 0;
+       }
+
+       vbox_ttm_placement(bo, pl_flag);
+
+       for (i = 0; i < bo->placement.num_placement; i++)
+               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
+
+       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+       if (ret)
+               return ret;
+
+       bo->pin_count = 1;
+
+       if (gpu_addr)
+               *gpu_addr = vbox_bo_gpu_offset(bo);
+
+       return 0;
+}
+
+int vbox_bo_unpin(struct vbox_bo *bo)
+{
+       int i, ret;
+
+       if (!bo->pin_count) {
+               DRM_ERROR("unpin bad %p\n", bo);
+               return 0;
+       }
+       bo->pin_count--;
+       if (bo->pin_count)
+               return 0;
+
+       for (i = 0; i < bo->placement.num_placement; i++)
+               bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
+
+       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+/*
+ * Move a vbox-owned buffer object to system memory if no one else has it
+ * pinned.  The caller must have pinned it previously, and this call will
+ * release the caller's pin.
+ */
+int vbox_bo_push_sysram(struct vbox_bo *bo)
+{
+       int i, ret;
+
+       if (!bo->pin_count) {
+               DRM_ERROR("unpin bad %p\n", bo);
+               return 0;
+       }
+       bo->pin_count--;
+       if (bo->pin_count)
+               return 0;
+
+       if (bo->kmap.virtual)
+               ttm_bo_kunmap(&bo->kmap);
+
+       vbox_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
+
+       for (i = 0; i < bo->placement.num_placement; i++)
+               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
+
+       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+       if (ret) {
+               DRM_ERROR("pushing to VRAM failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+int vbox_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct drm_file *file_priv;
+       struct vbox_private *vbox;
+
+       if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+               return -EINVAL;
+
+       file_priv = filp->private_data;
+       vbox = file_priv->minor->dev->dev_private;
+
+       return ttm_bo_mmap(filp, vma, &vbox->ttm.bdev);
+}
diff --git a/drivers/staging/vboxvideo/vboxvideo.h b/drivers/staging/vboxvideo/vboxvideo.h
new file mode 100644 (file)
index 0000000..d835d75
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#ifndef __VBOXVIDEO_H__
+#define __VBOXVIDEO_H__
+
+/*
+ * This should be in sync with monitorCount <xsd:maxInclusive value="64"/> in
+ * src/VBox/Main/xml/VirtualBox-settings-common.xsd
+ */
+#define VBOX_VIDEO_MAX_SCREENS 64
+
+/*
+ * The last 4096 bytes of the guest VRAM contains the generic info for all
+ * DualView chunks: sizes and offsets of chunks. This is filled by miniport.
+ *
+ * Last 4096 bytes of each chunk contain chunk specific data: framebuffer info,
+ * etc. This is used exclusively by the corresponding instance of a display
+ * driver.
+ *
+ * The VRAM layout:
+ *   Last 4096 bytes - Adapter information area.
+ *   4096 bytes aligned miniport heap (value specified in the config rouded up).
+ *   Slack - what left after dividing the VRAM.
+ *   4096 bytes aligned framebuffers:
+ *     last 4096 bytes of each framebuffer is the display information area.
+ *
+ * The Virtual Graphics Adapter information in the guest VRAM is stored by the
+ * guest video driver using structures prepended by VBOXVIDEOINFOHDR.
+ *
+ * When the guest driver writes dword 0 to the VBE_DISPI_INDEX_VBOX_VIDEO
+ * the host starts to process the info. The first element at the start of
+ * the 4096 bytes region should be normally be a LINK that points to
+ * actual information chain. That way the guest driver can have some
+ * fixed layout of the information memory block and just rewrite
+ * the link to point to relevant memory chain.
+ *
+ * The processing stops at the END element.
+ *
+ * The host can access the memory only when the port IO is processed.
+ * All data that will be needed later must be copied from these 4096 bytes.
+ * But other VRAM can be used by host until the mode is disabled.
+ *
+ * The guest driver writes dword 0xffffffff to the VBE_DISPI_INDEX_VBOX_VIDEO
+ * to disable the mode.
+ *
+ * VBE_DISPI_INDEX_VBOX_VIDEO is used to read the configuration information
+ * from the host and issue commands to the host.
+ *
+ * The guest writes the VBE_DISPI_INDEX_VBOX_VIDEO index register, the the
+ * following operations with the VBE data register can be performed:
+ *
+ * Operation            Result
+ * write 16 bit value   NOP
+ * read 16 bit value    count of monitors
+ * write 32 bit value   set the vbox cmd value and the cmd processed by the host
+ * read 32 bit value    result of the last vbox command is returned
+ */
+
+/**
+ * VBVA command header.
+ *
+ * @todo Where does this fit in?
+ */
+struct vbva_cmd_hdr {
+   /** Coordinates of affected rectangle. */
+       s16 x;
+       s16 y;
+       u16 w;
+       u16 h;
+} __packed;
+
+/** @name VBVA ring defines.
+ *
+ * The VBVA ring buffer is suitable for transferring large (< 2GB) amount of
+ * data. For example big bitmaps which do not fit to the buffer.
+ *
+ * Guest starts writing to the buffer by initializing a record entry in the
+ * records queue. VBVA_F_RECORD_PARTIAL indicates that the record is being
+ * written. As data is written to the ring buffer, the guest increases
+ * free_offset.
+ *
+ * The host reads the records on flushes and processes all completed records.
+ * When host encounters situation when only a partial record presents and
+ * len_and_flags & ~VBVA_F_RECORD_PARTIAL >= VBVA_RING_BUFFER_SIZE -
+ * VBVA_RING_BUFFER_THRESHOLD, the host fetched all record data and updates
+ * data_offset. After that on each flush the host continues fetching the data
+ * until the record is completed.
+ *
+ */
+#define VBVA_RING_BUFFER_SIZE        (4194304 - 1024)
+#define VBVA_RING_BUFFER_THRESHOLD   (4096)
+
+#define VBVA_MAX_RECORDS (64)
+
+#define VBVA_F_MODE_ENABLED         0x00000001u
+#define VBVA_F_MODE_VRDP            0x00000002u
+#define VBVA_F_MODE_VRDP_RESET      0x00000004u
+#define VBVA_F_MODE_VRDP_ORDER_MASK 0x00000008u
+
+#define VBVA_F_STATE_PROCESSING     0x00010000u
+
+#define VBVA_F_RECORD_PARTIAL       0x80000000u
+
+/**
+ * VBVA record.
+ */
+struct vbva_record {
+       /** The length of the record. Changed by guest. */
+       u32 len_and_flags;
+} __packed;
+
+/*
+ * The minimum HGSMI heap size is PAGE_SIZE (4096 bytes) and is a restriction of
+ * the runtime heapsimple API. Use minimum 2 pages here, because the info area
+ * also may contain other data (for example hgsmi_host_flags structure).
+ */
+#define VBVA_ADAPTER_INFORMATION_SIZE 65536
+#define VBVA_MIN_BUFFER_SIZE          65536
+
+/* The value for port IO to let the adapter to interpret the adapter memory. */
+#define VBOX_VIDEO_DISABLE_ADAPTER_MEMORY        0xFFFFFFFF
+
+/* The value for port IO to let the adapter to interpret the adapter memory. */
+#define VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY      0x00000000
+
+/* The value for port IO to let the adapter to interpret the display memory.
+ * The display number is encoded in low 16 bits.
+ */
+#define VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE 0x00010000
+
+struct vbva_host_flags {
+       u32 host_events;
+       u32 supported_orders;
+} __packed;
+
+struct vbva_buffer {
+       struct vbva_host_flags host_flags;
+
+       /* The offset where the data start in the buffer. */
+       u32 data_offset;
+       /* The offset where next data must be placed in the buffer. */
+       u32 free_offset;
+
+       /* The queue of record descriptions. */
+       struct vbva_record records[VBVA_MAX_RECORDS];
+       u32 record_first_index;
+       u32 record_free_index;
+
+       /* Space to leave free when large partial records are transferred. */
+       u32 partial_write_tresh;
+
+       u32 data_len;
+       /* variable size for the rest of the vbva_buffer area in VRAM. */
+       u8 data[0];
+} __packed;
+
+#define VBVA_MAX_RECORD_SIZE (128 * 1024 * 1024)
+
+/* guest->host commands */
+#define VBVA_QUERY_CONF32                       1
+#define VBVA_SET_CONF32                                 2
+#define VBVA_INFO_VIEW                          3
+#define VBVA_INFO_HEAP                          4
+#define VBVA_FLUSH                              5
+#define VBVA_INFO_SCREEN                        6
+#define VBVA_ENABLE                             7
+#define VBVA_MOUSE_POINTER_SHAPE                8
+/* informs host about HGSMI caps. see vbva_caps below */
+#define VBVA_INFO_CAPS                         12
+/* configures scanline, see VBVASCANLINECFG below */
+#define VBVA_SCANLINE_CFG                      13
+/* requests scanline info, see VBVASCANLINEINFO below */
+#define VBVA_SCANLINE_INFO                     14
+/* inform host about VBVA Command submission */
+#define VBVA_CMDVBVA_SUBMIT                    16
+/* inform host about VBVA Command submission */
+#define VBVA_CMDVBVA_FLUSH                     17
+/* G->H DMA command */
+#define VBVA_CMDVBVA_CTL                       18
+/* Query most recent mode hints sent */
+#define VBVA_QUERY_MODE_HINTS                  19
+/**
+ * Report the guest virtual desktop position and size for mapping host and
+ * guest pointer positions.
+ */
+#define VBVA_REPORT_INPUT_MAPPING              20
+/** Report the guest cursor position and query the host position. */
+#define VBVA_CURSOR_POSITION                   21
+
+/* host->guest commands */
+#define VBVAHG_EVENT                           1
+#define VBVAHG_DISPLAY_CUSTOM                  2
+
+/* vbva_conf32::index */
+#define VBOX_VBVA_CONF32_MONITOR_COUNT         0
+#define VBOX_VBVA_CONF32_HOST_HEAP_SIZE                1
+/**
+ * Returns VINF_SUCCESS if the host can report mode hints via VBVA.
+ * Set value to VERR_NOT_SUPPORTED before calling.
+ */
+#define VBOX_VBVA_CONF32_MODE_HINT_REPORTING   2
+/**
+ * Returns VINF_SUCCESS if the host can report guest cursor enabled status via
+ * VBVA.  Set value to VERR_NOT_SUPPORTED before calling.
+ */
+#define VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING        3
+/**
+ * Returns the currently available host cursor capabilities.  Available if
+ * vbva_conf32::VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING returns success.
+ * @see VMMDevReqMouseStatus::mouseFeatures.
+ */
+#define VBOX_VBVA_CONF32_CURSOR_CAPABILITIES   4
+/** Returns the supported flags in vbva_infoscreen::flags. */
+#define VBOX_VBVA_CONF32_SCREEN_FLAGS          5
+/** Returns the max size of VBVA record. */
+#define VBOX_VBVA_CONF32_MAX_RECORD_SIZE       6
+
+struct vbva_conf32 {
+       u32 index;
+       u32 value;
+} __packed;
+
+/** Reserved for historical reasons. */
+#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED0   BIT(0)
+/**
+ * Guest cursor capability: can the host show a hardware cursor at the host
+ * pointer location?
+ */
+#define VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE    BIT(1)
+/** Reserved for historical reasons. */
+#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED2   BIT(2)
+/** Reserved for historical reasons.  Must always be unset. */
+#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED3   BIT(3)
+/** Reserved for historical reasons. */
+#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED4   BIT(4)
+/** Reserved for historical reasons. */
+#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED5   BIT(5)
+
+struct vbva_infoview {
+       /* Index of the screen, assigned by the guest. */
+       u32 view_index;
+
+       /* The screen offset in VRAM, the framebuffer starts here. */
+       u32 view_offset;
+
+       /* The size of the VRAM memory that can be used for the view. */
+       u32 view_size;
+
+       /* The recommended maximum size of the VRAM memory for the screen. */
+       u32 max_screen_size;
+} __packed;
+
+struct vbva_flush {
+       u32 reserved;
+} __packed;
+
+/* vbva_infoscreen::flags */
+#define VBVA_SCREEN_F_NONE                     0x0000
+#define VBVA_SCREEN_F_ACTIVE                   0x0001
+/**
+ * The virtual monitor has been disabled by the guest and should be removed
+ * by the host and ignored for purposes of pointer position calculation.
+ */
+#define VBVA_SCREEN_F_DISABLED                 0x0002
+/**
+ * The virtual monitor has been blanked by the guest and should be blacked
+ * out by the host using width, height, etc values from the vbva_infoscreen
+ * request.
+ */
+#define VBVA_SCREEN_F_BLANK                    0x0004
+/**
+ * The virtual monitor has been blanked by the guest and should be blacked
+ * out by the host using the previous mode values for width. height, etc.
+ */
+#define VBVA_SCREEN_F_BLANK2                   0x0008
+
+struct vbva_infoscreen {
+       /* Which view contains the screen. */
+       u32 view_index;
+
+       /* Physical X origin relative to the primary screen. */
+       s32 origin_x;
+
+       /* Physical Y origin relative to the primary screen. */
+       s32 origin_y;
+
+       /* Offset of visible framebuffer relative to the framebuffer start. */
+       u32 start_offset;
+
+       /* The scan line size in bytes. */
+       u32 line_size;
+
+       /* Width of the screen. */
+       u32 width;
+
+       /* Height of the screen. */
+       u32 height;
+
+       /* Color depth. */
+       u16 bits_per_pixel;
+
+       /* VBVA_SCREEN_F_* */
+       u16 flags;
+} __packed;
+
+/* vbva_enable::flags */
+#define VBVA_F_NONE                            0x00000000
+#define VBVA_F_ENABLE                          0x00000001
+#define VBVA_F_DISABLE                         0x00000002
+/* extended VBVA to be used with WDDM */
+#define VBVA_F_EXTENDED                                0x00000004
+/* vbva offset is absolute VRAM offset */
+#define VBVA_F_ABSOFFSET                       0x00000008
+
+struct vbva_enable {
+       u32 flags;
+       u32 offset;
+       s32 result;
+} __packed;
+
+struct vbva_enable_ex {
+       struct vbva_enable base;
+       u32 screen_id;
+} __packed;
+
+struct vbva_mouse_pointer_shape {
+       /* The host result. */
+       s32 result;
+
+       /* VBOX_MOUSE_POINTER_* bit flags. */
+       u32 flags;
+
+       /* X coordinate of the hot spot. */
+       u32 hot_X;
+
+       /* Y coordinate of the hot spot. */
+       u32 hot_y;
+
+       /* Width of the pointer in pixels. */
+       u32 width;
+
+       /* Height of the pointer in scanlines. */
+       u32 height;
+
+       /* Pointer data.
+        *
+        ****
+        * The data consists of 1 bpp AND mask followed by 32 bpp XOR (color)
+        * mask.
+        *
+        * For pointers without alpha channel the XOR mask pixels are 32 bit
+        * values: (lsb)BGR0(msb). For pointers with alpha channel the XOR mask
+        * consists of (lsb)BGRA(msb) 32 bit values.
+        *
+        * Guest driver must create the AND mask for pointers with alpha chan.,
+        * so if host does not support alpha, the pointer could be displayed as
+        * a normal color pointer. The AND mask can be constructed from alpha
+        * values. For example alpha value >= 0xf0 means bit 0 in the AND mask.
+        *
+        * The AND mask is 1 bpp bitmap with byte aligned scanlines. Size of AND
+        * mask, therefore, is and_len = (width + 7) / 8 * height. The padding
+        * bits at the end of any scanline are undefined.
+        *
+        * The XOR mask follows the AND mask on the next 4 bytes aligned offset:
+        * u8 *xor = and + (and_len + 3) & ~3
+        * Bytes in the gap between the AND and the XOR mask are undefined.
+        * XOR mask scanlines have no gap between them and size of XOR mask is:
+        * xor_len = width * 4 * height.
+        ****
+        *
+        * Preallocate 4 bytes for accessing actual data as p->data.
+        */
+       u8 data[4];
+} __packed;
+
+/**
+ * @name vbva_mouse_pointer_shape::flags
+ * @note The VBOX_MOUSE_POINTER_* flags are used in the guest video driver,
+ *       values must be <= 0x8000 and must not be changed. (try make more sense
+ *       of this, please).
+ * @{
+ */
+
+/** pointer is visible */
+#define VBOX_MOUSE_POINTER_VISIBLE             0x0001
+/** pointer has alpha channel */
+#define VBOX_MOUSE_POINTER_ALPHA               0x0002
+/** pointerData contains new pointer shape */
+#define VBOX_MOUSE_POINTER_SHAPE               0x0004
+
+/** @} */
+
+/*
+ * The guest driver can handle asynch guest cmd completion by reading the
+ * command offset from io port.
+ */
+#define VBVACAPS_COMPLETEGCMD_BY_IOREAD                0x00000001
+/* the guest driver can handle video adapter IRQs */
+#define VBVACAPS_IRQ                           0x00000002
+/** The guest can read video mode hints sent via VBVA. */
+#define VBVACAPS_VIDEO_MODE_HINTS              0x00000004
+/** The guest can switch to a software cursor on demand. */
+#define VBVACAPS_DISABLE_CURSOR_INTEGRATION    0x00000008
+/** The guest does not depend on host handling the VBE registers. */
+#define VBVACAPS_USE_VBVA_ONLY                 0x00000010
+
+struct vbva_caps {
+       s32 rc;
+       u32 caps;
+} __packed;
+
+/** Query the most recent mode hints received from the host. */
+struct vbva_query_mode_hints {
+       /** The maximum number of screens to return hints for. */
+       u16 hints_queried_count;
+       /** The size of the mode hint structures directly following this one. */
+       u16 hint_structure_guest_size;
+       /** Return code for the operation. Initialise to VERR_NOT_SUPPORTED. */
+       s32 rc;
+} __packed;
+
+/**
+ * Structure in which a mode hint is returned. The guest allocates an array
+ * of these immediately after the vbva_query_mode_hints structure.
+ * To accommodate future extensions, the vbva_query_mode_hints structure
+ * specifies the size of the vbva_modehint structures allocated by the guest,
+ * and the host only fills out structure elements which fit into that size. The
+ * host should fill any unused members (e.g. dx, dy) or structure space on the
+ * end with ~0. The whole structure can legally be set to ~0 to skip a screen.
+ */
+struct vbva_modehint {
+       u32 magic;
+       u32 cx;
+       u32 cy;
+       u32 bpp;                /* Which has never been used... */
+       u32 display;
+       u32 dx;                 /**< X offset into the virtual frame-buffer. */
+       u32 dy;                 /**< Y offset into the virtual frame-buffer. */
+       u32 enabled;            /* Not flags. Add new members for new flags. */
+} __packed;
+
+#define VBVAMODEHINT_MAGIC 0x0801add9u
+
+/**
+ * Report the rectangle relative to which absolute pointer events should be
+ * expressed. This information remains valid until the next VBVA resize event
+ * for any screen, at which time it is reset to the bounding rectangle of all
+ * virtual screens and must be re-set.
+ * @see VBVA_REPORT_INPUT_MAPPING.
+ */
+struct vbva_report_input_mapping {
+       s32 x;  /**< Upper left X co-ordinate relative to the first screen. */
+       s32 y;  /**< Upper left Y co-ordinate relative to the first screen. */
+       u32 cx; /**< Rectangle width. */
+       u32 cy; /**< Rectangle height. */
+} __packed;
+
+/**
+ * Report the guest cursor position and query the host one. The host may wish
+ * to use the guest information to re-position its own cursor (though this is
+ * currently unlikely).
+ * @see VBVA_CURSOR_POSITION
+ */
+struct vbva_cursor_position {
+       u32 report_position;    /**< Are we reporting a position? */
+       u32 x;                  /**< Guest cursor X position */
+       u32 y;                  /**< Guest cursor Y position */
+} __packed;
+
+#endif
diff --git a/drivers/staging/vboxvideo/vboxvideo_guest.h b/drivers/staging/vboxvideo/vboxvideo_guest.h
new file mode 100644 (file)
index 0000000..d09da84
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __VBOXVIDEO_GUEST_H__
+#define __VBOXVIDEO_GUEST_H__
+
+#include <linux/genalloc.h>
+#include "vboxvideo.h"
+
+/**
+ * Structure grouping the context needed for sending graphics acceleration
+ * information to the host via VBVA.  Each screen has its own VBVA buffer.
+ */
+struct vbva_buf_ctx {
+       /** Offset of the buffer in the VRAM section for the screen */
+       u32 buffer_offset;
+       /** Length of the buffer in bytes */
+       u32 buffer_length;
+       /** Set if we wrote to the buffer faster than the host could read it */
+       bool buffer_overflow;
+       /** VBVA record that we are currently preparing for the host, or NULL */
+       struct vbva_record *record;
+       /**
+        * Pointer to the VBVA buffer mapped into the current address space.
+        * Will be NULL if VBVA is not enabled.
+        */
+       struct vbva_buffer *vbva;
+};
+
+/**
+ * @name Base HGSMI APIs
+ * @{
+ */
+int hgsmi_report_flags_location(struct gen_pool *ctx, u32 location);
+int hgsmi_send_caps_info(struct gen_pool *ctx, u32 caps);
+int hgsmi_test_query_conf(struct gen_pool *ctx);
+int hgsmi_query_conf(struct gen_pool *ctx, u32 index, u32 *value_ret);
+int hgsmi_update_pointer_shape(struct gen_pool *ctx, u32 flags,
+                              u32 hot_x, u32 hot_y, u32 width, u32 height,
+                              u8 *pixels, u32 len);
+int hgsmi_cursor_position(struct gen_pool *ctx, bool report_position,
+                         u32 x, u32 y, u32 *x_host, u32 *y_host);
+/** @}  */
+
+/**
+ * @name VBVA APIs
+ * @{
+ */
+bool vbva_enable(struct vbva_buf_ctx *vbva_ctx, struct gen_pool *ctx,
+                struct vbva_buffer *vbva, s32 screen);
+void vbva_disable(struct vbva_buf_ctx *vbva_ctx, struct gen_pool *ctx,
+                 s32 screen);
+bool vbva_buffer_begin_update(struct vbva_buf_ctx *vbva_ctx,
+                             struct gen_pool *ctx);
+void vbva_buffer_end_update(struct vbva_buf_ctx *vbva_ctx);
+bool vbva_write(struct vbva_buf_ctx *vbva_ctx, struct gen_pool *ctx,
+               const void *p, u32 len);
+void vbva_setup_buffer_context(struct vbva_buf_ctx *vbva_ctx,
+                              u32 buffer_offset, u32 buffer_length);
+/** @}  */
+
+/**
+ * @name Modesetting APIs
+ * @{
+ */
+void hgsmi_process_display_info(struct gen_pool *ctx, u32 display,
+                               s32 origin_x, s32 origin_y, u32 start_offset,
+                               u32 pitch, u32 width, u32 height,
+                               u16 bpp, u16 flags);
+int hgsmi_update_input_mapping(struct gen_pool *ctx, s32 origin_x, s32 origin_y,
+                              u32 width, u32 height);
+int hgsmi_get_mode_hints(struct gen_pool *ctx, unsigned int screens,
+                        struct vbva_modehint *hints);
+/** @}  */
+
+#endif
diff --git a/drivers/staging/vboxvideo/vboxvideo_vbe.h b/drivers/staging/vboxvideo/vboxvideo_vbe.h
new file mode 100644 (file)
index 0000000..f842f4d
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __VBOXVIDEO_VBE_H__
+#define __VBOXVIDEO_VBE_H__
+
+/* GUEST <-> HOST Communication API */
+
+/**
+ * @todo FIXME: Either dynamicly ask host for this or put somewhere high in
+ *              physical memory like 0xE0000000.
+ */
+
+#define VBE_DISPI_BANK_ADDRESS          0xA0000
+#define VBE_DISPI_BANK_SIZE_KB          64
+
+#define VBE_DISPI_MAX_XRES              16384
+#define VBE_DISPI_MAX_YRES              16384
+#define VBE_DISPI_MAX_BPP               32
+
+#define VBE_DISPI_IOPORT_INDEX          0x01CE
+#define VBE_DISPI_IOPORT_DATA           0x01CF
+
+#define VBE_DISPI_IOPORT_DAC_WRITE_INDEX  0x03C8
+#define VBE_DISPI_IOPORT_DAC_DATA         0x03C9
+
+#define VBE_DISPI_INDEX_ID              0x0
+#define VBE_DISPI_INDEX_XRES            0x1
+#define VBE_DISPI_INDEX_YRES            0x2
+#define VBE_DISPI_INDEX_BPP             0x3
+#define VBE_DISPI_INDEX_ENABLE          0x4
+#define VBE_DISPI_INDEX_BANK            0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
+#define VBE_DISPI_INDEX_X_OFFSET        0x8
+#define VBE_DISPI_INDEX_Y_OFFSET        0x9
+#define VBE_DISPI_INDEX_VBOX_VIDEO      0xa
+#define VBE_DISPI_INDEX_FB_BASE_HI      0xb
+
+#define VBE_DISPI_ID0                   0xB0C0
+#define VBE_DISPI_ID1                   0xB0C1
+#define VBE_DISPI_ID2                   0xB0C2
+#define VBE_DISPI_ID3                   0xB0C3
+#define VBE_DISPI_ID4                   0xB0C4
+
+#define VBE_DISPI_ID_VBOX_VIDEO         0xBE00
+/* The VBOX interface id. Indicates support for VBVA shared memory interface. */
+#define VBE_DISPI_ID_HGSMI              0xBE01
+#define VBE_DISPI_ID_ANYX               0xBE02
+
+#define VBE_DISPI_DISABLED              0x00
+#define VBE_DISPI_ENABLED               0x01
+#define VBE_DISPI_GETCAPS               0x02
+#define VBE_DISPI_8BIT_DAC              0x20
+/**
+ * @note this definition is a BOCHS legacy, used only in the video BIOS
+ * code and ignored by the emulated hardware.
+ */
+#define VBE_DISPI_LFB_ENABLED           0x40
+#define VBE_DISPI_NOCLEARMEM            0x80
+
+#define VGA_PORT_HGSMI_HOST             0x3b0
+#define VGA_PORT_HGSMI_GUEST            0x3d0
+
+#endif
diff --git a/drivers/staging/vboxvideo/vbva_base.c b/drivers/staging/vboxvideo/vbva_base.c
new file mode 100644 (file)
index 0000000..c10c782
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "vbox_drv.h"
+#include "vbox_err.h"
+#include "vboxvideo_guest.h"
+#include "hgsmi_channels.h"
+
+/*
+ * There is a hardware ring buffer in the graphics device video RAM, formerly
+ * in the VBox VMMDev PCI memory space.
+ * All graphics commands go there serialized by vbva_buffer_begin_update.
+ * and vbva_buffer_end_update.
+ *
+ * free_offset is writing position. data_offset is reading position.
+ * free_offset == data_offset means buffer is empty.
+ * There must be always gap between data_offset and free_offset when data
+ * are in the buffer.
+ * Guest only changes free_offset, host changes data_offset.
+ */
+
+static u32 vbva_buffer_available(const struct vbva_buffer *vbva)
+{
+       s32 diff = vbva->data_offset - vbva->free_offset;
+
+       return diff > 0 ? diff : vbva->data_len + diff;
+}
+
+static void vbva_buffer_place_data_at(struct vbva_buf_ctx *vbva_ctx,
+                                     const void *p, u32 len, u32 offset)
+{
+       struct vbva_buffer *vbva = vbva_ctx->vbva;
+       u32 bytes_till_boundary = vbva->data_len - offset;
+       u8 *dst = &vbva->data[offset];
+       s32 diff = len - bytes_till_boundary;
+
+       if (diff <= 0) {
+               /* Chunk will not cross buffer boundary. */
+               memcpy(dst, p, len);
+       } else {
+               /* Chunk crosses buffer boundary. */
+               memcpy(dst, p, bytes_till_boundary);
+               memcpy(&vbva->data[0], (u8 *)p + bytes_till_boundary, diff);
+       }
+}
+
+static void vbva_buffer_flush(struct gen_pool *ctx)
+{
+       struct vbva_flush *p;
+
+       p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA, VBVA_FLUSH);
+       if (!p)
+               return;
+
+       p->reserved = 0;
+
+       hgsmi_buffer_submit(ctx, p);
+       hgsmi_buffer_free(ctx, p);
+}
+
+bool vbva_write(struct vbva_buf_ctx *vbva_ctx, struct gen_pool *ctx,
+               const void *p, u32 len)
+{
+       struct vbva_record *record;
+       struct vbva_buffer *vbva;
+       u32 available;
+
+       vbva = vbva_ctx->vbva;
+       record = vbva_ctx->record;
+
+       if (!vbva || vbva_ctx->buffer_overflow ||
+           !record || !(record->len_and_flags & VBVA_F_RECORD_PARTIAL))
+               return false;
+
+       available = vbva_buffer_available(vbva);
+
+       while (len > 0) {
+               u32 chunk = len;
+
+               if (chunk >= available) {
+                       vbva_buffer_flush(ctx);
+                       available = vbva_buffer_available(vbva);
+               }
+
+               if (chunk >= available) {
+                       if (WARN_ON(available <= vbva->partial_write_tresh)) {
+                               vbva_ctx->buffer_overflow = true;
+                               return false;
+                       }
+                       chunk = available - vbva->partial_write_tresh;
+               }
+
+               vbva_buffer_place_data_at(vbva_ctx, p, chunk,
+                                         vbva->free_offset);
+
+               vbva->free_offset = (vbva->free_offset + chunk) %
+                                   vbva->data_len;
+               record->len_and_flags += chunk;
+               available -= chunk;
+               len -= chunk;
+               p += chunk;
+       }
+
+       return true;
+}
+
+static bool vbva_inform_host(struct vbva_buf_ctx *vbva_ctx,
+                            struct gen_pool *ctx, s32 screen, bool enable)
+{
+       struct vbva_enable_ex *p;
+       bool ret;
+
+       p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA, VBVA_ENABLE);
+       if (!p)
+               return false;
+
+       p->base.flags = enable ? VBVA_F_ENABLE : VBVA_F_DISABLE;
+       p->base.offset = vbva_ctx->buffer_offset;
+       p->base.result = VERR_NOT_SUPPORTED;
+       if (screen >= 0) {
+               p->base.flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET;
+               p->screen_id = screen;
+       }
+
+       hgsmi_buffer_submit(ctx, p);
+
+       if (enable)
+               ret = RT_SUCCESS(p->base.result);
+       else
+               ret = true;
+
+       hgsmi_buffer_free(ctx, p);
+
+       return ret;
+}
+
+bool vbva_enable(struct vbva_buf_ctx *vbva_ctx, struct gen_pool *ctx,
+                struct vbva_buffer *vbva, s32 screen)
+{
+       bool ret = false;
+
+       memset(vbva, 0, sizeof(*vbva));
+       vbva->partial_write_tresh = 256;
+       vbva->data_len = vbva_ctx->buffer_length - sizeof(struct vbva_buffer);
+       vbva_ctx->vbva = vbva;
+
+       ret = vbva_inform_host(vbva_ctx, ctx, screen, true);
+       if (!ret)
+               vbva_disable(vbva_ctx, ctx, screen);
+
+       return ret;
+}
+
+void vbva_disable(struct vbva_buf_ctx *vbva_ctx, struct gen_pool *ctx,
+                 s32 screen)
+{
+       vbva_ctx->buffer_overflow = false;
+       vbva_ctx->record = NULL;
+       vbva_ctx->vbva = NULL;
+
+       vbva_inform_host(vbva_ctx, ctx, screen, false);
+}
+
+bool vbva_buffer_begin_update(struct vbva_buf_ctx *vbva_ctx,
+                             struct gen_pool *ctx)
+{
+       struct vbva_record *record;
+       u32 next;
+
+       if (!vbva_ctx->vbva ||
+           !(vbva_ctx->vbva->host_flags.host_events & VBVA_F_MODE_ENABLED))
+               return false;
+
+       WARN_ON(vbva_ctx->buffer_overflow || vbva_ctx->record);
+
+       next = (vbva_ctx->vbva->record_free_index + 1) % VBVA_MAX_RECORDS;
+
+       /* Flush if all slots in the records queue are used */
+       if (next == vbva_ctx->vbva->record_first_index)
+               vbva_buffer_flush(ctx);
+
+       /* If even after flush there is no place then fail the request */
+       if (next == vbva_ctx->vbva->record_first_index)
+               return false;
+
+       record = &vbva_ctx->vbva->records[vbva_ctx->vbva->record_free_index];
+       record->len_and_flags = VBVA_F_RECORD_PARTIAL;
+       vbva_ctx->vbva->record_free_index = next;
+       /* Remember which record we are using. */
+       vbva_ctx->record = record;
+
+       return true;
+}
+
+void vbva_buffer_end_update(struct vbva_buf_ctx *vbva_ctx)
+{
+       struct vbva_record *record = vbva_ctx->record;
+
+       WARN_ON(!vbva_ctx->vbva || !record ||
+               !(record->len_and_flags & VBVA_F_RECORD_PARTIAL));
+
+       /* Mark the record completed. */
+       record->len_and_flags &= ~VBVA_F_RECORD_PARTIAL;
+
+       vbva_ctx->buffer_overflow = false;
+       vbva_ctx->record = NULL;
+}
+
+void vbva_setup_buffer_context(struct vbva_buf_ctx *vbva_ctx,
+                              u32 buffer_offset, u32 buffer_length)
+{
+       vbva_ctx->buffer_offset = buffer_offset;
+       vbva_ctx->buffer_length = buffer_length;
+}
index 030bec8..314ffac 100644 (file)
@@ -3391,7 +3391,6 @@ static int vchiq_probe(struct platform_device *pdev)
        struct device_node *fw_node;
        struct rpi_firmware *fw;
        int err;
-       void *ptr_err;
 
        fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
        if (!fw_node) {
@@ -3427,14 +3426,14 @@ static int vchiq_probe(struct platform_device *pdev)
 
        /* create sysfs entries */
        vchiq_class = class_create(THIS_MODULE, DEVICE_NAME);
-       ptr_err = vchiq_class;
-       if (IS_ERR(ptr_err))
+       err = PTR_ERR(vchiq_class);
+       if (IS_ERR(vchiq_class))
                goto failed_class_create;
 
        vchiq_dev = device_create(vchiq_class, NULL,
                vchiq_devid, NULL, "vchiq");
-       ptr_err = vchiq_dev;
-       if (IS_ERR(ptr_err))
+       err = PTR_ERR(vchiq_dev);
+       if (IS_ERR(vchiq_dev))
                goto failed_device_create;
 
        /* create debugfs entries */
@@ -3455,7 +3454,6 @@ failed_device_create:
        class_destroy(vchiq_class);
 failed_class_create:
        cdev_del(&vchiq_cdev);
-       err = PTR_ERR(ptr_err);
 failed_cdev_add:
        unregister_chrdev_region(vchiq_devid, 1);
 failed_platform_init:
index 3fdca2c..74e4975 100644 (file)
@@ -488,15 +488,13 @@ EXPORT_SYMBOL(iscsit_queue_rsp);
 
 void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
 {
-       bool scsi_cmd = (cmd->iscsi_opcode == ISCSI_OP_SCSI_CMD);
-
        spin_lock_bh(&conn->cmd_lock);
        if (!list_empty(&cmd->i_conn_node) &&
            !(cmd->se_cmd.transport_state & CMD_T_FABRIC_STOP))
                list_del_init(&cmd->i_conn_node);
        spin_unlock_bh(&conn->cmd_lock);
 
-       __iscsit_free_cmd(cmd, scsi_cmd, true);
+       __iscsit_free_cmd(cmd, true);
 }
 EXPORT_SYMBOL(iscsit_aborted_task);
 
@@ -1251,12 +1249,8 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
         * execution.  These exceptions are processed in CmdSN order using
         * iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below.
         */
-       if (cmd->sense_reason) {
-               if (cmd->reject_reason)
-                       return 0;
-
+       if (cmd->sense_reason)
                return 1;
-       }
        /*
         * Call directly into transport_generic_new_cmd() to perform
         * the backend memory allocation.
index 903b667..f9bc8ec 100644 (file)
@@ -47,18 +47,21 @@ static void chap_binaryhex_to_asciihex(char *dst, char *src, int src_len)
        }
 }
 
-static void chap_gen_challenge(
+static int chap_gen_challenge(
        struct iscsi_conn *conn,
        int caller,
        char *c_str,
        unsigned int *c_len)
 {
+       int ret;
        unsigned char challenge_asciihex[CHAP_CHALLENGE_LENGTH * 2 + 1];
        struct iscsi_chap *chap = conn->auth_protocol;
 
        memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1);
 
-       get_random_bytes(chap->challenge, CHAP_CHALLENGE_LENGTH);
+       ret = get_random_bytes_wait(chap->challenge, CHAP_CHALLENGE_LENGTH);
+       if (unlikely(ret))
+               return ret;
        chap_binaryhex_to_asciihex(challenge_asciihex, chap->challenge,
                                CHAP_CHALLENGE_LENGTH);
        /*
@@ -69,6 +72,7 @@ static void chap_gen_challenge(
 
        pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client",
                        challenge_asciihex);
+       return 0;
 }
 
 static int chap_check_algorithm(const char *a_str)
@@ -143,6 +147,7 @@ static struct iscsi_chap *chap_server_open(
        case CHAP_DIGEST_UNKNOWN:
        default:
                pr_err("Unsupported CHAP_A value\n");
+               kfree(conn->auth_protocol);
                return NULL;
        }
 
@@ -156,7 +161,10 @@ static struct iscsi_chap *chap_server_open(
        /*
         * Generate Challenge.
         */
-       chap_gen_challenge(conn, 1, aic_str, aic_len);
+       if (chap_gen_challenge(conn, 1, aic_str, aic_len) < 0) {
+               kfree(conn->auth_protocol);
+               return NULL;
+       }
 
        return chap;
 }
index 535a8e0..0dd4c45 100644 (file)
@@ -781,6 +781,7 @@ DEF_TPG_ATTRIB(default_erl);
 DEF_TPG_ATTRIB(t10_pi);
 DEF_TPG_ATTRIB(fabric_prot_type);
 DEF_TPG_ATTRIB(tpg_enabled_sendtargets);
+DEF_TPG_ATTRIB(login_keys_workaround);
 
 static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
        &iscsi_tpg_attrib_attr_authentication,
@@ -796,6 +797,7 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
        &iscsi_tpg_attrib_attr_t10_pi,
        &iscsi_tpg_attrib_attr_fabric_prot_type,
        &iscsi_tpg_attrib_attr_tpg_enabled_sendtargets,
+       &iscsi_tpg_attrib_attr_login_keys_workaround,
        NULL,
 };
 
index 92b96b5..e9bdc8b 100644 (file)
@@ -245,22 +245,26 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
        return 0;
 }
 
-static void iscsi_login_set_conn_values(
+static int iscsi_login_set_conn_values(
        struct iscsi_session *sess,
        struct iscsi_conn *conn,
        __be16 cid)
 {
+       int ret;
        conn->sess              = sess;
        conn->cid               = be16_to_cpu(cid);
        /*
         * Generate a random Status sequence number (statsn) for the new
         * iSCSI connection.
         */
-       get_random_bytes(&conn->stat_sn, sizeof(u32));
+       ret = get_random_bytes_wait(&conn->stat_sn, sizeof(u32));
+       if (unlikely(ret))
+               return ret;
 
        mutex_lock(&auth_id_lock);
        conn->auth_id           = iscsit_global->auth_id++;
        mutex_unlock(&auth_id_lock);
+       return 0;
 }
 
 __printf(2, 3) int iscsi_change_param_sprintf(
@@ -306,7 +310,11 @@ static int iscsi_login_zero_tsih_s1(
                return -ENOMEM;
        }
 
-       iscsi_login_set_conn_values(sess, conn, pdu->cid);
+       ret = iscsi_login_set_conn_values(sess, conn, pdu->cid);
+       if (unlikely(ret)) {
+               kfree(sess);
+               return ret;
+       }
        sess->init_task_tag     = pdu->itt;
        memcpy(&sess->isid, pdu->isid, 6);
        sess->exp_cmd_sn        = be32_to_cpu(pdu->cmdsn);
@@ -497,8 +505,7 @@ static int iscsi_login_non_zero_tsih_s1(
 {
        struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
 
-       iscsi_login_set_conn_values(NULL, conn, pdu->cid);
-       return 0;
+       return iscsi_login_set_conn_values(NULL, conn, pdu->cid);
 }
 
 /*
@@ -554,9 +561,8 @@ static int iscsi_login_non_zero_tsih_s2(
                atomic_set(&sess->session_continuation, 1);
        spin_unlock_bh(&sess->conn_lock);
 
-       iscsi_login_set_conn_values(sess, conn, pdu->cid);
-
-       if (iscsi_copy_param_list(&conn->param_list,
+       if (iscsi_login_set_conn_values(sess, conn, pdu->cid) < 0 ||
+           iscsi_copy_param_list(&conn->param_list,
                        conn->tpg->param_list, 0) < 0) {
                iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
                                ISCSI_LOGIN_STATUS_NO_RESOURCES);
index 6f88b31..7a6751f 100644 (file)
@@ -655,28 +655,6 @@ err:
        iscsit_deaccess_np(np, tpg, tpg_np);
 }
 
-static void iscsi_target_do_cleanup(struct work_struct *work)
-{
-       struct iscsi_conn *conn = container_of(work,
-                               struct iscsi_conn, login_cleanup_work.work);
-       struct sock *sk = conn->sock->sk;
-       struct iscsi_login *login = conn->login;
-       struct iscsi_np *np = login->np;
-       struct iscsi_portal_group *tpg = conn->tpg;
-       struct iscsi_tpg_np *tpg_np = conn->tpg_np;
-
-       pr_debug("Entering iscsi_target_do_cleanup\n");
-
-       cancel_delayed_work_sync(&conn->login_work);
-       conn->orig_state_change(sk);
-
-       iscsi_target_restore_sock_callbacks(conn);
-       iscsi_target_login_drop(conn, login);
-       iscsit_deaccess_np(np, tpg, tpg_np);
-
-       pr_debug("iscsi_target_do_cleanup done()\n");
-}
-
 static void iscsi_target_sk_state_change(struct sock *sk)
 {
        struct iscsi_conn *conn;
@@ -886,7 +864,8 @@ static int iscsi_target_handle_csg_zero(
                        SENDER_TARGET,
                        login->rsp_buf,
                        &login->rsp_length,
-                       conn->param_list);
+                       conn->param_list,
+                       conn->tpg->tpg_attrib.login_keys_workaround);
        if (ret < 0)
                return -1;
 
@@ -956,7 +935,8 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log
                        SENDER_TARGET,
                        login->rsp_buf,
                        &login->rsp_length,
-                       conn->param_list);
+                       conn->param_list,
+                       conn->tpg->tpg_attrib.login_keys_workaround);
        if (ret < 0) {
                iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
                                ISCSI_LOGIN_STATUS_INIT_ERR);
@@ -1082,7 +1062,6 @@ int iscsi_target_locate_portal(
        int sessiontype = 0, ret = 0, tag_num, tag_size;
 
        INIT_DELAYED_WORK(&conn->login_work, iscsi_target_do_login_rx);
-       INIT_DELAYED_WORK(&conn->login_cleanup_work, iscsi_target_do_cleanup);
        iscsi_target_set_sock_callbacks(conn);
 
        login->np = np;
@@ -1331,7 +1310,6 @@ int iscsi_target_start_negotiation(
 
        if (ret < 0) {
                cancel_delayed_work_sync(&conn->login_work);
-               cancel_delayed_work_sync(&conn->login_cleanup_work);
                iscsi_target_restore_sock_callbacks(conn);
                iscsi_remove_failed_auth_entry(conn);
        }
index fce6276..caab104 100644 (file)
@@ -765,7 +765,8 @@ static int iscsi_check_for_auth_key(char *key)
        return 0;
 }
 
-static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param)
+static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param,
+                                                   bool keys_workaround)
 {
        if (IS_TYPE_BOOL_AND(param)) {
                if (!strcmp(param->value, NO))
@@ -773,19 +774,31 @@ static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param)
        } else if (IS_TYPE_BOOL_OR(param)) {
                if (!strcmp(param->value, YES))
                        SET_PSTATE_REPLY_OPTIONAL(param);
-                /*
-                 * Required for gPXE iSCSI boot client
-                 */
-               if (!strcmp(param->name, IMMEDIATEDATA))
-                       SET_PSTATE_REPLY_OPTIONAL(param);
+
+               if (keys_workaround) {
+                       /*
+                        * Required for gPXE iSCSI boot client
+                        */
+                       if (!strcmp(param->name, IMMEDIATEDATA))
+                               SET_PSTATE_REPLY_OPTIONAL(param);
+               }
        } else if (IS_TYPE_NUMBER(param)) {
                if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH))
                        SET_PSTATE_REPLY_OPTIONAL(param);
-               /*
-                * Required for gPXE iSCSI boot client
-                */
-               if (!strcmp(param->name, MAXCONNECTIONS))
-                       SET_PSTATE_REPLY_OPTIONAL(param);
+
+               if (keys_workaround) {
+                       /*
+                        * Required for Mellanox Flexboot PXE boot ROM
+                        */
+                       if (!strcmp(param->name, FIRSTBURSTLENGTH))
+                               SET_PSTATE_REPLY_OPTIONAL(param);
+
+                       /*
+                        * Required for gPXE iSCSI boot client
+                        */
+                       if (!strcmp(param->name, MAXCONNECTIONS))
+                               SET_PSTATE_REPLY_OPTIONAL(param);
+               }
        } else if (IS_PHASE_DECLARATIVE(param))
                SET_PSTATE_REPLY_OPTIONAL(param);
 }
@@ -1422,7 +1435,8 @@ int iscsi_encode_text_output(
        u8 sender,
        char *textbuf,
        u32 *length,
-       struct iscsi_param_list *param_list)
+       struct iscsi_param_list *param_list,
+       bool keys_workaround)
 {
        char *output_buf = NULL;
        struct iscsi_extra_response *er;
@@ -1458,7 +1472,8 @@ int iscsi_encode_text_output(
                        *length += 1;
                        output_buf = textbuf + *length;
                        SET_PSTATE_PROPOSER(param);
-                       iscsi_check_proposer_for_optional_reply(param);
+                       iscsi_check_proposer_for_optional_reply(param,
+                                                               keys_workaround);
                        pr_debug("Sending key: %s=%s\n",
                                param->name, param->value);
                }
index 9962ccf..c47b73f 100644 (file)
@@ -46,7 +46,7 @@ extern int iscsi_extract_key_value(char *, char **, char **);
 extern int iscsi_update_param_value(struct iscsi_param *, char *);
 extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_conn *);
 extern int iscsi_encode_text_output(u8, u8, char *, u32 *,
-                       struct iscsi_param_list *);
+                       struct iscsi_param_list *, bool);
 extern int iscsi_check_negotiated_keys(struct iscsi_param_list *);
 extern void iscsi_set_connection_parameters(struct iscsi_conn_ops *,
                        struct iscsi_param_list *);
index 2e7e08d..594d07a 100644 (file)
@@ -227,6 +227,7 @@ static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg)
        a->t10_pi = TA_DEFAULT_T10_PI;
        a->fabric_prot_type = TA_DEFAULT_FABRIC_PROT_TYPE;
        a->tpg_enabled_sendtargets = TA_DEFAULT_TPG_ENABLED_SENDTARGETS;
+       a->login_keys_workaround = TA_DEFAULT_LOGIN_KEYS_WORKAROUND;
 }
 
 int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg)
@@ -311,11 +312,9 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg)
        struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
        int ret;
 
-       spin_lock(&tpg->tpg_state_lock);
        if (tpg->tpg_state == TPG_STATE_ACTIVE) {
                pr_err("iSCSI target portal group: %hu is already"
                        " active, ignoring request.\n", tpg->tpgt);
-               spin_unlock(&tpg->tpg_state_lock);
                return -EINVAL;
        }
        /*
@@ -324,10 +323,8 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg)
         * is enforced (as per default), and remove the NONE option.
         */
        param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list);
-       if (!param) {
-               spin_unlock(&tpg->tpg_state_lock);
+       if (!param)
                return -EINVAL;
-       }
 
        if (tpg->tpg_attrib.authentication) {
                if (!strcmp(param->value, NONE)) {
@@ -341,6 +338,7 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg)
                        goto err;
        }
 
+       spin_lock(&tpg->tpg_state_lock);
        tpg->tpg_state = TPG_STATE_ACTIVE;
        spin_unlock(&tpg->tpg_state_lock);
 
@@ -353,7 +351,6 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg)
        return 0;
 
 err:
-       spin_unlock(&tpg->tpg_state_lock);
        return ret;
 }
 
@@ -899,3 +896,21 @@ int iscsit_ta_tpg_enabled_sendtargets(
 
        return 0;
 }
+
+int iscsit_ta_login_keys_workaround(
+       struct iscsi_portal_group *tpg,
+       u32 flag)
+{
+       struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
+
+       if ((flag != 0) && (flag != 1)) {
+               pr_err("Illegal value %d\n", flag);
+               return -EINVAL;
+       }
+
+       a->login_keys_workaround = flag;
+       pr_debug("iSCSI_TPG[%hu] - TPG enabled bit for login keys workaround: %s ",
+               tpg->tpgt, (a->login_keys_workaround) ? "ON" : "OFF");
+
+       return 0;
+}
index ceba298..59fd3ca 100644 (file)
@@ -48,5 +48,6 @@ extern int iscsit_ta_default_erl(struct iscsi_portal_group *, u32);
 extern int iscsit_ta_t10_pi(struct iscsi_portal_group *, u32);
 extern int iscsit_ta_fabric_prot_type(struct iscsi_portal_group *, u32);
 extern int iscsit_ta_tpg_enabled_sendtargets(struct iscsi_portal_group *, u32);
+extern int iscsit_ta_login_keys_workaround(struct iscsi_portal_group *, u32);
 
 #endif /* ISCSI_TARGET_TPG_H */
index 7d3e2fc..1e36f83 100644 (file)
@@ -167,6 +167,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state)
 
        cmd->se_cmd.map_tag = tag;
        cmd->conn = conn;
+       cmd->data_direction = DMA_NONE;
        INIT_LIST_HEAD(&cmd->i_conn_node);
        INIT_LIST_HEAD(&cmd->datain_list);
        INIT_LIST_HEAD(&cmd->cmd_r2t_list);
@@ -711,19 +712,16 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
 }
 EXPORT_SYMBOL(iscsit_release_cmd);
 
-void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd,
-                      bool check_queues)
+void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool check_queues)
 {
        struct iscsi_conn *conn = cmd->conn;
 
-       if (scsi_cmd) {
-               if (cmd->data_direction == DMA_TO_DEVICE) {
-                       iscsit_stop_dataout_timer(cmd);
-                       iscsit_free_r2ts_from_list(cmd);
-               }
-               if (cmd->data_direction == DMA_FROM_DEVICE)
-                       iscsit_free_all_datain_reqs(cmd);
+       if (cmd->data_direction == DMA_TO_DEVICE) {
+               iscsit_stop_dataout_timer(cmd);
+               iscsit_free_r2ts_from_list(cmd);
        }
+       if (cmd->data_direction == DMA_FROM_DEVICE)
+               iscsit_free_all_datain_reqs(cmd);
 
        if (conn && check_queues) {
                iscsit_remove_cmd_from_immediate_queue(cmd, conn);
@@ -736,50 +734,18 @@ void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd,
 
 void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
 {
-       struct se_cmd *se_cmd = NULL;
+       struct se_cmd *se_cmd = cmd->se_cmd.se_tfo ? &cmd->se_cmd : NULL;
        int rc;
-       bool op_scsi = false;
-       /*
-        * Determine if a struct se_cmd is associated with
-        * this struct iscsi_cmd.
-        */
-       switch (cmd->iscsi_opcode) {
-       case ISCSI_OP_SCSI_CMD:
-               op_scsi = true;
-               /*
-                * Fallthrough
-                */
-       case ISCSI_OP_SCSI_TMFUNC:
-               se_cmd = &cmd->se_cmd;
-               __iscsit_free_cmd(cmd, op_scsi, shutdown);
+
+       __iscsit_free_cmd(cmd, shutdown);
+       if (se_cmd) {
                rc = transport_generic_free_cmd(se_cmd, shutdown);
                if (!rc && shutdown && se_cmd->se_sess) {
-                       __iscsit_free_cmd(cmd, op_scsi, shutdown);
+                       __iscsit_free_cmd(cmd, shutdown);
                        target_put_sess_cmd(se_cmd);
                }
-               break;
-       case ISCSI_OP_REJECT:
-               /*
-                * Handle special case for REJECT when iscsi_add_reject*() has
-                * overwritten the original iscsi_opcode assignment, and the
-                * associated cmd->se_cmd needs to be released.
-                */
-               if (cmd->se_cmd.se_tfo != NULL) {
-                       se_cmd = &cmd->se_cmd;
-                       __iscsit_free_cmd(cmd, true, shutdown);
-
-                       rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown);
-                       if (!rc && shutdown && se_cmd->se_sess) {
-                               __iscsit_free_cmd(cmd, true, shutdown);
-                               target_put_sess_cmd(se_cmd);
-                       }
-                       break;
-               }
-               /* Fall-through */
-       default:
-               __iscsit_free_cmd(cmd, false, shutdown);
+       } else {
                iscsit_release_cmd(cmd);
-               break;
        }
 }
 EXPORT_SYMBOL(iscsit_free_cmd);
index 9e4197a..4251605 100644 (file)
@@ -37,7 +37,7 @@ extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_co
 extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *);
 extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
 extern void iscsit_release_cmd(struct iscsi_cmd *);
-extern void __iscsit_free_cmd(struct iscsi_cmd *, bool, bool);
+extern void __iscsit_free_cmd(struct iscsi_cmd *, bool);
 extern void iscsit_free_cmd(struct iscsi_cmd *, bool);
 extern int iscsit_check_session_usage_count(struct iscsi_session *);
 extern void iscsit_dec_session_usage_count(struct iscsi_session *);
index 5091b31..b6a913e 100644 (file)
@@ -51,19 +51,7 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd);
  */
 static int tcm_loop_check_stop_free(struct se_cmd *se_cmd)
 {
-       /*
-        * Do not release struct se_cmd's containing a valid TMR
-        * pointer.  These will be released directly in tcm_loop_device_reset()
-        * with transport_generic_free_cmd().
-        */
-       if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
-               return 0;
-       /*
-        * Release the struct se_cmd, which will make a callback to release
-        * struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd()
-        */
-       transport_generic_free_cmd(se_cmd, 0);
-       return 1;
+       return transport_generic_free_cmd(se_cmd, 0);
 }
 
 static void tcm_loop_release_cmd(struct se_cmd *se_cmd)
@@ -218,10 +206,8 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg,
 {
        struct se_cmd *se_cmd = NULL;
        struct se_session *se_sess;
-       struct se_portal_group *se_tpg;
        struct tcm_loop_nexus *tl_nexus;
        struct tcm_loop_cmd *tl_cmd = NULL;
-       struct tcm_loop_tmr *tl_tmr = NULL;
        int ret = TMR_FUNCTION_FAILED, rc;
 
        /*
@@ -240,55 +226,29 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg,
                return ret;
        }
 
-       tl_tmr = kzalloc(sizeof(struct tcm_loop_tmr), GFP_KERNEL);
-       if (!tl_tmr) {
-               pr_err("Unable to allocate memory for tl_tmr\n");
-               goto release;
-       }
-       init_waitqueue_head(&tl_tmr->tl_tmr_wait);
+       init_completion(&tl_cmd->tmr_done);
 
        se_cmd = &tl_cmd->tl_se_cmd;
-       se_tpg = &tl_tpg->tl_se_tpg;
        se_sess = tl_tpg->tl_nexus->se_sess;
-       /*
-        * Initialize struct se_cmd descriptor from target_core_mod infrastructure
-        */
-       transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, 0,
-                               DMA_NONE, TCM_SIMPLE_TAG,
-                               &tl_cmd->tl_sense_buf[0]);
 
-       rc = core_tmr_alloc_req(se_cmd, tl_tmr, tmr, GFP_KERNEL);
+       rc = target_submit_tmr(se_cmd, se_sess, tl_cmd->tl_sense_buf, lun,
+                              NULL, tmr, GFP_KERNEL, task,
+                              TARGET_SCF_ACK_KREF);
        if (rc < 0)
                goto release;
+       wait_for_completion(&tl_cmd->tmr_done);
+       ret = se_cmd->se_tmr_req->response;
+       target_put_sess_cmd(se_cmd);
 
-       if (tmr == TMR_ABORT_TASK)
-               se_cmd->se_tmr_req->ref_task_tag = task;
+out:
+       return ret;
 
-       /*
-        * Locate the underlying TCM struct se_lun
-        */
-       if (transport_lookup_tmr_lun(se_cmd, lun) < 0) {
-               ret = TMR_LUN_DOES_NOT_EXIST;
-               goto release;
-       }
-       /*
-        * Queue the TMR to TCM Core and sleep waiting for
-        * tcm_loop_queue_tm_rsp() to wake us up.
-        */
-       transport_generic_handle_tmr(se_cmd);
-       wait_event(tl_tmr->tl_tmr_wait, atomic_read(&tl_tmr->tmr_complete));
-       /*
-        * The TMR LUN_RESET has completed, check the response status and
-        * then release allocations.
-        */
-       ret = se_cmd->se_tmr_req->response;
 release:
        if (se_cmd)
-               transport_generic_free_cmd(se_cmd, 1);
+               transport_generic_free_cmd(se_cmd, 0);
        else
                kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
-       kfree(tl_tmr);
-       return ret;
+       goto out;
 }
 
 static int tcm_loop_abort_task(struct scsi_cmnd *sc)
@@ -669,14 +629,11 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd)
 
 static void tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
 {
-       struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
-       struct tcm_loop_tmr *tl_tmr = se_tmr->fabric_tmr_ptr;
-       /*
-        * The SCSI EH thread will be sleeping on se_tmr->tl_tmr_wait, go ahead
-        * and wake up the wait_queue_head_t in tcm_loop_device_reset()
-        */
-       atomic_set(&tl_tmr->tmr_complete, 1);
-       wake_up(&tl_tmr->tl_tmr_wait);
+       struct tcm_loop_cmd *tl_cmd = container_of(se_cmd,
+                               struct tcm_loop_cmd, tl_se_cmd);
+
+       /* Wake up tcm_loop_issue_tmr(). */
+       complete(&tl_cmd->tmr_done);
 }
 
 static void tcm_loop_aborted_task(struct se_cmd *se_cmd)
index a8a230b..3acc43c 100644 (file)
@@ -16,15 +16,11 @@ struct tcm_loop_cmd {
        /* The TCM I/O descriptor that is accessed via container_of() */
        struct se_cmd tl_se_cmd;
        struct work_struct work;
+       struct completion tmr_done;
        /* Sense buffer that will be mapped into outgoing status */
        unsigned char tl_sense_buf[TRANSPORT_SENSE_BUFFER];
 };
 
-struct tcm_loop_tmr {
-       atomic_t tmr_complete;
-       wait_queue_head_t tl_tmr_wait;
-};
-
 struct tcm_loop_nexus {
        /*
         * Pointer to TCM session for I_T Nexus
index fc4a9c3..a91b7c2 100644 (file)
@@ -205,8 +205,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
                /*
                 * TARGET PORT GROUP
                 */
-               buf[off++] = ((tg_pt_gp->tg_pt_gp_id >> 8) & 0xff);
-               buf[off++] = (tg_pt_gp->tg_pt_gp_id & 0xff);
+               put_unaligned_be16(tg_pt_gp->tg_pt_gp_id, &buf[off]);
+               off += 2;
 
                off++; /* Skip over Reserved */
                /*
@@ -235,8 +235,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
                        /*
                         * Set RELATIVE TARGET PORT IDENTIFIER
                         */
-                       buf[off++] = ((lun->lun_rtpi >> 8) & 0xff);
-                       buf[off++] = (lun->lun_rtpi & 0xff);
+                       put_unaligned_be16(lun->lun_rtpi, &buf[off]);
+                       off += 2;
                        rd_len += 4;
                }
                spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
index 0326607..7e87d95 100644 (file)
@@ -1085,6 +1085,24 @@ static ssize_t block_size_store(struct config_item *item,
        return count;
 }
 
+static ssize_t alua_support_show(struct config_item *item, char *page)
+{
+       struct se_dev_attrib *da = to_attrib(item);
+       u8 flags = da->da_dev->transport->transport_flags;
+
+       return snprintf(page, PAGE_SIZE, "%d\n",
+                       flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA ? 0 : 1);
+}
+
+static ssize_t pgr_support_show(struct config_item *item, char *page)
+{
+       struct se_dev_attrib *da = to_attrib(item);
+       u8 flags = da->da_dev->transport->transport_flags;
+
+       return snprintf(page, PAGE_SIZE, "%d\n",
+                       flags & TRANSPORT_FLAG_PASSTHROUGH_PGR ? 0 : 1);
+}
+
 CONFIGFS_ATTR(, emulate_model_alias);
 CONFIGFS_ATTR(, emulate_dpo);
 CONFIGFS_ATTR(, emulate_fua_write);
@@ -1116,6 +1134,8 @@ CONFIGFS_ATTR(, unmap_granularity);
 CONFIGFS_ATTR(, unmap_granularity_alignment);
 CONFIGFS_ATTR(, unmap_zeroes_data);
 CONFIGFS_ATTR(, max_write_same_len);
+CONFIGFS_ATTR_RO(, alua_support);
+CONFIGFS_ATTR_RO(, pgr_support);
 
 /*
  * dev_attrib attributes for devices using the target core SBC/SPC
@@ -1154,6 +1174,8 @@ struct configfs_attribute *sbc_attrib_attrs[] = {
        &attr_unmap_granularity_alignment,
        &attr_unmap_zeroes_data,
        &attr_max_write_same_len,
+       &attr_alua_support,
+       &attr_pgr_support,
        NULL,
 };
 EXPORT_SYMBOL(sbc_attrib_attrs);
@@ -1168,6 +1190,8 @@ struct configfs_attribute *passthrough_attrib_attrs[] = {
        &attr_hw_block_size,
        &attr_hw_max_sectors,
        &attr_hw_queue_depth,
+       &attr_alua_support,
+       &attr_pgr_support,
        NULL,
 };
 EXPORT_SYMBOL(passthrough_attrib_attrs);
@@ -2236,7 +2260,11 @@ static void target_core_dev_release(struct config_item *item)
        target_free_device(dev);
 }
 
-static struct configfs_item_operations target_core_dev_item_ops = {
+/*
+ * Used in target_core_fabric_configfs.c to verify valid se_device symlink
+ * within target_fabric_port_link()
+ */
+struct configfs_item_operations target_core_dev_item_ops = {
        .release                = target_core_dev_release,
 };
 
index 8add07f..e8dd6da 100644 (file)
@@ -49,8 +49,9 @@
 #include "target_core_pr.h"
 #include "target_core_ua.h"
 
-DEFINE_MUTEX(g_device_mutex);
-LIST_HEAD(g_device_list);
+static DEFINE_MUTEX(device_mutex);
+static LIST_HEAD(device_list);
+static DEFINE_IDR(devices_idr);
 
 static struct se_hba *lun0_hba;
 /* not static, needed by tpg.c */
@@ -168,11 +169,20 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u64 unpacked_lun)
        rcu_read_lock();
        deve = target_nacl_find_deve(nacl, unpacked_lun);
        if (deve) {
-               se_cmd->se_lun = rcu_dereference(deve->se_lun);
                se_lun = rcu_dereference(deve->se_lun);
+
+               if (!percpu_ref_tryget_live(&se_lun->lun_ref)) {
+                       se_lun = NULL;
+                       goto out_unlock;
+               }
+
+               se_cmd->se_lun = rcu_dereference(deve->se_lun);
                se_cmd->pr_res_key = deve->pr_res_key;
                se_cmd->orig_fe_lun = unpacked_lun;
+               se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
+               se_cmd->lun_ref_active = true;
        }
+out_unlock:
        rcu_read_unlock();
 
        if (!se_lun) {
@@ -182,9 +192,6 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u64 unpacked_lun)
                        unpacked_lun);
                return -ENODEV;
        }
-       /*
-        * XXX: Add percpu se_lun->lun_ref reference count for TMR
-        */
        se_cmd->se_dev = rcu_dereference_raw(se_lun->lun_se_dev);
        se_tmr->tmr_dev = rcu_dereference_raw(se_lun->lun_se_dev);
 
@@ -756,19 +763,16 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
        if (!dev)
                return NULL;
 
-       dev->dev_link_magic = SE_DEV_LINK_MAGIC;
        dev->se_hba = hba;
        dev->transport = hba->backend->ops;
        dev->prot_length = sizeof(struct t10_pi_tuple);
        dev->hba_index = hba->hba_index;
 
-       INIT_LIST_HEAD(&dev->dev_list);
        INIT_LIST_HEAD(&dev->dev_sep_list);
        INIT_LIST_HEAD(&dev->dev_tmr_list);
        INIT_LIST_HEAD(&dev->delayed_cmd_list);
        INIT_LIST_HEAD(&dev->state_list);
        INIT_LIST_HEAD(&dev->qf_cmd_list);
-       INIT_LIST_HEAD(&dev->g_dev_node);
        spin_lock_init(&dev->execute_task_lock);
        spin_lock_init(&dev->delayed_cmd_lock);
        spin_lock_init(&dev->dev_reservation_lock);
@@ -851,7 +855,7 @@ bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
        attrib->unmap_granularity = q->limits.discard_granularity / block_size;
        attrib->unmap_granularity_alignment = q->limits.discard_alignment /
                                                                block_size;
-       attrib->unmap_zeroes_data = 0;
+       attrib->unmap_zeroes_data = (q->limits.max_write_zeroes_sectors);
        return true;
 }
 EXPORT_SYMBOL(target_configure_unmap_from_queue);
@@ -875,10 +879,79 @@ sector_t target_to_linux_sector(struct se_device *dev, sector_t lb)
 }
 EXPORT_SYMBOL(target_to_linux_sector);
 
+/**
+ * target_find_device - find a se_device by its dev_index
+ * @id: dev_index
+ * @do_depend: true if caller needs target_depend_item to be done
+ *
+ * If do_depend is true, the caller must do a target_undepend_item
+ * when finished using the device.
+ *
+ * If do_depend is false, the caller must be called in a configfs
+ * callback or during removal.
+ */
+struct se_device *target_find_device(int id, bool do_depend)
+{
+       struct se_device *dev;
+
+       mutex_lock(&device_mutex);
+       dev = idr_find(&devices_idr, id);
+       if (dev && do_depend && target_depend_item(&dev->dev_group.cg_item))
+               dev = NULL;
+       mutex_unlock(&device_mutex);
+       return dev;
+}
+EXPORT_SYMBOL(target_find_device);
+
+struct devices_idr_iter {
+       int (*fn)(struct se_device *dev, void *data);
+       void *data;
+};
+
+static int target_devices_idr_iter(int id, void *p, void *data)
+{
+       struct devices_idr_iter *iter = data;
+       struct se_device *dev = p;
+
+       /*
+        * We add the device early to the idr, so it can be used
+        * by backend modules during configuration. We do not want
+        * to allow other callers to access partially setup devices,
+        * so we skip them here.
+        */
+       if (!(dev->dev_flags & DF_CONFIGURED))
+               return 0;
+
+       return iter->fn(dev, iter->data);
+}
+
+/**
+ * target_for_each_device - iterate over configured devices
+ * @fn: iterator function
+ * @data: pointer to data that will be passed to fn
+ *
+ * fn must return 0 to continue looping over devices. non-zero will break
+ * from the loop and return that value to the caller.
+ */
+int target_for_each_device(int (*fn)(struct se_device *dev, void *data),
+                          void *data)
+{
+       struct devices_idr_iter iter;
+       int ret;
+
+       iter.fn = fn;
+       iter.data = data;
+
+       mutex_lock(&device_mutex);
+       ret = idr_for_each(&devices_idr, target_devices_idr_iter, &iter);
+       mutex_unlock(&device_mutex);
+       return ret;
+}
+
 int target_configure_device(struct se_device *dev)
 {
        struct se_hba *hba = dev->se_hba;
-       int ret;
+       int ret, id;
 
        if (dev->dev_flags & DF_CONFIGURED) {
                pr_err("se_dev->se_dev_ptr already set for storage"
@@ -886,9 +959,26 @@ int target_configure_device(struct se_device *dev)
                return -EEXIST;
        }
 
+       /*
+        * Add early so modules like tcmu can use during its
+        * configuration.
+        */
+       mutex_lock(&device_mutex);
+       /*
+        * Use cyclic to try and avoid collisions with devices
+        * that were recently removed.
+        */
+       id = idr_alloc_cyclic(&devices_idr, dev, 0, INT_MAX, GFP_KERNEL);
+       mutex_unlock(&device_mutex);
+       if (id < 0) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       dev->dev_index = id;
+
        ret = dev->transport->configure_device(dev);
        if (ret)
-               goto out;
+               goto out_free_index;
        /*
         * XXX: there is not much point to have two different values here..
         */
@@ -903,12 +993,11 @@ int target_configure_device(struct se_device *dev)
                                         dev->dev_attrib.hw_block_size);
        dev->dev_attrib.optimal_sectors = dev->dev_attrib.hw_max_sectors;
 
-       dev->dev_index = scsi_get_new_index(SCSI_DEVICE_INDEX);
        dev->creation_time = get_jiffies_64();
 
        ret = core_setup_alua(dev);
        if (ret)
-               goto out;
+               goto out_free_index;
 
        /*
         * Startup the struct se_device processing thread
@@ -946,16 +1035,16 @@ int target_configure_device(struct se_device *dev)
        hba->dev_count++;
        spin_unlock(&hba->device_lock);
 
-       mutex_lock(&g_device_mutex);
-       list_add_tail(&dev->g_dev_node, &g_device_list);
-       mutex_unlock(&g_device_mutex);
-
        dev->dev_flags |= DF_CONFIGURED;
 
        return 0;
 
 out_free_alua:
        core_alua_free_lu_gp_mem(dev);
+out_free_index:
+       mutex_lock(&device_mutex);
+       idr_remove(&devices_idr, dev->dev_index);
+       mutex_unlock(&device_mutex);
 out:
        se_release_vpd_for_dev(dev);
        return ret;
@@ -970,9 +1059,11 @@ void target_free_device(struct se_device *dev)
        if (dev->dev_flags & DF_CONFIGURED) {
                destroy_workqueue(dev->tmr_wq);
 
-               mutex_lock(&g_device_mutex);
-               list_del(&dev->g_dev_node);
-               mutex_unlock(&g_device_mutex);
+               dev->transport->destroy_device(dev);
+
+               mutex_lock(&device_mutex);
+               idr_remove(&devices_idr, dev->dev_index);
+               mutex_unlock(&device_mutex);
 
                spin_lock(&hba->device_lock);
                hba->dev_count--;
@@ -1087,19 +1178,19 @@ passthrough_parse_cdb(struct se_cmd *cmd,
              TRANSPORT_FLAG_PASSTHROUGH_PGR)) {
                if (cdb[0] == PERSISTENT_RESERVE_IN) {
                        cmd->execute_cmd = target_scsi3_emulate_pr_in;
-                       size = (cdb[7] << 8) + cdb[8];
+                       size = get_unaligned_be16(&cdb[7]);
                        return target_cmd_size_check(cmd, size);
                }
                if (cdb[0] == PERSISTENT_RESERVE_OUT) {
                        cmd->execute_cmd = target_scsi3_emulate_pr_out;
-                       size = (cdb[7] << 8) + cdb[8];
+                       size = get_unaligned_be32(&cdb[5]);
                        return target_cmd_size_check(cmd, size);
                }
 
                if (cdb[0] == RELEASE || cdb[0] == RELEASE_10) {
                        cmd->execute_cmd = target_scsi2_reservation_release;
                        if (cdb[0] == RELEASE_10)
-                               size = (cdb[7] << 8) | cdb[8];
+                               size = get_unaligned_be16(&cdb[7]);
                        else
                                size = cmd->data_length;
                        return target_cmd_size_check(cmd, size);
@@ -1107,7 +1198,7 @@ passthrough_parse_cdb(struct se_cmd *cmd,
                if (cdb[0] == RESERVE || cdb[0] == RESERVE_10) {
                        cmd->execute_cmd = target_scsi2_reservation_reserve;
                        if (cdb[0] == RESERVE_10)
-                               size = (cdb[7] << 8) | cdb[8];
+                               size = get_unaligned_be16(&cdb[7]);
                        else
                                size = cmd->data_length;
                        return target_cmd_size_check(cmd, size);
@@ -1126,7 +1217,7 @@ passthrough_parse_cdb(struct se_cmd *cmd,
        case WRITE_16:
        case WRITE_VERIFY:
        case WRITE_VERIFY_12:
-       case 0x8e: /* WRITE_VERIFY_16 */
+       case WRITE_VERIFY_16:
        case COMPARE_AND_WRITE:
        case XDWRITEREAD_10:
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
@@ -1135,7 +1226,7 @@ passthrough_parse_cdb(struct se_cmd *cmd,
                switch (get_unaligned_be16(&cdb[8])) {
                case READ_32:
                case WRITE_32:
-               case 0x0c: /* WRITE_VERIFY_32 */
+               case WRITE_VERIFY_32:
                case XDWRITEREAD_32:
                        cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
                        break;
index d1e6cab..e9e917c 100644 (file)
@@ -65,6 +65,8 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf)
        pr_debug("Setup generic %s\n", __stringify(_name));             \
 }
 
+static struct configfs_item_operations target_fabric_port_item_ops;
+
 /* Start of tfc_tpg_mappedlun_cit */
 
 static int target_fabric_mappedlun_link(
@@ -72,19 +74,20 @@ static int target_fabric_mappedlun_link(
        struct config_item *lun_ci)
 {
        struct se_dev_entry *deve;
-       struct se_lun *lun = container_of(to_config_group(lun_ci),
-                       struct se_lun, lun_group);
+       struct se_lun *lun;
        struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci),
                        struct se_lun_acl, se_lun_group);
        struct se_portal_group *se_tpg;
        struct config_item *nacl_ci, *tpg_ci, *tpg_ci_s, *wwn_ci, *wwn_ci_s;
        bool lun_access_ro;
 
-       if (lun->lun_link_magic != SE_LUN_LINK_MAGIC) {
-               pr_err("Bad lun->lun_link_magic, not a valid lun_ci pointer:"
-                       " %p to struct lun: %p\n", lun_ci, lun);
+       if (!lun_ci->ci_type ||
+           lun_ci->ci_type->ct_item_ops != &target_fabric_port_item_ops) {
+               pr_err("Bad lun_ci, not a valid lun_ci pointer: %p\n", lun_ci);
                return -EFAULT;
        }
+       lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group);
+
        /*
         * Ensure that the source port exists
         */
@@ -620,6 +623,8 @@ static struct configfs_attribute *target_fabric_port_attrs[] = {
        NULL,
 };
 
+extern struct configfs_item_operations target_core_dev_item_ops;
+
 static int target_fabric_port_link(
        struct config_item *lun_ci,
        struct config_item *se_dev_ci)
@@ -628,16 +633,16 @@ static int target_fabric_port_link(
        struct se_lun *lun = container_of(to_config_group(lun_ci),
                                struct se_lun, lun_group);
        struct se_portal_group *se_tpg;
-       struct se_device *dev =
-               container_of(to_config_group(se_dev_ci), struct se_device, dev_group);
+       struct se_device *dev;
        struct target_fabric_configfs *tf;
        int ret;
 
-       if (dev->dev_link_magic != SE_DEV_LINK_MAGIC) {
-               pr_err("Bad dev->dev_link_magic, not a valid se_dev_ci pointer:"
-                       " %p to struct se_device: %p\n", se_dev_ci, dev);
+       if (!se_dev_ci->ci_type ||
+           se_dev_ci->ci_type->ct_item_ops != &target_core_dev_item_ops) {
+               pr_err("Bad se_dev_ci, not a valid se_dev_ci pointer: %p\n", se_dev_ci);
                return -EFAULT;
        }
+       dev = container_of(to_config_group(se_dev_ci), struct se_device, dev_group);
 
        if (!(dev->dev_flags & DF_CONFIGURED)) {
                pr_err("se_device not configured yet, cannot port link\n");
index cb6497c..508da34 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/ctype.h>
 #include <linux/spinlock.h>
 #include <linux/export.h>
+#include <asm/unaligned.h>
 
 #include <scsi/scsi_proto.h>
 
@@ -216,8 +217,7 @@ static int iscsi_get_pr_transport_id(
        if (padding != 0)
                len += padding;
 
-       buf[2] = ((len >> 8) & 0xff);
-       buf[3] = (len & 0xff);
+       put_unaligned_be16(len, &buf[2]);
        /*
         * Increment value for total payload + header length for
         * full status descriptor
@@ -306,7 +306,7 @@ static char *iscsi_parse_pr_out_transport_id(
         */
        if (out_tid_len) {
                /* The shift works thanks to integer promotion rules */
-               add_len = (buf[2] << 8) | buf[3];
+               add_len = get_unaligned_be16(&buf[2]);
 
                tid_len = strlen(&buf[4]);
                tid_len += 4; /* Add four bytes for iSCSI Transport ID header */
index e921948..24cf11d 100644 (file)
@@ -237,13 +237,17 @@ static void fd_dev_call_rcu(struct rcu_head *p)
 
 static void fd_free_device(struct se_device *dev)
 {
+       call_rcu(&dev->rcu_head, fd_dev_call_rcu);
+}
+
+static void fd_destroy_device(struct se_device *dev)
+{
        struct fd_dev *fd_dev = FD_DEV(dev);
 
        if (fd_dev->fd_file) {
                filp_close(fd_dev->fd_file, NULL);
                fd_dev->fd_file = NULL;
        }
-       call_rcu(&dev->rcu_head, fd_dev_call_rcu);
 }
 
 static int fd_do_rw(struct se_cmd *cmd, struct file *fd,
@@ -826,6 +830,7 @@ static const struct target_backend_ops fileio_ops = {
        .detach_hba             = fd_detach_hba,
        .alloc_device           = fd_alloc_device,
        .configure_device       = fd_configure_device,
+       .destroy_device         = fd_destroy_device,
        .free_device            = fd_free_device,
        .parse_cdb              = fd_parse_cdb,
        .set_configfs_dev_params = fd_set_configfs_dev_params,
index c05d380..ee7c7fa 100644 (file)
@@ -86,6 +86,7 @@ static int iblock_configure_device(struct se_device *dev)
        struct block_device *bd = NULL;
        struct blk_integrity *bi;
        fmode_t mode;
+       unsigned int max_write_zeroes_sectors;
        int ret = -ENOMEM;
 
        if (!(ib_dev->ibd_flags & IBDF_HAS_UDEV_PATH)) {
@@ -129,7 +130,11 @@ static int iblock_configure_device(struct se_device *dev)
         * Enable write same emulation for IBLOCK and use 0xFFFF as
         * the smaller WRITE_SAME(10) only has a two-byte block count.
         */
-       dev->dev_attrib.max_write_same_len = 0xFFFF;
+       max_write_zeroes_sectors = bdev_write_zeroes_sectors(bd);
+       if (max_write_zeroes_sectors)
+               dev->dev_attrib.max_write_same_len = max_write_zeroes_sectors;
+       else
+               dev->dev_attrib.max_write_same_len = 0xFFFF;
 
        if (blk_queue_nonrot(q))
                dev->dev_attrib.is_nonrot = 1;
@@ -185,14 +190,17 @@ static void iblock_dev_call_rcu(struct rcu_head *p)
 
 static void iblock_free_device(struct se_device *dev)
 {
+       call_rcu(&dev->rcu_head, iblock_dev_call_rcu);
+}
+
+static void iblock_destroy_device(struct se_device *dev)
+{
        struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
 
        if (ib_dev->ibd_bd != NULL)
                blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
        if (ib_dev->ibd_bio_set != NULL)
                bioset_free(ib_dev->ibd_bio_set);
-
-       call_rcu(&dev->rcu_head, iblock_dev_call_rcu);
 }
 
 static unsigned long long iblock_emulate_read_cap_with_block_size(
@@ -415,28 +423,31 @@ iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb)
 }
 
 static sense_reason_t
-iblock_execute_write_same_direct(struct block_device *bdev, struct se_cmd *cmd)
+iblock_execute_zero_out(struct block_device *bdev, struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
        struct scatterlist *sg = &cmd->t_data_sg[0];
-       struct page *page = NULL;
-       int ret;
+       unsigned char *buf, zero = 0x00, *p = &zero;
+       int rc, ret;
 
-       if (sg->offset) {
-               page = alloc_page(GFP_KERNEL);
-               if (!page)
-                       return TCM_OUT_OF_RESOURCES;
-               sg_copy_to_buffer(sg, cmd->t_data_nents, page_address(page),
-                                 dev->dev_attrib.block_size);
-       }
+       buf = kmap(sg_page(sg)) + sg->offset;
+       if (!buf)
+               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+       /*
+        * Fall back to block_execute_write_same() slow-path if
+        * incoming WRITE_SAME payload does not contain zeros.
+        */
+       rc = memcmp(buf, p, cmd->data_length);
+       kunmap(sg_page(sg));
 
-       ret = blkdev_issue_write_same(bdev,
+       if (rc)
+               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+       ret = blkdev_issue_zeroout(bdev,
                                target_to_linux_sector(dev, cmd->t_task_lba),
                                target_to_linux_sector(dev,
                                        sbc_get_write_same_sectors(cmd)),
-                               GFP_KERNEL, page ? page : sg_page(sg));
-       if (page)
-               __free_page(page);
+                               GFP_KERNEL, false);
        if (ret)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
@@ -472,8 +483,10 @@ iblock_execute_write_same(struct se_cmd *cmd)
                return TCM_INVALID_CDB_FIELD;
        }
 
-       if (bdev_write_same(bdev))
-               return iblock_execute_write_same_direct(bdev, cmd);
+       if (bdev_write_zeroes_sectors(bdev)) {
+               if (!iblock_execute_zero_out(bdev, cmd))
+                       return 0;
+       }
 
        ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL);
        if (!ibr)
@@ -848,6 +861,7 @@ static const struct target_backend_ops iblock_ops = {
        .detach_hba             = iblock_detach_hba,
        .alloc_device           = iblock_alloc_device,
        .configure_device       = iblock_configure_device,
+       .destroy_device         = iblock_destroy_device,
        .free_device            = iblock_free_device,
        .parse_cdb              = iblock_parse_cdb,
        .set_configfs_dev_params = iblock_set_configfs_dev_params,
index 0912de7..f30e8ac 100644 (file)
@@ -56,9 +56,6 @@ struct target_fabric_configfs {
 extern struct t10_alua_lu_gp *default_lu_gp;
 
 /* target_core_device.c */
-extern struct mutex g_device_mutex;
-extern struct list_head g_device_list;
-
 int    core_alloc_rtpi(struct se_lun *lun, struct se_device *dev);
 struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
 void   target_pr_kref_release(struct kref *);
@@ -87,6 +84,8 @@ void  core_dev_release_virtual_lun0(void);
 struct se_device *target_alloc_device(struct se_hba *hba, const char *name);
 int    target_configure_device(struct se_device *dev);
 void   target_free_device(struct se_device *);
+int    target_for_each_device(int (*fn)(struct se_device *dev, void *data),
+                              void *data);
 
 /* target_core_configfs.c */
 void   target_setup_backend_cits(struct target_backend *);
index 129ca57..6d5def6 100644 (file)
@@ -1562,10 +1562,7 @@ core_scsi3_decode_spec_i_port(
         * first extract TransportID Parameter Data Length, and make sure
         * the value matches up to the SCSI expected data transfer length.
         */
-       tpdl = (buf[24] & 0xff) << 24;
-       tpdl |= (buf[25] & 0xff) << 16;
-       tpdl |= (buf[26] & 0xff) << 8;
-       tpdl |= buf[27] & 0xff;
+       tpdl = get_unaligned_be32(&buf[24]);
 
        if ((tpdl + 28) != cmd->data_length) {
                pr_err("SPC-3 PR: Illegal tpdl: %u + 28 byte header"
@@ -3221,12 +3218,8 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
                goto out_put_pr_reg;
        }
 
-       rtpi = (buf[18] & 0xff) << 8;
-       rtpi |= buf[19] & 0xff;
-       tid_len = (buf[20] & 0xff) << 24;
-       tid_len |= (buf[21] & 0xff) << 16;
-       tid_len |= (buf[22] & 0xff) << 8;
-       tid_len |= buf[23] & 0xff;
+       rtpi = get_unaligned_be16(&buf[18]);
+       tid_len = get_unaligned_be32(&buf[20]);
        transport_kunmap_data_sg(cmd);
        buf = NULL;
 
@@ -3552,16 +3545,6 @@ out_put_pr_reg:
        return ret;
 }
 
-static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb)
-{
-       unsigned int __v1, __v2;
-
-       __v1 = (cdb[0] << 24) | (cdb[1] << 16) | (cdb[2] << 8) | cdb[3];
-       __v2 = (cdb[4] << 24) | (cdb[5] << 16) | (cdb[6] << 8) | cdb[7];
-
-       return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
-}
-
 /*
  * See spc4r17 section 6.14 Table 170
  */
@@ -3602,7 +3585,7 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)
        if (cmd->data_length < 24) {
                pr_warn("SPC-PR: Received PR OUT parameter list"
                        " length too small: %u\n", cmd->data_length);
-               return TCM_INVALID_PARAMETER_LIST;
+               return TCM_PARAMETER_LIST_LENGTH_ERROR;
        }
 
        /*
@@ -3619,8 +3602,8 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)
        /*
         * From PERSISTENT_RESERVE_OUT parameter list (payload)
         */
-       res_key = core_scsi3_extract_reservation_key(&buf[0]);
-       sa_res_key = core_scsi3_extract_reservation_key(&buf[8]);
+       res_key = get_unaligned_be64(&buf[0]);
+       sa_res_key = get_unaligned_be64(&buf[8]);
        /*
         * REGISTER_AND_MOVE uses a different SA parameter list containing
         * SCSI TransportIDs.
@@ -3646,7 +3629,7 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)
        /*
         * SPEC_I_PT=1 is only valid for Service action: REGISTER
         */
-       if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER))
+       if (spec_i_pt && (sa != PRO_REGISTER))
                return TCM_INVALID_PARAMETER_LIST;
 
        /*
@@ -3658,11 +3641,11 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)
         * the sense key set to ILLEGAL REQUEST, and the additional sense
         * code set to PARAMETER LIST LENGTH ERROR.
         */
-       if (!spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER_AND_MOVE) &&
+       if (!spec_i_pt && (sa != PRO_REGISTER_AND_MOVE) &&
            (cmd->data_length != 24)) {
                pr_warn("SPC-PR: Received PR OUT illegal parameter"
                        " list length: %u\n", cmd->data_length);
-               return TCM_INVALID_PARAMETER_LIST;
+               return TCM_PARAMETER_LIST_LENGTH_ERROR;
        }
 
        /*
@@ -3702,7 +3685,7 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)
                break;
        default:
                pr_err("Unknown PERSISTENT_RESERVE_OUT service"
-                       " action: 0x%02x\n", cdb[1] & 0x1f);
+                       " action: 0x%02x\n", sa);
                return TCM_INVALID_CDB_FIELD;
        }
 
@@ -3734,10 +3717,7 @@ core_scsi3_pri_read_keys(struct se_cmd *cmd)
        if (!buf)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
-       buf[0] = ((dev->t10_pr.pr_generation >> 24) & 0xff);
-       buf[1] = ((dev->t10_pr.pr_generation >> 16) & 0xff);
-       buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff);
-       buf[3] = (dev->t10_pr.pr_generation & 0xff);
+       put_unaligned_be32(dev->t10_pr.pr_generation, buf);
 
        spin_lock(&dev->t10_pr.registration_lock);
        list_for_each_entry(pr_reg, &dev->t10_pr.registration_list,
@@ -3749,23 +3729,13 @@ core_scsi3_pri_read_keys(struct se_cmd *cmd)
                if ((add_len + 8) > (cmd->data_length - 8))
                        break;
 
-               buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff);
-               buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff);
-               buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff);
-               buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff);
-               buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff);
-               buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff);
-               buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff);
-               buf[off++] = (pr_reg->pr_res_key & 0xff);
-
+               put_unaligned_be64(pr_reg->pr_res_key, &buf[off]);
+               off += 8;
                add_len += 8;
        }
        spin_unlock(&dev->t10_pr.registration_lock);
 
-       buf[4] = ((add_len >> 24) & 0xff);
-       buf[5] = ((add_len >> 16) & 0xff);
-       buf[6] = ((add_len >> 8) & 0xff);
-       buf[7] = (add_len & 0xff);
+       put_unaligned_be32(add_len, &buf[4]);
 
        transport_kunmap_data_sg(cmd);
 
@@ -3796,10 +3766,7 @@ core_scsi3_pri_read_reservation(struct se_cmd *cmd)
        if (!buf)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
-       buf[0] = ((dev->t10_pr.pr_generation >> 24) & 0xff);
-       buf[1] = ((dev->t10_pr.pr_generation >> 16) & 0xff);
-       buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff);
-       buf[3] = (dev->t10_pr.pr_generation & 0xff);
+       put_unaligned_be32(dev->t10_pr.pr_generation, &buf[0]);
 
        spin_lock(&dev->dev_reservation_lock);
        pr_reg = dev->dev_pr_res_holder;
@@ -3807,10 +3774,7 @@ core_scsi3_pri_read_reservation(struct se_cmd *cmd)
                /*
                 * Set the hardcoded Additional Length
                 */
-               buf[4] = ((add_len >> 24) & 0xff);
-               buf[5] = ((add_len >> 16) & 0xff);
-               buf[6] = ((add_len >> 8) & 0xff);
-               buf[7] = (add_len & 0xff);
+               put_unaligned_be32(add_len, &buf[4]);
 
                if (cmd->data_length < 22)
                        goto err;
@@ -3837,14 +3801,7 @@ core_scsi3_pri_read_reservation(struct se_cmd *cmd)
                else
                        pr_res_key = pr_reg->pr_res_key;
 
-               buf[8] = ((pr_res_key >> 56) & 0xff);
-               buf[9] = ((pr_res_key >> 48) & 0xff);
-               buf[10] = ((pr_res_key >> 40) & 0xff);
-               buf[11] = ((pr_res_key >> 32) & 0xff);
-               buf[12] = ((pr_res_key >> 24) & 0xff);
-               buf[13] = ((pr_res_key >> 16) & 0xff);
-               buf[14] = ((pr_res_key >> 8) & 0xff);
-               buf[15] = (pr_res_key & 0xff);
+               put_unaligned_be64(pr_res_key, &buf[8]);
                /*
                 * Set the SCOPE and TYPE
                 */
@@ -3882,8 +3839,7 @@ core_scsi3_pri_report_capabilities(struct se_cmd *cmd)
        if (!buf)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
-       buf[0] = ((add_len >> 8) & 0xff);
-       buf[1] = (add_len & 0xff);
+       put_unaligned_be16(add_len, &buf[0]);
        buf[2] |= 0x10; /* CRH: Compatible Reservation Hanlding bit. */
        buf[2] |= 0x08; /* SIP_C: Specify Initiator Ports Capable bit */
        buf[2] |= 0x04; /* ATP_C: All Target Ports Capable bit */
@@ -3947,10 +3903,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
        if (!buf)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
-       buf[0] = ((dev->t10_pr.pr_generation >> 24) & 0xff);
-       buf[1] = ((dev->t10_pr.pr_generation >> 16) & 0xff);
-       buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff);
-       buf[3] = (dev->t10_pr.pr_generation & 0xff);
+       put_unaligned_be32(dev->t10_pr.pr_generation, &buf[0]);
 
        spin_lock(&dev->dev_reservation_lock);
        if (dev->dev_pr_res_holder) {
@@ -3992,14 +3945,8 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
                /*
                 * Set RESERVATION KEY
                 */
-               buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff);
-               buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff);
-               buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff);
-               buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff);
-               buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff);
-               buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff);
-               buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff);
-               buf[off++] = (pr_reg->pr_res_key & 0xff);
+               put_unaligned_be64(pr_reg->pr_res_key, &buf[off]);
+               off += 8;
                off += 4; /* Skip Over Reserved area */
 
                /*
@@ -4041,8 +3988,8 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
                if (!pr_reg->pr_reg_all_tg_pt) {
                        u16 sep_rtpi = pr_reg->tg_pt_sep_rtpi;
 
-                       buf[off++] = ((sep_rtpi >> 8) & 0xff);
-                       buf[off++] = (sep_rtpi & 0xff);
+                       put_unaligned_be16(sep_rtpi, &buf[off]);
+                       off += 2;
                } else
                        off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFIER */
 
@@ -4062,10 +4009,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
                /*
                 * Set the ADDITIONAL DESCRIPTOR LENGTH
                 */
-               buf[off++] = ((desc_len >> 24) & 0xff);
-               buf[off++] = ((desc_len >> 16) & 0xff);
-               buf[off++] = ((desc_len >> 8) & 0xff);
-               buf[off++] = (desc_len & 0xff);
+               put_unaligned_be32(desc_len, &buf[off]);
                /*
                 * Size of full desctipor header minus TransportID
                 * containing $FABRIC_MOD specific) initiator device/port
@@ -4082,10 +4026,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
        /*
         * Set ADDITIONAL_LENGTH
         */
-       buf[4] = ((add_len >> 24) & 0xff);
-       buf[5] = ((add_len >> 16) & 0xff);
-       buf[6] = ((add_len >> 8) & 0xff);
-       buf[7] = (add_len & 0xff);
+       put_unaligned_be32(add_len, &buf[4]);
 
        transport_kunmap_data_sg(cmd);
 
index ceec021..7c69b4a 100644 (file)
@@ -168,7 +168,7 @@ static void pscsi_tape_read_blocksize(struct se_device *dev,
        /*
         * If MODE_SENSE still returns zero, set the default value to 1024.
         */
-       sdev->sector_size = (buf[9] << 16) | (buf[10] << 8) | (buf[11]);
+       sdev->sector_size = get_unaligned_be24(&buf[9]);
 out_free:
        if (!sdev->sector_size)
                sdev->sector_size = 1024;
@@ -209,8 +209,7 @@ pscsi_get_inquiry_vpd_serial(struct scsi_device *sdev, struct t10_wwn *wwn)
        cdb[0] = INQUIRY;
        cdb[1] = 0x01; /* Query VPD */
        cdb[2] = 0x80; /* Unit Serial Number */
-       cdb[3] = (INQUIRY_VPD_SERIAL_LEN >> 8) & 0xff;
-       cdb[4] = (INQUIRY_VPD_SERIAL_LEN & 0xff);
+       put_unaligned_be16(INQUIRY_VPD_SERIAL_LEN, &cdb[3]);
 
        ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf,
                              INQUIRY_VPD_SERIAL_LEN, NULL, HZ, 1, NULL);
@@ -245,8 +244,7 @@ pscsi_get_inquiry_vpd_device_ident(struct scsi_device *sdev,
        cdb[0] = INQUIRY;
        cdb[1] = 0x01; /* Query VPD */
        cdb[2] = 0x83; /* Device Identifier */
-       cdb[3] = (INQUIRY_VPD_DEVICE_IDENTIFIER_LEN >> 8) & 0xff;
-       cdb[4] = (INQUIRY_VPD_DEVICE_IDENTIFIER_LEN & 0xff);
+       put_unaligned_be16(INQUIRY_VPD_DEVICE_IDENTIFIER_LEN, &cdb[3]);
 
        ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf,
                              INQUIRY_VPD_DEVICE_IDENTIFIER_LEN,
@@ -254,7 +252,7 @@ pscsi_get_inquiry_vpd_device_ident(struct scsi_device *sdev,
        if (ret)
                goto out;
 
-       page_len = (buf[2] << 8) | buf[3];
+       page_len = get_unaligned_be16(&buf[2]);
        while (page_len > 0) {
                /* Grab a pointer to the Identification descriptor */
                page_83 = &buf[off];
@@ -384,7 +382,7 @@ static int pscsi_create_type_disk(struct se_device *dev, struct scsi_device *sd)
        spin_unlock_irq(sh->host_lock);
        /*
         * Claim exclusive struct block_device access to struct scsi_device
-        * for TYPE_DISK using supplied udev_path
+        * for TYPE_DISK and TYPE_ZBC using supplied udev_path
         */
        bd = blkdev_get_by_path(dev->udev_path,
                                FMODE_WRITE|FMODE_READ|FMODE_EXCL, pdv);
@@ -402,8 +400,9 @@ static int pscsi_create_type_disk(struct se_device *dev, struct scsi_device *sd)
                return ret;
        }
 
-       pr_debug("CORE_PSCSI[%d] - Added TYPE_DISK for %d:%d:%d:%llu\n",
-               phv->phv_host_id, sh->host_no, sd->channel, sd->id, sd->lun);
+       pr_debug("CORE_PSCSI[%d] - Added TYPE_%s for %d:%d:%d:%llu\n",
+               phv->phv_host_id, sd->type == TYPE_DISK ? "DISK" : "ZBC",
+               sh->host_no, sd->channel, sd->id, sd->lun);
        return 0;
 }
 
@@ -522,6 +521,7 @@ static int pscsi_configure_device(struct se_device *dev)
                 */
                switch (sd->type) {
                case TYPE_DISK:
+               case TYPE_ZBC:
                        ret = pscsi_create_type_disk(dev, sd);
                        break;
                default:
@@ -566,6 +566,11 @@ static void pscsi_dev_call_rcu(struct rcu_head *p)
 
 static void pscsi_free_device(struct se_device *dev)
 {
+       call_rcu(&dev->rcu_head, pscsi_dev_call_rcu);
+}
+
+static void pscsi_destroy_device(struct se_device *dev)
+{
        struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);
        struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr;
        struct scsi_device *sd = pdv->pdv_sd;
@@ -573,9 +578,11 @@ static void pscsi_free_device(struct se_device *dev)
        if (sd) {
                /*
                 * Release exclusive pSCSI internal struct block_device claim for
-                * struct scsi_device with TYPE_DISK from pscsi_create_type_disk()
+                * struct scsi_device with TYPE_DISK or TYPE_ZBC
+                * from pscsi_create_type_disk()
                 */
-               if ((sd->type == TYPE_DISK) && pdv->pdv_bd) {
+               if ((sd->type == TYPE_DISK || sd->type == TYPE_ZBC) &&
+                   pdv->pdv_bd) {
                        blkdev_put(pdv->pdv_bd,
                                   FMODE_WRITE|FMODE_READ|FMODE_EXCL);
                        pdv->pdv_bd = NULL;
@@ -594,15 +601,13 @@ static void pscsi_free_device(struct se_device *dev)
 
                pdv->pdv_sd = NULL;
        }
-       call_rcu(&dev->rcu_head, pscsi_dev_call_rcu);
 }
 
-static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg,
-                                    unsigned char *sense_buffer)
+static void pscsi_complete_cmd(struct se_cmd *cmd, u8 scsi_status,
+                              unsigned char *req_sense)
 {
        struct pscsi_dev_virt *pdv = PSCSI_DEV(cmd->se_dev);
        struct scsi_device *sd = pdv->pdv_sd;
-       int result;
        struct pscsi_plugin_task *pt = cmd->priv;
        unsigned char *cdb;
        /*
@@ -613,7 +618,6 @@ static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg,
                return;
 
        cdb = &pt->pscsi_cdb[0];
-       result = pt->pscsi_result;
        /*
         * Hack to make sure that Write-Protect modepage is set if R/O mode is
         * forced.
@@ -622,7 +626,7 @@ static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg,
                goto after_mode_sense;
 
        if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) &&
-            (status_byte(result) << 1) == SAM_STAT_GOOD) {
+           scsi_status == SAM_STAT_GOOD) {
                bool read_only = target_lun_is_rdonly(cmd);
 
                if (read_only) {
@@ -657,40 +661,36 @@ after_mode_sense:
         * storage engine.
         */
        if (((cdb[0] == MODE_SELECT) || (cdb[0] == MODE_SELECT_10)) &&
-             (status_byte(result) << 1) == SAM_STAT_GOOD) {
+            scsi_status == SAM_STAT_GOOD) {
                unsigned char *buf;
                u16 bdl;
                u32 blocksize;
 
-               buf = sg_virt(&sg[0]);
+               buf = sg_virt(&cmd->t_data_sg[0]);
                if (!buf) {
                        pr_err("Unable to get buf for scatterlist\n");
                        goto after_mode_select;
                }
 
                if (cdb[0] == MODE_SELECT)
-                       bdl = (buf[3]);
+                       bdl = buf[3];
                else
-                       bdl = (buf[6] << 8) | (buf[7]);
+                       bdl = get_unaligned_be16(&buf[6]);
 
                if (!bdl)
                        goto after_mode_select;
 
                if (cdb[0] == MODE_SELECT)
-                       blocksize = (buf[9] << 16) | (buf[10] << 8) |
-                                       (buf[11]);
+                       blocksize = get_unaligned_be24(&buf[9]);
                else
-                       blocksize = (buf[13] << 16) | (buf[14] << 8) |
-                                       (buf[15]);
+                       blocksize = get_unaligned_be24(&buf[13]);
 
                sd->sector_size = blocksize;
        }
 after_mode_select:
 
-       if (sense_buffer && (status_byte(result) & CHECK_CONDITION)) {
-               memcpy(sense_buffer, pt->pscsi_sense, TRANSPORT_SENSE_BUFFER);
-               cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE;
-       }
+       if (scsi_status == SAM_STAT_CHECK_CONDITION)
+               transport_copy_sense_to_cmd(cmd, req_sense);
 }
 
 enum {
@@ -1002,7 +1002,8 @@ pscsi_execute_cmd(struct se_cmd *cmd)
        req->end_io_data = cmd;
        scsi_req(req)->cmd_len = scsi_command_size(pt->pscsi_cdb);
        scsi_req(req)->cmd = &pt->pscsi_cdb[0];
-       if (pdv->pdv_sd->type == TYPE_DISK)
+       if (pdv->pdv_sd->type == TYPE_DISK ||
+           pdv->pdv_sd->type == TYPE_ZBC)
                req->timeout = PS_TIMEOUT_DISK;
        else
                req->timeout = PS_TIMEOUT_OTHER;
@@ -1047,30 +1048,29 @@ static void pscsi_req_done(struct request *req, blk_status_t status)
 {
        struct se_cmd *cmd = req->end_io_data;
        struct pscsi_plugin_task *pt = cmd->priv;
+       int result = scsi_req(req)->result;
+       u8 scsi_status = status_byte(result) << 1;
 
-       pt->pscsi_result = scsi_req(req)->result;
-       pt->pscsi_resid = scsi_req(req)->resid_len;
-
-       cmd->scsi_status = status_byte(pt->pscsi_result) << 1;
-       if (cmd->scsi_status) {
+       if (scsi_status) {
                pr_debug("PSCSI Status Byte exception at cmd: %p CDB:"
                        " 0x%02x Result: 0x%08x\n", cmd, pt->pscsi_cdb[0],
-                       pt->pscsi_result);
+                       result);
        }
 
-       switch (host_byte(pt->pscsi_result)) {
+       pscsi_complete_cmd(cmd, scsi_status, scsi_req(req)->sense);
+
+       switch (host_byte(result)) {
        case DID_OK:
-               target_complete_cmd(cmd, cmd->scsi_status);
+               target_complete_cmd(cmd, scsi_status);
                break;
        default:
                pr_debug("PSCSI Host Byte exception at cmd: %p CDB:"
                        " 0x%02x Result: 0x%08x\n", cmd, pt->pscsi_cdb[0],
-                       pt->pscsi_result);
+                       result);
                target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION);
                break;
        }
 
-       memcpy(pt->pscsi_sense, scsi_req(req)->sense, TRANSPORT_SENSE_BUFFER);
        __blk_put_request(req->q, req);
        kfree(pt);
 }
@@ -1086,8 +1086,8 @@ static const struct target_backend_ops pscsi_ops = {
        .pmode_enable_hba       = pscsi_pmode_enable_hba,
        .alloc_device           = pscsi_alloc_device,
        .configure_device       = pscsi_configure_device,
+       .destroy_device         = pscsi_destroy_device,
        .free_device            = pscsi_free_device,
-       .transport_complete     = pscsi_transport_complete,
        .parse_cdb              = pscsi_parse_cdb,
        .set_configfs_dev_params = pscsi_set_configfs_dev_params,
        .show_configfs_dev_params = pscsi_show_configfs_dev_params,
index 8a02fa4..b86fb0e 100644 (file)
@@ -23,10 +23,6 @@ struct scsi_device;
 struct Scsi_Host;
 
 struct pscsi_plugin_task {
-       unsigned char pscsi_sense[TRANSPORT_SENSE_BUFFER];
-       int     pscsi_direction;
-       int     pscsi_result;
-       u32     pscsi_resid;
        unsigned char pscsi_cdb[0];
 } ____cacheline_aligned;
 
index 20253d0..a6e8106 100644 (file)
@@ -339,10 +339,14 @@ static void rd_dev_call_rcu(struct rcu_head *p)
 
 static void rd_free_device(struct se_device *dev)
 {
+       call_rcu(&dev->rcu_head, rd_dev_call_rcu);
+}
+
+static void rd_destroy_device(struct se_device *dev)
+{
        struct rd_dev *rd_dev = RD_DEV(dev);
 
        rd_release_device_space(rd_dev);
-       call_rcu(&dev->rcu_head, rd_dev_call_rcu);
 }
 
 static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
@@ -554,7 +558,7 @@ static ssize_t rd_set_configfs_dev_params(struct se_device *dev,
        struct rd_dev *rd_dev = RD_DEV(dev);
        char *orig, *ptr, *opts;
        substring_t args[MAX_OPT_ARGS];
-       int ret = 0, arg, token;
+       int arg, token;
 
        opts = kstrdup(page, GFP_KERNEL);
        if (!opts)
@@ -589,7 +593,7 @@ static ssize_t rd_set_configfs_dev_params(struct se_device *dev,
        }
 
        kfree(orig);
-       return (!ret) ? count : ret;
+       return count;
 }
 
 static ssize_t rd_show_configfs_dev_params(struct se_device *dev, char *b)
@@ -651,6 +655,7 @@ static const struct target_backend_ops rd_mcp_ops = {
        .detach_hba             = rd_detach_hba,
        .alloc_device           = rd_alloc_device,
        .configure_device       = rd_configure_device,
+       .destroy_device         = rd_destroy_device,
        .free_device            = rd_free_device,
        .parse_cdb              = rd_parse_cdb,
        .set_configfs_dev_params = rd_set_configfs_dev_params,
index dc9456e..750a04e 100644 (file)
@@ -71,14 +71,8 @@ sbc_emulate_readcapacity(struct se_cmd *cmd)
        else
                blocks = (u32)blocks_long;
 
-       buf[0] = (blocks >> 24) & 0xff;
-       buf[1] = (blocks >> 16) & 0xff;
-       buf[2] = (blocks >> 8) & 0xff;
-       buf[3] = blocks & 0xff;
-       buf[4] = (dev->dev_attrib.block_size >> 24) & 0xff;
-       buf[5] = (dev->dev_attrib.block_size >> 16) & 0xff;
-       buf[6] = (dev->dev_attrib.block_size >> 8) & 0xff;
-       buf[7] = dev->dev_attrib.block_size & 0xff;
+       put_unaligned_be32(blocks, &buf[0]);
+       put_unaligned_be32(dev->dev_attrib.block_size, &buf[4]);
 
        rbuf = transport_kmap_data_sg(cmd);
        if (rbuf) {
@@ -102,18 +96,8 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
        unsigned long long blocks = dev->transport->get_blocks(dev);
 
        memset(buf, 0, sizeof(buf));
-       buf[0] = (blocks >> 56) & 0xff;
-       buf[1] = (blocks >> 48) & 0xff;
-       buf[2] = (blocks >> 40) & 0xff;
-       buf[3] = (blocks >> 32) & 0xff;
-       buf[4] = (blocks >> 24) & 0xff;
-       buf[5] = (blocks >> 16) & 0xff;
-       buf[6] = (blocks >> 8) & 0xff;
-       buf[7] = blocks & 0xff;
-       buf[8] = (dev->dev_attrib.block_size >> 24) & 0xff;
-       buf[9] = (dev->dev_attrib.block_size >> 16) & 0xff;
-       buf[10] = (dev->dev_attrib.block_size >> 8) & 0xff;
-       buf[11] = dev->dev_attrib.block_size & 0xff;
+       put_unaligned_be64(blocks, &buf[0]);
+       put_unaligned_be32(dev->dev_attrib.block_size, &buf[8]);
        /*
         * Set P_TYPE and PROT_EN bits for DIF support
         */
@@ -134,8 +118,8 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
 
        if (dev->transport->get_alignment_offset_lbas) {
                u16 lalba = dev->transport->get_alignment_offset_lbas(dev);
-               buf[14] = (lalba >> 8) & 0x3f;
-               buf[15] = lalba & 0xff;
+
+               put_unaligned_be16(lalba, &buf[14]);
        }
 
        /*
@@ -262,18 +246,17 @@ static inline u32 transport_get_sectors_6(unsigned char *cdb)
 
 static inline u32 transport_get_sectors_10(unsigned char *cdb)
 {
-       return (u32)(cdb[7] << 8) + cdb[8];
+       return get_unaligned_be16(&cdb[7]);
 }
 
 static inline u32 transport_get_sectors_12(unsigned char *cdb)
 {
-       return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9];
+       return get_unaligned_be32(&cdb[6]);
 }
 
 static inline u32 transport_get_sectors_16(unsigned char *cdb)
 {
-       return (u32)(cdb[10] << 24) + (cdb[11] << 16) +
-                   (cdb[12] << 8) + cdb[13];
+       return get_unaligned_be32(&cdb[10]);
 }
 
 /*
@@ -281,29 +264,23 @@ static inline u32 transport_get_sectors_16(unsigned char *cdb)
  */
 static inline u32 transport_get_sectors_32(unsigned char *cdb)
 {
-       return (u32)(cdb[28] << 24) + (cdb[29] << 16) +
-                   (cdb[30] << 8) + cdb[31];
+       return get_unaligned_be32(&cdb[28]);
 
 }
 
 static inline u32 transport_lba_21(unsigned char *cdb)
 {
-       return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3];
+       return get_unaligned_be24(&cdb[1]) & 0x1fffff;
 }
 
 static inline u32 transport_lba_32(unsigned char *cdb)
 {
-       return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
+       return get_unaligned_be32(&cdb[2]);
 }
 
 static inline unsigned long long transport_lba_64(unsigned char *cdb)
 {
-       unsigned int __v1, __v2;
-
-       __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
-       __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
-
-       return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+       return get_unaligned_be64(&cdb[2]);
 }
 
 /*
@@ -311,12 +288,7 @@ static inline unsigned long long transport_lba_64(unsigned char *cdb)
  */
 static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)
 {
-       unsigned int __v1, __v2;
-
-       __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15];
-       __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19];
-
-       return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+       return get_unaligned_be64(&cdb[12]);
 }
 
 static sense_reason_t
@@ -1005,6 +977,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                break;
        }
        case COMPARE_AND_WRITE:
+               if (!dev->dev_attrib.emulate_caw) {
+                       pr_err_ratelimited("se_device %s/%s (vpd_unit_serial %s) reject"
+                               " COMPARE_AND_WRITE\n", dev->se_hba->backend->ops->name,
+                               dev->dev_group.cg_item.ci_name, dev->t10_wwn.unit_serial);
+                       return TCM_UNSUPPORTED_SCSI_OPCODE;
+               }
                sectors = cdb[13];
                /*
                 * Currently enforce COMPARE_AND_WRITE for a single sector
@@ -1045,8 +1023,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                                cmd->t_task_cdb[1] & 0x1f);
                        return TCM_INVALID_CDB_FIELD;
                }
-               size = (cdb[10] << 24) | (cdb[11] << 16) |
-                      (cdb[12] << 8) | cdb[13];
+               size = get_unaligned_be32(&cdb[10]);
                break;
        case SYNCHRONIZE_CACHE:
        case SYNCHRONIZE_CACHE_16:
index 2a91ed3..cb0461a 100644 (file)
@@ -287,8 +287,8 @@ check_t10_vend_desc:
                /* Skip over Obsolete field in RTPI payload
                 * in Table 472 */
                off += 2;
-               buf[off++] = ((lun->lun_rtpi >> 8) & 0xff);
-               buf[off++] = (lun->lun_rtpi & 0xff);
+               put_unaligned_be16(lun->lun_rtpi, &buf[off]);
+               off += 2;
                len += 8; /* Header size + Designation descriptor */
                /*
                 * Target port group identifier, see spc4r17
@@ -316,8 +316,8 @@ check_t10_vend_desc:
                off++; /* Skip over Reserved */
                buf[off++] = 4; /* DESIGNATOR LENGTH */
                off += 2; /* Skip over Reserved Field */
-               buf[off++] = ((tg_pt_gp_id >> 8) & 0xff);
-               buf[off++] = (tg_pt_gp_id & 0xff);
+               put_unaligned_be16(tg_pt_gp_id, &buf[off]);
+               off += 2;
                len += 8; /* Header size + Designation descriptor */
                /*
                 * Logical Unit Group identifier, see spc4r17
@@ -343,8 +343,8 @@ check_lu_gp:
                off++; /* Skip over Reserved */
                buf[off++] = 4; /* DESIGNATOR LENGTH */
                off += 2; /* Skip over Reserved Field */
-               buf[off++] = ((lu_gp_id >> 8) & 0xff);
-               buf[off++] = (lu_gp_id & 0xff);
+               put_unaligned_be16(lu_gp_id, &buf[off]);
+               off += 2;
                len += 8; /* Header size + Designation descriptor */
                /*
                 * SCSI name string designator, see spc4r17
@@ -431,8 +431,7 @@ check_scsi_name:
                /* Header size + Designation descriptor */
                len += (scsi_target_len + 4);
        }
-       buf[2] = ((len >> 8) & 0xff);
-       buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */
+       put_unaligned_be16(len, &buf[2]); /* Page Length for VPD 0x83 */
        return 0;
 }
 EXPORT_SYMBOL(spc_emulate_evpd_83);
@@ -1288,7 +1287,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
                cmd->execute_cmd = spc_emulate_modeselect;
                break;
        case MODE_SELECT_10:
-               *size = (cdb[7] << 8) + cdb[8];
+               *size = get_unaligned_be16(&cdb[7]);
                cmd->execute_cmd = spc_emulate_modeselect;
                break;
        case MODE_SENSE:
@@ -1296,25 +1295,25 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
                cmd->execute_cmd = spc_emulate_modesense;
                break;
        case MODE_SENSE_10:
-               *size = (cdb[7] << 8) + cdb[8];
+               *size = get_unaligned_be16(&cdb[7]);
                cmd->execute_cmd = spc_emulate_modesense;
                break;
        case LOG_SELECT:
        case LOG_SENSE:
-               *size = (cdb[7] << 8) + cdb[8];
+               *size = get_unaligned_be16(&cdb[7]);
                break;
        case PERSISTENT_RESERVE_IN:
-               *size = (cdb[7] << 8) + cdb[8];
+               *size = get_unaligned_be16(&cdb[7]);
                cmd->execute_cmd = target_scsi3_emulate_pr_in;
                break;
        case PERSISTENT_RESERVE_OUT:
-               *size = (cdb[7] << 8) + cdb[8];
+               *size = get_unaligned_be32(&cdb[5]);
                cmd->execute_cmd = target_scsi3_emulate_pr_out;
                break;
        case RELEASE:
        case RELEASE_10:
                if (cdb[0] == RELEASE_10)
-                       *size = (cdb[7] << 8) | cdb[8];
+                       *size = get_unaligned_be16(&cdb[7]);
                else
                        *size = cmd->data_length;
 
@@ -1327,7 +1326,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
                 * Assume the passthrough or $FABRIC_MOD will tell us about it.
                 */
                if (cdb[0] == RESERVE_10)
-                       *size = (cdb[7] << 8) | cdb[8];
+                       *size = get_unaligned_be16(&cdb[7]);
                else
                        *size = cmd->data_length;
 
@@ -1338,7 +1337,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
                cmd->execute_cmd = spc_emulate_request_sense;
                break;
        case INQUIRY:
-               *size = (cdb[3] << 8) + cdb[4];
+               *size = get_unaligned_be16(&cdb[3]);
 
                /*
                 * Do implicit HEAD_OF_QUEUE processing for INQUIRY.
@@ -1349,7 +1348,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
                break;
        case SECURITY_PROTOCOL_IN:
        case SECURITY_PROTOCOL_OUT:
-               *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+               *size = get_unaligned_be32(&cdb[6]);
                break;
        case EXTENDED_COPY:
                *size = get_unaligned_be32(&cdb[10]);
@@ -1361,19 +1360,18 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
                break;
        case READ_ATTRIBUTE:
        case WRITE_ATTRIBUTE:
-               *size = (cdb[10] << 24) | (cdb[11] << 16) |
-                      (cdb[12] << 8) | cdb[13];
+               *size = get_unaligned_be32(&cdb[10]);
                break;
        case RECEIVE_DIAGNOSTIC:
        case SEND_DIAGNOSTIC:
-               *size = (cdb[3] << 8) | cdb[4];
+               *size = get_unaligned_be16(&cdb[3]);
                break;
        case WRITE_BUFFER:
-               *size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
+               *size = get_unaligned_be24(&cdb[6]);
                break;
        case REPORT_LUNS:
                cmd->execute_cmd = spc_emulate_report_luns;
-               *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+               *size = get_unaligned_be32(&cdb[6]);
                /*
                 * Do implicit HEAD_OF_QUEUE processing for REPORT_LUNS
                 * See spc4r17 section 5.3
index 13f47bf..e22847b 100644 (file)
@@ -355,20 +355,10 @@ static void core_tmr_drain_state_list(
                cmd = list_entry(drain_task_list.next, struct se_cmd, state_list);
                list_del_init(&cmd->state_list);
 
-               pr_debug("LUN_RESET: %s cmd: %p"
-                       " ITT/CmdSN: 0x%08llx/0x%08x, i_state: %d, t_state: %d"
-                       "cdb: 0x%02x\n",
-                       (preempt_and_abort_list) ? "Preempt" : "", cmd,
-                       cmd->tag, 0,
-                       cmd->se_tfo->get_cmd_state(cmd), cmd->t_state,
-                       cmd->t_task_cdb[0]);
-               pr_debug("LUN_RESET: ITT[0x%08llx] - pr_res_key: 0x%016Lx"
-                       " -- CMD_T_ACTIVE: %d"
-                       " CMD_T_STOP: %d CMD_T_SENT: %d\n",
-                       cmd->tag, cmd->pr_res_key,
-                       (cmd->transport_state & CMD_T_ACTIVE) != 0,
-                       (cmd->transport_state & CMD_T_STOP) != 0,
-                       (cmd->transport_state & CMD_T_SENT) != 0);
+               target_show_cmd("LUN_RESET: ", cmd);
+               pr_debug("LUN_RESET: ITT[0x%08llx] - %s pr_res_key: 0x%016Lx\n",
+                        cmd->tag, (preempt_and_abort_list) ? "preempt" : "",
+                        cmd->pr_res_key);
 
                /*
                 * If the command may be queued onto a workqueue cancel it now.
index 310d9e5..3691373 100644 (file)
@@ -576,7 +576,6 @@ struct se_lun *core_tpg_alloc_lun(
                return ERR_PTR(-ENOMEM);
        }
        lun->unpacked_lun = unpacked_lun;
-       lun->lun_link_magic = SE_LUN_LINK_MAGIC;
        atomic_set(&lun->lun_acl_count, 0);
        init_completion(&lun->lun_ref_comp);
        init_completion(&lun->lun_shutdown_comp);
index f1b3a46..97fed9a 100644 (file)
@@ -252,7 +252,7 @@ int transport_alloc_session_tags(struct se_session *se_sess,
        int rc;
 
        se_sess->sess_cmd_map = kzalloc(tag_num * tag_size,
-                                       GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
+                                       GFP_KERNEL | __GFP_NOWARN | __GFP_RETRY_MAYFAIL);
        if (!se_sess->sess_cmd_map) {
                se_sess->sess_cmd_map = vzalloc(tag_num * tag_size);
                if (!se_sess->sess_cmd_map) {
@@ -704,23 +704,43 @@ static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd)
        return cmd->sense_buffer;
 }
 
+void transport_copy_sense_to_cmd(struct se_cmd *cmd, unsigned char *sense)
+{
+       unsigned char *cmd_sense_buf;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cmd->t_state_lock, flags);
+       cmd_sense_buf = transport_get_sense_buffer(cmd);
+       if (!cmd_sense_buf) {
+               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+               return;
+       }
+
+       cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE;
+       memcpy(cmd_sense_buf, sense, cmd->scsi_sense_length);
+       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+}
+EXPORT_SYMBOL(transport_copy_sense_to_cmd);
+
 void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
 {
        struct se_device *dev = cmd->se_dev;
-       int success = scsi_status == GOOD;
+       int success;
        unsigned long flags;
 
        cmd->scsi_status = scsi_status;
 
-
        spin_lock_irqsave(&cmd->t_state_lock, flags);
-
-       if (dev && dev->transport->transport_complete) {
-               dev->transport->transport_complete(cmd,
-                               cmd->t_data_sg,
-                               transport_get_sense_buffer(cmd));
+       switch (cmd->scsi_status) {
+       case SAM_STAT_CHECK_CONDITION:
                if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE)
                        success = 1;
+               else
+                       success = 0;
+               break;
+       default:
+               success = 1;
+               break;
        }
 
        /*
@@ -730,6 +750,15 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
        if (cmd->transport_state & CMD_T_ABORTED ||
            cmd->transport_state & CMD_T_STOP) {
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+               /*
+                * If COMPARE_AND_WRITE was stopped by __transport_wait_for_tasks(),
+                * release se_device->caw_sem obtained by sbc_compare_and_write()
+                * since target_complete_ok_work() or target_complete_failure_work()
+                * won't be called to invoke the normal CAW completion callbacks.
+                */
+               if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) {
+                       up(&dev->caw_sem);
+               }
                complete_all(&cmd->t_transport_stop_comp);
                return;
        } else if (!success) {
@@ -1239,6 +1268,7 @@ void transport_init_se_cmd(
        init_completion(&cmd->t_transport_stop_comp);
        init_completion(&cmd->cmd_wait_comp);
        spin_lock_init(&cmd->t_state_lock);
+       INIT_WORK(&cmd->work, NULL);
        kref_init(&cmd->cmd_kref);
 
        cmd->se_tfo = tfo;
@@ -1590,9 +1620,33 @@ static void target_complete_tmr_failure(struct work_struct *work)
        se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST;
        se_cmd->se_tfo->queue_tm_rsp(se_cmd);
 
+       transport_lun_remove_cmd(se_cmd);
        transport_cmd_check_stop_to_fabric(se_cmd);
 }
 
+static bool target_lookup_lun_from_tag(struct se_session *se_sess, u64 tag,
+                                      u64 *unpacked_lun)
+{
+       struct se_cmd *se_cmd;
+       unsigned long flags;
+       bool ret = false;
+
+       spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
+       list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) {
+               if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
+                       continue;
+
+               if (se_cmd->tag == tag) {
+                       *unpacked_lun = se_cmd->orig_fe_lun;
+                       ret = true;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
+       return ret;
+}
+
 /**
  * target_submit_tmr - lookup unpacked lun and submit uninitialized se_cmd
  *                     for TMR CDBs
@@ -1640,19 +1694,31 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
                core_tmr_release_req(se_cmd->se_tmr_req);
                return ret;
        }
+       /*
+        * If this is ABORT_TASK with no explicit fabric provided LUN,
+        * go ahead and search active session tags for a match to figure
+        * out unpacked_lun for the original se_cmd.
+        */
+       if (tm_type == TMR_ABORT_TASK && (flags & TARGET_SCF_LOOKUP_LUN_FROM_TAG)) {
+               if (!target_lookup_lun_from_tag(se_sess, tag, &unpacked_lun))
+                       goto failure;
+       }
 
        ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun);
-       if (ret) {
-               /*
-                * For callback during failure handling, push this work off
-                * to process context with TMR_LUN_DOES_NOT_EXIST status.
-                */
-               INIT_WORK(&se_cmd->work, target_complete_tmr_failure);
-               schedule_work(&se_cmd->work);
-               return 0;
-       }
+       if (ret)
+               goto failure;
+
        transport_generic_handle_tmr(se_cmd);
        return 0;
+
+       /*
+        * For callback during failure handling, push this work off
+        * to process context with TMR_LUN_DOES_NOT_EXIST status.
+        */
+failure:
+       INIT_WORK(&se_cmd->work, target_complete_tmr_failure);
+       schedule_work(&se_cmd->work);
+       return 0;
 }
 EXPORT_SYMBOL(target_submit_tmr);
 
@@ -1667,15 +1733,9 @@ void transport_generic_request_failure(struct se_cmd *cmd,
        if (transport_check_aborted_status(cmd, 1))
                return;
 
-       pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08llx"
-               " CDB: 0x%02x\n", cmd, cmd->tag, cmd->t_task_cdb[0]);
-       pr_debug("-----[ i_state: %d t_state: %d sense_reason: %d\n",
-               cmd->se_tfo->get_cmd_state(cmd),
-               cmd->t_state, sense_reason);
-       pr_debug("-----[ CMD_T_ACTIVE: %d CMD_T_STOP: %d CMD_T_SENT: %d\n",
-               (cmd->transport_state & CMD_T_ACTIVE) != 0,
-               (cmd->transport_state & CMD_T_STOP) != 0,
-               (cmd->transport_state & CMD_T_SENT) != 0);
+       pr_debug("-----[ Storage Engine Exception; sense_reason %d\n",
+                sense_reason);
+       target_show_cmd("-----[ ", cmd);
 
        /*
         * For SAM Task Attribute emulation for failed struct se_cmd
@@ -2668,6 +2728,108 @@ int target_put_sess_cmd(struct se_cmd *se_cmd)
 }
 EXPORT_SYMBOL(target_put_sess_cmd);
 
+static const char *data_dir_name(enum dma_data_direction d)
+{
+       switch (d) {
+       case DMA_BIDIRECTIONAL: return "BIDI";
+       case DMA_TO_DEVICE:     return "WRITE";
+       case DMA_FROM_DEVICE:   return "READ";
+       case DMA_NONE:          return "NONE";
+       }
+
+       return "(?)";
+}
+
+static const char *cmd_state_name(enum transport_state_table t)
+{
+       switch (t) {
+       case TRANSPORT_NO_STATE:        return "NO_STATE";
+       case TRANSPORT_NEW_CMD:         return "NEW_CMD";
+       case TRANSPORT_WRITE_PENDING:   return "WRITE_PENDING";
+       case TRANSPORT_PROCESSING:      return "PROCESSING";
+       case TRANSPORT_COMPLETE:        return "COMPLETE";
+       case TRANSPORT_ISTATE_PROCESSING:
+                                       return "ISTATE_PROCESSING";
+       case TRANSPORT_COMPLETE_QF_WP:  return "COMPLETE_QF_WP";
+       case TRANSPORT_COMPLETE_QF_OK:  return "COMPLETE_QF_OK";
+       case TRANSPORT_COMPLETE_QF_ERR: return "COMPLETE_QF_ERR";
+       }
+
+       return "(?)";
+}
+
+static void target_append_str(char **str, const char *txt)
+{
+       char *prev = *str;
+
+       *str = *str ? kasprintf(GFP_ATOMIC, "%s,%s", *str, txt) :
+               kstrdup(txt, GFP_ATOMIC);
+       kfree(prev);
+}
+
+/*
+ * Convert a transport state bitmask into a string. The caller is
+ * responsible for freeing the returned pointer.
+ */
+static char *target_ts_to_str(u32 ts)
+{
+       char *str = NULL;
+
+       if (ts & CMD_T_ABORTED)
+               target_append_str(&str, "aborted");
+       if (ts & CMD_T_ACTIVE)
+               target_append_str(&str, "active");
+       if (ts & CMD_T_COMPLETE)
+               target_append_str(&str, "complete");
+       if (ts & CMD_T_SENT)
+               target_append_str(&str, "sent");
+       if (ts & CMD_T_STOP)
+               target_append_str(&str, "stop");
+       if (ts & CMD_T_FABRIC_STOP)
+               target_append_str(&str, "fabric_stop");
+
+       return str;
+}
+
+static const char *target_tmf_name(enum tcm_tmreq_table tmf)
+{
+       switch (tmf) {
+       case TMR_ABORT_TASK:            return "ABORT_TASK";
+       case TMR_ABORT_TASK_SET:        return "ABORT_TASK_SET";
+       case TMR_CLEAR_ACA:             return "CLEAR_ACA";
+       case TMR_CLEAR_TASK_SET:        return "CLEAR_TASK_SET";
+       case TMR_LUN_RESET:             return "LUN_RESET";
+       case TMR_TARGET_WARM_RESET:     return "TARGET_WARM_RESET";
+       case TMR_TARGET_COLD_RESET:     return "TARGET_COLD_RESET";
+       case TMR_UNKNOWN:               break;
+       }
+       return "(?)";
+}
+
+void target_show_cmd(const char *pfx, struct se_cmd *cmd)
+{
+       char *ts_str = target_ts_to_str(cmd->transport_state);
+       const u8 *cdb = cmd->t_task_cdb;
+       struct se_tmr_req *tmf = cmd->se_tmr_req;
+
+       if (!(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
+               pr_debug("%scmd %#02x:%#02x with tag %#llx dir %s i_state %d t_state %s len %d refcnt %d transport_state %s\n",
+                        pfx, cdb[0], cdb[1], cmd->tag,
+                        data_dir_name(cmd->data_direction),
+                        cmd->se_tfo->get_cmd_state(cmd),
+                        cmd_state_name(cmd->t_state), cmd->data_length,
+                        kref_read(&cmd->cmd_kref), ts_str);
+       } else {
+               pr_debug("%stmf %s with tag %#llx ref_task_tag %#llx i_state %d t_state %s refcnt %d transport_state %s\n",
+                        pfx, target_tmf_name(tmf->function), cmd->tag,
+                        tmf->ref_task_tag, cmd->se_tfo->get_cmd_state(cmd),
+                        cmd_state_name(cmd->t_state),
+                        kref_read(&cmd->cmd_kref), ts_str);
+       }
+       kfree(ts_str);
+}
+EXPORT_SYMBOL(target_show_cmd);
+
 /* target_sess_cmd_list_set_waiting - Flag all commands in
  *         sess_cmd_list to complete cmd_wait_comp.  Set
  *         sess_tearing_down so no more commands are queued.
@@ -2812,13 +2974,13 @@ __transport_wait_for_tasks(struct se_cmd *cmd, bool fabric_stop,
 
        cmd->transport_state |= CMD_T_STOP;
 
-       pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d,"
-                " t_state: %d, CMD_T_STOP\n", cmd, cmd->tag,
-                cmd->se_tfo->get_cmd_state(cmd), cmd->t_state);
+       target_show_cmd("wait_for_tasks: Stopping ", cmd);
 
        spin_unlock_irqrestore(&cmd->t_state_lock, *flags);
 
-       wait_for_completion(&cmd->t_transport_stop_comp);
+       while (!wait_for_completion_timeout(&cmd->t_transport_stop_comp,
+                                           180 * HZ))
+               target_show_cmd("wait for tasks: ", cmd);
 
        spin_lock_irqsave(&cmd->t_state_lock, *flags);
        cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP);
@@ -3201,6 +3363,7 @@ static void target_tmr_work(struct work_struct *work)
        cmd->se_tfo->queue_tm_rsp(cmd);
 
 check_stop:
+       transport_lun_remove_cmd(cmd);
        transport_cmd_check_stop_to_fabric(cmd);
 }
 
@@ -3223,6 +3386,7 @@ int transport_generic_handle_tmr(
                pr_warn_ratelimited("handle_tmr caught CMD_T_ABORTED TMR %d"
                        "ref_tag: %llu tag: %llu\n", cmd->se_tmr_req->function,
                        cmd->se_tmr_req->ref_task_tag, cmd->tag);
+               transport_lun_remove_cmd(cmd);
                transport_cmd_check_stop_to_fabric(cmd);
                return 0;
        }
index beb5f09..80ee130 100644 (file)
@@ -87,6 +87,8 @@
 /* Default maximum of the global data blocks(512K * PAGE_SIZE) */
 #define TCMU_GLOBAL_MAX_BLOCKS (512 * 1024)
 
+static u8 tcmu_kern_cmd_reply_supported;
+
 static struct device *tcmu_root_device;
 
 struct tcmu_hba {
@@ -95,6 +97,13 @@ struct tcmu_hba {
 
 #define TCMU_CONFIG_LEN 256
 
+struct tcmu_nl_cmd {
+       /* wake up thread waiting for reply */
+       struct completion complete;
+       int cmd;
+       int status;
+};
+
 struct tcmu_dev {
        struct list_head node;
        struct kref kref;
@@ -135,6 +144,11 @@ struct tcmu_dev {
        struct timer_list timeout;
        unsigned int cmd_time_out;
 
+       spinlock_t nl_cmd_lock;
+       struct tcmu_nl_cmd curr_nl_cmd;
+       /* wake up threads waiting on curr_nl_cmd */
+       wait_queue_head_t nl_cmd_wq;
+
        char dev_config[TCMU_CONFIG_LEN];
 };
 
@@ -178,16 +192,128 @@ static const struct genl_multicast_group tcmu_mcgrps[] = {
        [TCMU_MCGRP_CONFIG] = { .name = "config", },
 };
 
+static struct nla_policy tcmu_attr_policy[TCMU_ATTR_MAX+1] = {
+       [TCMU_ATTR_DEVICE]      = { .type = NLA_STRING },
+       [TCMU_ATTR_MINOR]       = { .type = NLA_U32 },
+       [TCMU_ATTR_CMD_STATUS]  = { .type = NLA_S32 },
+       [TCMU_ATTR_DEVICE_ID]   = { .type = NLA_U32 },
+       [TCMU_ATTR_SUPP_KERN_CMD_REPLY] = { .type = NLA_U8 },
+};
+
+static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd)
+{
+       struct se_device *dev;
+       struct tcmu_dev *udev;
+       struct tcmu_nl_cmd *nl_cmd;
+       int dev_id, rc, ret = 0;
+       bool is_removed = (completed_cmd == TCMU_CMD_REMOVED_DEVICE);
+
+       if (!info->attrs[TCMU_ATTR_CMD_STATUS] ||
+           !info->attrs[TCMU_ATTR_DEVICE_ID]) {
+               printk(KERN_ERR "TCMU_ATTR_CMD_STATUS or TCMU_ATTR_DEVICE_ID not set, doing nothing\n");
+                return -EINVAL;
+        }
+
+       dev_id = nla_get_u32(info->attrs[TCMU_ATTR_DEVICE_ID]);
+       rc = nla_get_s32(info->attrs[TCMU_ATTR_CMD_STATUS]);
+
+       dev = target_find_device(dev_id, !is_removed);
+       if (!dev) {
+               printk(KERN_ERR "tcmu nl cmd %u/%u completion could not find device with dev id %u.\n",
+                      completed_cmd, rc, dev_id);
+               return -ENODEV;
+       }
+       udev = TCMU_DEV(dev);
+
+       spin_lock(&udev->nl_cmd_lock);
+       nl_cmd = &udev->curr_nl_cmd;
+
+       pr_debug("genl cmd done got id %d curr %d done %d rc %d\n", dev_id,
+                nl_cmd->cmd, completed_cmd, rc);
+
+       if (nl_cmd->cmd != completed_cmd) {
+               printk(KERN_ERR "Mismatched commands (Expecting reply for %d. Current %d).\n",
+                      completed_cmd, nl_cmd->cmd);
+               ret = -EINVAL;
+       } else {
+               nl_cmd->status = rc;
+       }
+
+       spin_unlock(&udev->nl_cmd_lock);
+       if (!is_removed)
+                target_undepend_item(&dev->dev_group.cg_item);
+       if (!ret)
+               complete(&nl_cmd->complete);
+       return ret;
+}
+
+static int tcmu_genl_rm_dev_done(struct sk_buff *skb, struct genl_info *info)
+{
+       return tcmu_genl_cmd_done(info, TCMU_CMD_REMOVED_DEVICE);
+}
+
+static int tcmu_genl_add_dev_done(struct sk_buff *skb, struct genl_info *info)
+{
+       return tcmu_genl_cmd_done(info, TCMU_CMD_ADDED_DEVICE);
+}
+
+static int tcmu_genl_reconfig_dev_done(struct sk_buff *skb,
+                                      struct genl_info *info)
+{
+       return tcmu_genl_cmd_done(info, TCMU_CMD_RECONFIG_DEVICE);
+}
+
+static int tcmu_genl_set_features(struct sk_buff *skb, struct genl_info *info)
+{
+       if (info->attrs[TCMU_ATTR_SUPP_KERN_CMD_REPLY]) {
+               tcmu_kern_cmd_reply_supported  =
+                       nla_get_u8(info->attrs[TCMU_ATTR_SUPP_KERN_CMD_REPLY]);
+               printk(KERN_INFO "tcmu daemon: command reply support %u.\n",
+                      tcmu_kern_cmd_reply_supported);
+       }
+
+       return 0;
+}
+
+static const struct genl_ops tcmu_genl_ops[] = {
+       {
+               .cmd    = TCMU_CMD_SET_FEATURES,
+               .flags  = GENL_ADMIN_PERM,
+               .policy = tcmu_attr_policy,
+               .doit   = tcmu_genl_set_features,
+       },
+       {
+               .cmd    = TCMU_CMD_ADDED_DEVICE_DONE,
+               .flags  = GENL_ADMIN_PERM,
+               .policy = tcmu_attr_policy,
+               .doit   = tcmu_genl_add_dev_done,
+       },
+       {
+               .cmd    = TCMU_CMD_REMOVED_DEVICE_DONE,
+               .flags  = GENL_ADMIN_PERM,
+               .policy = tcmu_attr_policy,
+               .doit   = tcmu_genl_rm_dev_done,
+       },
+       {
+               .cmd    = TCMU_CMD_RECONFIG_DEVICE_DONE,
+               .flags  = GENL_ADMIN_PERM,
+               .policy = tcmu_attr_policy,
+               .doit   = tcmu_genl_reconfig_dev_done,
+       },
+};
+
 /* Our generic netlink family */
 static struct genl_family tcmu_genl_family __ro_after_init = {
        .module = THIS_MODULE,
        .hdrsize = 0,
        .name = "TCM-USER",
-       .version = 1,
+       .version = 2,
        .maxattr = TCMU_ATTR_MAX,
        .mcgrps = tcmu_mcgrps,
        .n_mcgrps = ARRAY_SIZE(tcmu_mcgrps),
        .netnsok = true,
+       .ops = tcmu_genl_ops,
+       .n_ops = ARRAY_SIZE(tcmu_genl_ops),
 };
 
 #define tcmu_cmd_set_dbi_cur(cmd, index) ((cmd)->dbi_cur = (index))
@@ -216,7 +342,6 @@ static inline bool tcmu_get_empty_block(struct tcmu_dev *udev,
 
        page = radix_tree_lookup(&udev->data_blocks, dbi);
        if (!page) {
-
                if (atomic_add_return(1, &global_db_count) >
                                        TCMU_GLOBAL_MAX_BLOCKS) {
                        atomic_dec(&global_db_count);
@@ -226,14 +351,11 @@ static inline bool tcmu_get_empty_block(struct tcmu_dev *udev,
                /* try to get new page from the mm */
                page = alloc_page(GFP_KERNEL);
                if (!page)
-                       return false;
+                       goto err_alloc;
 
                ret = radix_tree_insert(&udev->data_blocks, dbi, page);
-               if (ret) {
-                       __free_page(page);
-                       return false;
-               }
-
+               if (ret)
+                       goto err_insert;
        }
 
        if (dbi > udev->dbi_max)
@@ -243,6 +365,11 @@ static inline bool tcmu_get_empty_block(struct tcmu_dev *udev,
        tcmu_cmd_set_dbi(tcmu_cmd, dbi);
 
        return true;
+err_insert:
+       __free_page(page);
+err_alloc:
+       atomic_dec(&global_db_count);
+       return false;
 }
 
 static bool tcmu_get_empty_blocks(struct tcmu_dev *udev,
@@ -401,7 +528,7 @@ static inline size_t get_block_offset_user(struct tcmu_dev *dev,
                DATA_BLOCK_SIZE - remaining;
 }
 
-static inline size_t iov_tail(struct tcmu_dev *udev, struct iovec *iov)
+static inline size_t iov_tail(struct iovec *iov)
 {
        return (size_t)iov->iov_base + iov->iov_len;
 }
@@ -437,10 +564,10 @@ static int scatter_data_area(struct tcmu_dev *udev,
                        to_offset = get_block_offset_user(udev, dbi,
                                        block_remaining);
                        offset = DATA_BLOCK_SIZE - block_remaining;
-                       to = (void *)(unsigned long)to + offset;
+                       to += offset;
 
                        if (*iov_cnt != 0 &&
-                           to_offset == iov_tail(udev, *iov)) {
+                           to_offset == iov_tail(*iov)) {
                                (*iov)->iov_len += copy_bytes;
                        } else {
                                new_iov(iov, iov_cnt, udev);
@@ -510,7 +637,7 @@ static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd,
                        copy_bytes = min_t(size_t, sg_remaining,
                                        block_remaining);
                        offset = DATA_BLOCK_SIZE - block_remaining;
-                       from = (void *)(unsigned long)from + offset;
+                       from += offset;
                        tcmu_flush_dcache_range(from, copy_bytes);
                        memcpy(to + sg->length - sg_remaining, from,
                                        copy_bytes);
@@ -596,10 +723,7 @@ static bool is_ring_space_avail(struct tcmu_dev *udev, struct tcmu_cmd *cmd,
                }
        }
 
-       if (!tcmu_get_empty_blocks(udev, cmd))
-               return false;
-
-       return true;
+       return tcmu_get_empty_blocks(udev, cmd);
 }
 
 static inline size_t tcmu_cmd_get_base_cmd_size(size_t iov_cnt)
@@ -699,25 +823,24 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
                size_t pad_size = head_to_end(cmd_head, udev->cmdr_size);
 
                entry = (void *) mb + CMDR_OFF + cmd_head;
-               tcmu_flush_dcache_range(entry, sizeof(*entry));
                tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_PAD);
                tcmu_hdr_set_len(&entry->hdr.len_op, pad_size);
                entry->hdr.cmd_id = 0; /* not used for PAD */
                entry->hdr.kflags = 0;
                entry->hdr.uflags = 0;
+               tcmu_flush_dcache_range(entry, sizeof(*entry));
 
                UPDATE_HEAD(mb->cmd_head, pad_size, udev->cmdr_size);
+               tcmu_flush_dcache_range(mb, sizeof(*mb));
 
                cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */
                WARN_ON(cmd_head != 0);
        }
 
        entry = (void *) mb + CMDR_OFF + cmd_head;
-       tcmu_flush_dcache_range(entry, sizeof(*entry));
+       memset(entry, 0, command_size);
        tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_CMD);
        entry->hdr.cmd_id = tcmu_cmd->cmd_id;
-       entry->hdr.kflags = 0;
-       entry->hdr.uflags = 0;
 
        /* Handle allocating space from the data area */
        tcmu_cmd_reset_dbi_cur(tcmu_cmd);
@@ -736,11 +859,10 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
        entry->req.iov_cnt = iov_cnt;
-       entry->req.iov_dif_cnt = 0;
 
        /* Handle BIDI commands */
+       iov_cnt = 0;
        if (se_cmd->se_cmd_flags & SCF_BIDI) {
-               iov_cnt = 0;
                iov++;
                ret = scatter_data_area(udev, tcmu_cmd,
                                        se_cmd->t_bidi_data_sg,
@@ -753,8 +875,8 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
                        pr_err("tcmu: alloc and scatter bidi data failed\n");
                        return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
                }
-               entry->req.iov_bidi_cnt = iov_cnt;
        }
+       entry->req.iov_bidi_cnt = iov_cnt;
 
        /*
         * Recalaulate the command's base size and size according
@@ -830,8 +952,7 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
                        cmd->se_cmd);
                entry->rsp.scsi_status = SAM_STAT_CHECK_CONDITION;
        } else if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) {
-               memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer,
-                              se_cmd->scsi_sense_length);
+               transport_copy_sense_to_cmd(se_cmd, entry->rsp.sense_buffer);
        } else if (se_cmd->se_cmd_flags & SCF_BIDI) {
                /* Get Data-In buffer before clean up */
                gather_data_area(udev, cmd, true);
@@ -989,6 +1110,9 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name)
        setup_timer(&udev->timeout, tcmu_device_timedout,
                (unsigned long)udev);
 
+       init_waitqueue_head(&udev->nl_cmd_wq);
+       spin_lock_init(&udev->nl_cmd_lock);
+
        return &udev->se_dev;
 }
 
@@ -1140,6 +1264,7 @@ static int tcmu_open(struct uio_info *info, struct inode *inode)
                return -EBUSY;
 
        udev->inode = inode;
+       kref_get(&udev->kref);
 
        pr_debug("open\n");
 
@@ -1171,12 +1296,59 @@ static int tcmu_release(struct uio_info *info, struct inode *inode)
        clear_bit(TCMU_DEV_BIT_OPEN, &udev->flags);
 
        pr_debug("close\n");
-       /* release ref from configure */
+       /* release ref from open */
        kref_put(&udev->kref, tcmu_dev_kref_release);
        return 0;
 }
 
-static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, int minor)
+static void tcmu_init_genl_cmd_reply(struct tcmu_dev *udev, int cmd)
+{
+       struct tcmu_nl_cmd *nl_cmd = &udev->curr_nl_cmd;
+
+       if (!tcmu_kern_cmd_reply_supported)
+               return;
+relock:
+       spin_lock(&udev->nl_cmd_lock);
+
+       if (nl_cmd->cmd != TCMU_CMD_UNSPEC) {
+               spin_unlock(&udev->nl_cmd_lock);
+               pr_debug("sleeping for open nl cmd\n");
+               wait_event(udev->nl_cmd_wq, (nl_cmd->cmd == TCMU_CMD_UNSPEC));
+               goto relock;
+       }
+
+       memset(nl_cmd, 0, sizeof(*nl_cmd));
+       nl_cmd->cmd = cmd;
+       init_completion(&nl_cmd->complete);
+
+       spin_unlock(&udev->nl_cmd_lock);
+}
+
+static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev)
+{
+       struct tcmu_nl_cmd *nl_cmd = &udev->curr_nl_cmd;
+       int ret;
+       DEFINE_WAIT(__wait);
+
+       if (!tcmu_kern_cmd_reply_supported)
+               return 0;
+
+       pr_debug("sleeping for nl reply\n");
+       wait_for_completion(&nl_cmd->complete);
+
+       spin_lock(&udev->nl_cmd_lock);
+       nl_cmd->cmd = TCMU_CMD_UNSPEC;
+       ret = nl_cmd->status;
+       nl_cmd->status = 0;
+       spin_unlock(&udev->nl_cmd_lock);
+
+       wake_up_all(&udev->nl_cmd_wq);
+
+       return ret;;
+}
+
+static int tcmu_netlink_event(struct tcmu_dev *udev, enum tcmu_genl_cmd cmd,
+                             int reconfig_attr, const void *reconfig_data)
 {
        struct sk_buff *skb;
        void *msg_header;
@@ -1190,22 +1362,51 @@ static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, int mino
        if (!msg_header)
                goto free_skb;
 
-       ret = nla_put_string(skb, TCMU_ATTR_DEVICE, name);
+       ret = nla_put_string(skb, TCMU_ATTR_DEVICE, udev->uio_info.name);
+       if (ret < 0)
+               goto free_skb;
+
+       ret = nla_put_u32(skb, TCMU_ATTR_MINOR, udev->uio_info.uio_dev->minor);
        if (ret < 0)
                goto free_skb;
 
-       ret = nla_put_u32(skb, TCMU_ATTR_MINOR, minor);
+       ret = nla_put_u32(skb, TCMU_ATTR_DEVICE_ID, udev->se_dev.dev_index);
        if (ret < 0)
                goto free_skb;
 
+       if (cmd == TCMU_CMD_RECONFIG_DEVICE) {
+               switch (reconfig_attr) {
+               case TCMU_ATTR_DEV_CFG:
+                       ret = nla_put_string(skb, reconfig_attr, reconfig_data);
+                       break;
+               case TCMU_ATTR_DEV_SIZE:
+                       ret = nla_put_u64_64bit(skb, reconfig_attr,
+                                               *((u64 *)reconfig_data),
+                                               TCMU_ATTR_PAD);
+                       break;
+               case TCMU_ATTR_WRITECACHE:
+                       ret = nla_put_u8(skb, reconfig_attr,
+                                         *((u8 *)reconfig_data));
+                       break;
+               default:
+                       BUG();
+               }
+
+               if (ret < 0)
+                       goto free_skb;
+       }
+
        genlmsg_end(skb, msg_header);
 
+       tcmu_init_genl_cmd_reply(udev, cmd);
+
        ret = genlmsg_multicast_allns(&tcmu_genl_family, skb, 0,
                                TCMU_MCGRP_CONFIG, GFP_KERNEL);
-
        /* We don't care if no one is listening */
        if (ret == -ESRCH)
                ret = 0;
+       if (!ret)
+               ret = tcmu_wait_genl_cmd_reply(udev);
 
        return ret;
 free_skb:
@@ -1213,19 +1414,14 @@ free_skb:
        return ret;
 }
 
-static int tcmu_configure_device(struct se_device *dev)
+static int tcmu_update_uio_info(struct tcmu_dev *udev)
 {
-       struct tcmu_dev *udev = TCMU_DEV(dev);
        struct tcmu_hba *hba = udev->hba->hba_ptr;
        struct uio_info *info;
-       struct tcmu_mailbox *mb;
-       size_t size;
-       size_t used;
-       int ret = 0;
+       size_t size, used;
        char *str;
 
        info = &udev->uio_info;
-
        size = snprintf(NULL, 0, "tcm-user/%u/%s/%s", hba->host_id, udev->name,
                        udev->dev_config);
        size += 1; /* for \0 */
@@ -1234,12 +1430,27 @@ static int tcmu_configure_device(struct se_device *dev)
                return -ENOMEM;
 
        used = snprintf(str, size, "tcm-user/%u/%s", hba->host_id, udev->name);
-
        if (udev->dev_config[0])
                snprintf(str + used, size - used, "/%s", udev->dev_config);
 
        info->name = str;
 
+       return 0;
+}
+
+static int tcmu_configure_device(struct se_device *dev)
+{
+       struct tcmu_dev *udev = TCMU_DEV(dev);
+       struct uio_info *info;
+       struct tcmu_mailbox *mb;
+       int ret = 0;
+
+       ret = tcmu_update_uio_info(udev);
+       if (ret)
+               return ret;
+
+       info = &udev->uio_info;
+
        udev->mb_addr = vzalloc(CMDR_SIZE);
        if (!udev->mb_addr) {
                ret = -ENOMEM;
@@ -1290,6 +1501,8 @@ static int tcmu_configure_device(struct se_device *dev)
        /* Other attributes can be configured in userspace */
        if (!dev->dev_attrib.hw_max_sectors)
                dev->dev_attrib.hw_max_sectors = 128;
+       if (!dev->dev_attrib.emulate_write_cache)
+               dev->dev_attrib.emulate_write_cache = 0;
        dev->dev_attrib.hw_queue_depth = 128;
 
        /*
@@ -1298,8 +1511,7 @@ static int tcmu_configure_device(struct se_device *dev)
         */
        kref_get(&udev->kref);
 
-       ret = tcmu_netlink_event(TCMU_CMD_ADDED_DEVICE, udev->uio_info.name,
-                                udev->uio_info.uio_dev->minor);
+       ret = tcmu_netlink_event(udev, TCMU_CMD_ADDED_DEVICE, 0, NULL);
        if (ret)
                goto err_netlink;
 
@@ -1355,6 +1567,14 @@ static void tcmu_blocks_release(struct tcmu_dev *udev)
 static void tcmu_free_device(struct se_device *dev)
 {
        struct tcmu_dev *udev = TCMU_DEV(dev);
+
+       /* release ref from init */
+       kref_put(&udev->kref, tcmu_dev_kref_release);
+}
+
+static void tcmu_destroy_device(struct se_device *dev)
+{
+       struct tcmu_dev *udev = TCMU_DEV(dev);
        struct tcmu_cmd *cmd;
        bool all_expired = true;
        int i;
@@ -1379,14 +1599,11 @@ static void tcmu_free_device(struct se_device *dev)
 
        tcmu_blocks_release(udev);
 
-       if (tcmu_dev_configured(udev)) {
-               tcmu_netlink_event(TCMU_CMD_REMOVED_DEVICE, udev->uio_info.name,
-                                  udev->uio_info.uio_dev->minor);
+       tcmu_netlink_event(udev, TCMU_CMD_REMOVED_DEVICE, 0, NULL);
 
-               uio_unregister_device(&udev->uio_info);
-       }
+       uio_unregister_device(&udev->uio_info);
 
-       /* release ref from init */
+       /* release ref from configure */
        kref_put(&udev->kref, tcmu_dev_kref_release);
 }
 
@@ -1546,6 +1763,129 @@ static ssize_t tcmu_cmd_time_out_store(struct config_item *item, const char *pag
 }
 CONFIGFS_ATTR(tcmu_, cmd_time_out);
 
+static ssize_t tcmu_dev_config_show(struct config_item *item, char *page)
+{
+       struct se_dev_attrib *da = container_of(to_config_group(item),
+                                               struct se_dev_attrib, da_group);
+       struct tcmu_dev *udev = TCMU_DEV(da->da_dev);
+
+       return snprintf(page, PAGE_SIZE, "%s\n", udev->dev_config);
+}
+
+static ssize_t tcmu_dev_config_store(struct config_item *item, const char *page,
+                                    size_t count)
+{
+       struct se_dev_attrib *da = container_of(to_config_group(item),
+                                               struct se_dev_attrib, da_group);
+       struct tcmu_dev *udev = TCMU_DEV(da->da_dev);
+       int ret, len;
+
+       len = strlen(page);
+       if (!len || len > TCMU_CONFIG_LEN - 1)
+               return -EINVAL;
+
+       /* Check if device has been configured before */
+       if (tcmu_dev_configured(udev)) {
+               ret = tcmu_netlink_event(udev, TCMU_CMD_RECONFIG_DEVICE,
+                                        TCMU_ATTR_DEV_CFG, page);
+               if (ret) {
+                       pr_err("Unable to reconfigure device\n");
+                       return ret;
+               }
+               strlcpy(udev->dev_config, page, TCMU_CONFIG_LEN);
+
+               ret = tcmu_update_uio_info(udev);
+               if (ret)
+                       return ret;
+               return count;
+       }
+       strlcpy(udev->dev_config, page, TCMU_CONFIG_LEN);
+
+       return count;
+}
+CONFIGFS_ATTR(tcmu_, dev_config);
+
+static ssize_t tcmu_dev_size_show(struct config_item *item, char *page)
+{
+       struct se_dev_attrib *da = container_of(to_config_group(item),
+                                               struct se_dev_attrib, da_group);
+       struct tcmu_dev *udev = TCMU_DEV(da->da_dev);
+
+       return snprintf(page, PAGE_SIZE, "%zu\n", udev->dev_size);
+}
+
+static ssize_t tcmu_dev_size_store(struct config_item *item, const char *page,
+                                  size_t count)
+{
+       struct se_dev_attrib *da = container_of(to_config_group(item),
+                                               struct se_dev_attrib, da_group);
+       struct tcmu_dev *udev = TCMU_DEV(da->da_dev);
+       u64 val;
+       int ret;
+
+       ret = kstrtou64(page, 0, &val);
+       if (ret < 0)
+               return ret;
+
+       /* Check if device has been configured before */
+       if (tcmu_dev_configured(udev)) {
+               ret = tcmu_netlink_event(udev, TCMU_CMD_RECONFIG_DEVICE,
+                                        TCMU_ATTR_DEV_SIZE, &val);
+               if (ret) {
+                       pr_err("Unable to reconfigure device\n");
+                       return ret;
+               }
+       }
+       udev->dev_size = val;
+       return count;
+}
+CONFIGFS_ATTR(tcmu_, dev_size);
+
+static ssize_t tcmu_emulate_write_cache_show(struct config_item *item,
+                                            char *page)
+{
+       struct se_dev_attrib *da = container_of(to_config_group(item),
+                                       struct se_dev_attrib, da_group);
+
+       return snprintf(page, PAGE_SIZE, "%i\n", da->emulate_write_cache);
+}
+
+static ssize_t tcmu_emulate_write_cache_store(struct config_item *item,
+                                             const char *page, size_t count)
+{
+       struct se_dev_attrib *da = container_of(to_config_group(item),
+                                       struct se_dev_attrib, da_group);
+       struct tcmu_dev *udev = TCMU_DEV(da->da_dev);
+       u8 val;
+       int ret;
+
+       ret = kstrtou8(page, 0, &val);
+       if (ret < 0)
+               return ret;
+
+       /* Check if device has been configured before */
+       if (tcmu_dev_configured(udev)) {
+               ret = tcmu_netlink_event(udev, TCMU_CMD_RECONFIG_DEVICE,
+                                        TCMU_ATTR_WRITECACHE, &val);
+               if (ret) {
+                       pr_err("Unable to reconfigure device\n");
+                       return ret;
+               }
+       }
+
+       da->emulate_write_cache = val;
+       return count;
+}
+CONFIGFS_ATTR(tcmu_, emulate_write_cache);
+
+static struct configfs_attribute *tcmu_attrib_attrs[] = {
+       &tcmu_attr_cmd_time_out,
+       &tcmu_attr_dev_config,
+       &tcmu_attr_dev_size,
+       &tcmu_attr_emulate_write_cache,
+       NULL,
+};
+
 static struct configfs_attribute **tcmu_attrs;
 
 static struct target_backend_ops tcmu_ops = {
@@ -1556,6 +1896,7 @@ static struct target_backend_ops tcmu_ops = {
        .detach_hba             = tcmu_detach_hba,
        .alloc_device           = tcmu_alloc_device,
        .configure_device       = tcmu_configure_device,
+       .destroy_device         = tcmu_destroy_device,
        .free_device            = tcmu_free_device,
        .parse_cdb              = tcmu_parse_cdb,
        .set_configfs_dev_params = tcmu_set_configfs_dev_params,
@@ -1573,7 +1914,7 @@ static int unmap_thread_fn(void *data)
        struct page *page;
        int i;
 
-       while (1) {
+       while (!kthread_should_stop()) {
                DEFINE_WAIT(__wait);
 
                prepare_to_wait(&unmap_wait, &__wait, TASK_INTERRUPTIBLE);
@@ -1645,7 +1986,7 @@ static int unmap_thread_fn(void *data)
 
 static int __init tcmu_module_init(void)
 {
-       int ret, i, len = 0;
+       int ret, i, k, len = 0;
 
        BUILD_BUG_ON((sizeof(struct tcmu_cmd_entry) % TCMU_OP_ALIGN_SIZE) != 0);
 
@@ -1670,7 +2011,10 @@ static int __init tcmu_module_init(void)
        for (i = 0; passthrough_attrib_attrs[i] != NULL; i++) {
                len += sizeof(struct configfs_attribute *);
        }
-       len += sizeof(struct configfs_attribute *) * 2;
+       for (i = 0; tcmu_attrib_attrs[i] != NULL; i++) {
+               len += sizeof(struct configfs_attribute *);
+       }
+       len += sizeof(struct configfs_attribute *);
 
        tcmu_attrs = kzalloc(len, GFP_KERNEL);
        if (!tcmu_attrs) {
@@ -1681,7 +2025,10 @@ static int __init tcmu_module_init(void)
        for (i = 0; passthrough_attrib_attrs[i] != NULL; i++) {
                tcmu_attrs[i] = passthrough_attrib_attrs[i];
        }
-       tcmu_attrs[i] = &tcmu_attr_cmd_time_out;
+       for (k = 0; tcmu_attrib_attrs[k] != NULL; k++) {
+               tcmu_attrs[i] = tcmu_attrib_attrs[k];
+               i++;
+       }
        tcmu_ops.tb_dev_attrib_attrs = tcmu_attrs;
 
        ret = transport_backend_register(&tcmu_ops);
index cac5a20..9ee89e0 100644 (file)
@@ -40,6 +40,8 @@
 
 static struct workqueue_struct *xcopy_wq = NULL;
 
+static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop);
+
 static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
 {
        int off = 0;
@@ -53,48 +55,60 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
        return 0;
 }
 
-static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
-                                       struct se_device **found_dev)
+struct xcopy_dev_search_info {
+       const unsigned char *dev_wwn;
+       struct se_device *found_dev;
+};
+
+static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev,
+                                             void *data)
 {
-       struct se_device *se_dev;
+       struct xcopy_dev_search_info *info = data;
        unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
        int rc;
 
-       mutex_lock(&g_device_mutex);
-       list_for_each_entry(se_dev, &g_device_list, g_dev_node) {
+       if (!se_dev->dev_attrib.emulate_3pc)
+               return 0;
 
-               if (!se_dev->dev_attrib.emulate_3pc)
-                       continue;
+       memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
+       target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
 
-               memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
-               target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
+       rc = memcmp(&tmp_dev_wwn[0], info->dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
+       if (rc != 0)
+               return 0;
 
-               rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
-               if (rc != 0)
-                       continue;
+       info->found_dev = se_dev;
+       pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
 
-               *found_dev = se_dev;
-               pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
+       rc = target_depend_item(&se_dev->dev_group.cg_item);
+       if (rc != 0) {
+               pr_err("configfs_depend_item attempt failed: %d for se_dev: %p\n",
+                      rc, se_dev);
+               return rc;
+       }
 
-               rc = target_depend_item(&se_dev->dev_group.cg_item);
-               if (rc != 0) {
-                       pr_err("configfs_depend_item attempt failed:"
-                               " %d for se_dev: %p\n", rc, se_dev);
-                       mutex_unlock(&g_device_mutex);
-                       return rc;
-               }
+       pr_debug("Called configfs_depend_item for se_dev: %p se_dev->se_dev_group: %p\n",
+                se_dev, &se_dev->dev_group);
+       return 1;
+}
 
-               pr_debug("Called configfs_depend_item for se_dev: %p"
-                       " se_dev->se_dev_group: %p\n", se_dev,
-                       &se_dev->dev_group);
+static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
+                                       struct se_device **found_dev)
+{
+       struct xcopy_dev_search_info info;
+       int ret;
+
+       memset(&info, 0, sizeof(info));
+       info.dev_wwn = dev_wwn;
 
-               mutex_unlock(&g_device_mutex);
+       ret = target_for_each_device(target_xcopy_locate_se_dev_e4_iter, &info);
+       if (ret == 1) {
+               *found_dev = info.found_dev;
                return 0;
+       } else {
+               pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
+               return -EINVAL;
        }
-       mutex_unlock(&g_device_mutex);
-
-       pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
-       return -EINVAL;
 }
 
 static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
@@ -311,9 +325,7 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op
                (unsigned long long)xop->dst_lba);
 
        if (dc != 0) {
-               xop->dbl = (desc[29] & 0xff) << 16;
-               xop->dbl |= (desc[30] & 0xff) << 8;
-               xop->dbl |= desc[31] & 0xff;
+               xop->dbl = get_unaligned_be24(&desc[29]);
 
                pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl);
        }
@@ -781,13 +793,24 @@ static int target_xcopy_write_destination(
 static void target_xcopy_do_work(struct work_struct *work)
 {
        struct xcopy_op *xop = container_of(work, struct xcopy_op, xop_work);
-       struct se_device *src_dev = xop->src_dev, *dst_dev = xop->dst_dev;
        struct se_cmd *ec_cmd = xop->xop_se_cmd;
-       sector_t src_lba = xop->src_lba, dst_lba = xop->dst_lba, end_lba;
+       struct se_device *src_dev, *dst_dev;
+       sector_t src_lba, dst_lba, end_lba;
        unsigned int max_sectors;
-       int rc;
-       unsigned short nolb = xop->nolb, cur_nolb, max_nolb, copied_nolb = 0;
+       int rc = 0;
+       unsigned short nolb, cur_nolb, max_nolb, copied_nolb = 0;
+
+       if (target_parse_xcopy_cmd(xop) != TCM_NO_SENSE)
+               goto err_free;
 
+       if (WARN_ON_ONCE(!xop->src_dev) || WARN_ON_ONCE(!xop->dst_dev))
+               goto err_free;
+
+       src_dev = xop->src_dev;
+       dst_dev = xop->dst_dev;
+       src_lba = xop->src_lba;
+       dst_lba = xop->dst_lba;
+       nolb = xop->nolb;
        end_lba = src_lba + nolb;
        /*
         * Break up XCOPY I/O into hw_max_sectors sized I/O based on the
@@ -855,6 +878,8 @@ static void target_xcopy_do_work(struct work_struct *work)
 
 out:
        xcopy_pt_undepend_remotedev(xop);
+
+err_free:
        kfree(xop);
        /*
         * Don't override an error scsi status if it has already been set
@@ -867,48 +892,22 @@ out:
        target_complete_cmd(ec_cmd, ec_cmd->scsi_status);
 }
 
-sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
+/*
+ * Returns TCM_NO_SENSE upon success or a sense code != TCM_NO_SENSE if parsing
+ * fails.
+ */
+static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop)
 {
-       struct se_device *dev = se_cmd->se_dev;
-       struct xcopy_op *xop = NULL;
+       struct se_cmd *se_cmd = xop->xop_se_cmd;
        unsigned char *p = NULL, *seg_desc;
-       unsigned int list_id, list_id_usage, sdll, inline_dl, sa;
+       unsigned int list_id, list_id_usage, sdll, inline_dl;
        sense_reason_t ret = TCM_INVALID_PARAMETER_LIST;
        int rc;
        unsigned short tdll;
 
-       if (!dev->dev_attrib.emulate_3pc) {
-               pr_err("EXTENDED_COPY operation explicitly disabled\n");
-               return TCM_UNSUPPORTED_SCSI_OPCODE;
-       }
-
-       sa = se_cmd->t_task_cdb[1] & 0x1f;
-       if (sa != 0x00) {
-               pr_err("EXTENDED_COPY(LID4) not supported\n");
-               return TCM_UNSUPPORTED_SCSI_OPCODE;
-       }
-
-       if (se_cmd->data_length == 0) {
-               target_complete_cmd(se_cmd, SAM_STAT_GOOD);
-               return TCM_NO_SENSE;
-       }
-       if (se_cmd->data_length < XCOPY_HDR_LEN) {
-               pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n",
-                               se_cmd->data_length, XCOPY_HDR_LEN);
-               return TCM_PARAMETER_LIST_LENGTH_ERROR;
-       }
-
-       xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
-       if (!xop) {
-               pr_err("Unable to allocate xcopy_op\n");
-               return TCM_OUT_OF_RESOURCES;
-       }
-       xop->xop_se_cmd = se_cmd;
-
        p = transport_kmap_data_sg(se_cmd);
        if (!p) {
                pr_err("transport_kmap_data_sg() failed in target_do_xcopy\n");
-               kfree(xop);
                return TCM_OUT_OF_RESOURCES;
        }
 
@@ -977,18 +976,57 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
        pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc,
                                rc * XCOPY_TARGET_DESC_LEN);
        transport_kunmap_data_sg(se_cmd);
-
-       INIT_WORK(&xop->xop_work, target_xcopy_do_work);
-       queue_work(xcopy_wq, &xop->xop_work);
        return TCM_NO_SENSE;
 
 out:
        if (p)
                transport_kunmap_data_sg(se_cmd);
-       kfree(xop);
        return ret;
 }
 
+sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
+{
+       struct se_device *dev = se_cmd->se_dev;
+       struct xcopy_op *xop;
+       unsigned int sa;
+
+       if (!dev->dev_attrib.emulate_3pc) {
+               pr_err("EXTENDED_COPY operation explicitly disabled\n");
+               return TCM_UNSUPPORTED_SCSI_OPCODE;
+       }
+
+       sa = se_cmd->t_task_cdb[1] & 0x1f;
+       if (sa != 0x00) {
+               pr_err("EXTENDED_COPY(LID4) not supported\n");
+               return TCM_UNSUPPORTED_SCSI_OPCODE;
+       }
+
+       if (se_cmd->data_length == 0) {
+               target_complete_cmd(se_cmd, SAM_STAT_GOOD);
+               return TCM_NO_SENSE;
+       }
+       if (se_cmd->data_length < XCOPY_HDR_LEN) {
+               pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n",
+                               se_cmd->data_length, XCOPY_HDR_LEN);
+               return TCM_PARAMETER_LIST_LENGTH_ERROR;
+       }
+
+       xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
+       if (!xop)
+               goto err;
+       xop->xop_se_cmd = se_cmd;
+       INIT_WORK(&xop->xop_work, target_xcopy_do_work);
+       if (WARN_ON_ONCE(!queue_work(xcopy_wq, &xop->xop_work)))
+               goto free;
+       return TCM_NO_SENSE;
+
+free:
+       kfree(xop);
+
+err:
+       return TCM_OUT_OF_RESOURCES;
+}
+
 static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd)
 {
        unsigned char *p;
index 0ecf808..e6863c8 100644 (file)
@@ -245,7 +245,6 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
                 */
                err = tz->ops->get_trip_temp(tz, 0, &trip_temp);
                if (err < 0) {
-                       err = PTR_ERR(tz);
                        dev_err(&pdev->dev,
                                "Not able to read trip_temp: %d\n",
                                err);
index 69d0f43..908a801 100644 (file)
  */
 
 /**
- * struct power_table - frequency to power conversion
+ * struct freq_table - frequency table along with power entries
  * @frequency: frequency in KHz
  * @power:     power in mW
  *
  * This structure is built when the cooling device registers and helps
- * in translating frequency to power and viceversa.
+ * in translating frequency to power and vice versa.
  */
-struct power_table {
+struct freq_table {
        u32 frequency;
        u32 power;
 };
 
 /**
+ * struct time_in_idle - Idle time stats
+ * @time: previous reading of the absolute time that this cpu was idle
+ * @timestamp: wall time of the last invocation of get_cpu_idle_time_us()
+ */
+struct time_in_idle {
+       u64 time;
+       u64 timestamp;
+};
+
+/**
  * struct cpufreq_cooling_device - data for cooling device with cpufreq
  * @id: unique integer value corresponding to each cpufreq_cooling_device
  *     registered.
- * @cool_dev: thermal_cooling_device pointer to keep track of the
- *     registered cooling device.
+ * @last_load: load measured by the latest call to cpufreq_get_requested_power()
  * @cpufreq_state: integer value representing the current state of cpufreq
  *     cooling devices.
  * @clipped_freq: integer value representing the absolute value of the clipped
  *     frequency.
  * @max_level: maximum cooling level. One less than total number of valid
  *     cpufreq frequencies.
- * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device.
+ * @freq_table: Freq table in descending order of frequencies
+ * @cdev: thermal_cooling_device pointer to keep track of the
+ *     registered cooling device.
+ * @policy: cpufreq policy.
  * @node: list_head to link all cpufreq_cooling_device together.
- * @last_load: load measured by the latest call to cpufreq_get_requested_power()
- * @time_in_idle: previous reading of the absolute time that this cpu was idle
- * @time_in_idle_timestamp: wall time of the last invocation of
- *     get_cpu_idle_time_us()
- * @dyn_power_table: array of struct power_table for frequency to power
- *     conversion, sorted in ascending order.
- * @dyn_power_table_entries: number of entries in the @dyn_power_table array
- * @cpu_dev: the first cpu_device from @allowed_cpus that has OPPs registered
+ * @idle_time: idle time stats
  * @plat_get_static_power: callback to calculate the static power
  *
  * This structure is required for keeping information of each registered
@@ -90,81 +95,45 @@ struct power_table {
  */
 struct cpufreq_cooling_device {
        int id;
-       struct thermal_cooling_device *cool_dev;
+       u32 last_load;
        unsigned int cpufreq_state;
        unsigned int clipped_freq;
        unsigned int max_level;
-       unsigned int *freq_table;       /* In descending order */
-       struct cpumask allowed_cpus;
+       struct freq_table *freq_table;  /* In descending order */
+       struct thermal_cooling_device *cdev;
+       struct cpufreq_policy *policy;
        struct list_head node;
-       u32 last_load;
-       u64 *time_in_idle;
-       u64 *time_in_idle_timestamp;
-       struct power_table *dyn_power_table;
-       int dyn_power_table_entries;
-       struct device *cpu_dev;
+       struct time_in_idle *idle_time;
        get_static_t plat_get_static_power;
 };
-static DEFINE_IDA(cpufreq_ida);
 
+static DEFINE_IDA(cpufreq_ida);
 static DEFINE_MUTEX(cooling_list_lock);
-static LIST_HEAD(cpufreq_dev_list);
+static LIST_HEAD(cpufreq_cdev_list);
 
 /* Below code defines functions to be used for cpufreq as cooling device */
 
 /**
  * get_level: Find the level for a particular frequency
- * @cpufreq_dev: cpufreq_dev for which the property is required
+ * @cpufreq_cdev: cpufreq_cdev for which the property is required
  * @freq: Frequency
  *
- * Return: level on success, THERMAL_CSTATE_INVALID on error.
+ * Return: level corresponding to the frequency.
  */
-static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_dev,
+static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_cdev,
                               unsigned int freq)
 {
+       struct freq_table *freq_table = cpufreq_cdev->freq_table;
        unsigned long level;
 
-       for (level = 0; level <= cpufreq_dev->max_level; level++) {
-               if (freq == cpufreq_dev->freq_table[level])
-                       return level;
-
-               if (freq > cpufreq_dev->freq_table[level])
+       for (level = 1; level <= cpufreq_cdev->max_level; level++)
+               if (freq > freq_table[level].frequency)
                        break;
-       }
 
-       return THERMAL_CSTATE_INVALID;
+       return level - 1;
 }
 
 /**
- * cpufreq_cooling_get_level - for a given cpu, return the cooling level.
- * @cpu: cpu for which the level is required
- * @freq: the frequency of interest
- *
- * This function will match the cooling level corresponding to the
- * requested @freq and return it.
- *
- * Return: The matched cooling level on success or THERMAL_CSTATE_INVALID
- * otherwise.
- */
-unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
-{
-       struct cpufreq_cooling_device *cpufreq_dev;
-
-       mutex_lock(&cooling_list_lock);
-       list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
-               if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) {
-                       mutex_unlock(&cooling_list_lock);
-                       return get_level(cpufreq_dev, freq);
-               }
-       }
-       mutex_unlock(&cooling_list_lock);
-
-       pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu);
-       return THERMAL_CSTATE_INVALID;
-}
-EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level);
-
-/**
  * cpufreq_thermal_notifier - notifier callback for cpufreq policy change.
  * @nb:        struct notifier_block * with callback info.
  * @event: value showing cpufreq event for which this function invoked.
@@ -181,14 +150,18 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
 {
        struct cpufreq_policy *policy = data;
        unsigned long clipped_freq;
-       struct cpufreq_cooling_device *cpufreq_dev;
+       struct cpufreq_cooling_device *cpufreq_cdev;
 
        if (event != CPUFREQ_ADJUST)
                return NOTIFY_DONE;
 
        mutex_lock(&cooling_list_lock);
-       list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
-               if (!cpumask_test_cpu(policy->cpu, &cpufreq_dev->allowed_cpus))
+       list_for_each_entry(cpufreq_cdev, &cpufreq_cdev_list, node) {
+               /*
+                * A new copy of the policy is sent to the notifier and can't
+                * compare that directly.
+                */
+               if (policy->cpu != cpufreq_cdev->policy->cpu)
                        continue;
 
                /*
@@ -202,7 +175,7 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
                 * But, if clipped_freq is greater than policy->max, we don't
                 * need to do anything.
                 */
-               clipped_freq = cpufreq_dev->clipped_freq;
+               clipped_freq = cpufreq_cdev->clipped_freq;
 
                if (policy->max > clipped_freq)
                        cpufreq_verify_within_limits(policy, 0, clipped_freq);
@@ -214,63 +187,63 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
 }
 
 /**
- * build_dyn_power_table() - create a dynamic power to frequency table
- * @cpufreq_device:    the cpufreq cooling device in which to store the table
+ * update_freq_table() - Update the freq table with power numbers
+ * @cpufreq_cdev:      the cpufreq cooling device in which to update the table
  * @capacitance: dynamic power coefficient for these cpus
  *
- * Build a dynamic power to frequency table for this cpu and store it
- * in @cpufreq_device.  This table will be used in cpu_power_to_freq() and
- * cpu_freq_to_power() to convert between power and frequency
- * efficiently.  Power is stored in mW, frequency in KHz.  The
- * resulting table is in ascending order.
+ * Update the freq table with power numbers.  This table will be used in
+ * cpu_power_to_freq() and cpu_freq_to_power() to convert between power and
+ * frequency efficiently.  Power is stored in mW, frequency in KHz.  The
+ * resulting table is in descending order.
  *
  * Return: 0 on success, -EINVAL if there are no OPPs for any CPUs,
- * -ENOMEM if we run out of memory or -EAGAIN if an OPP was
- * added/enabled while the function was executing.
+ * or -ENOMEM if we run out of memory.
  */
-static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
-                                u32 capacitance)
+static int update_freq_table(struct cpufreq_cooling_device *cpufreq_cdev,
+                            u32 capacitance)
 {
-       struct power_table *power_table;
+       struct freq_table *freq_table = cpufreq_cdev->freq_table;
        struct dev_pm_opp *opp;
        struct device *dev = NULL;
-       int num_opps = 0, cpu, i, ret = 0;
-       unsigned long freq;
-
-       for_each_cpu(cpu, &cpufreq_device->allowed_cpus) {
-               dev = get_cpu_device(cpu);
-               if (!dev) {
-                       dev_warn(&cpufreq_device->cool_dev->device,
-                                "No cpu device for cpu %d\n", cpu);
-                       continue;
-               }
+       int num_opps = 0, cpu = cpufreq_cdev->policy->cpu, i;
 
-               num_opps = dev_pm_opp_get_opp_count(dev);
-               if (num_opps > 0)
-                       break;
-               else if (num_opps < 0)
-                       return num_opps;
+       dev = get_cpu_device(cpu);
+       if (unlikely(!dev)) {
+               dev_warn(&cpufreq_cdev->cdev->device,
+                        "No cpu device for cpu %d\n", cpu);
+               return -ENODEV;
        }
 
-       if (num_opps == 0)
-               return -EINVAL;
+       num_opps = dev_pm_opp_get_opp_count(dev);
+       if (num_opps < 0)
+               return num_opps;
 
-       power_table = kcalloc(num_opps, sizeof(*power_table), GFP_KERNEL);
-       if (!power_table)
-               return -ENOMEM;
+       /*
+        * The cpufreq table is also built from the OPP table and so the count
+        * should match.
+        */
+       if (num_opps != cpufreq_cdev->max_level + 1) {
+               dev_warn(dev, "Number of OPPs not matching with max_levels\n");
+               return -EINVAL;
+       }
 
-       for (freq = 0, i = 0;
-            opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp);
-            freq++, i++) {
-               u32 freq_mhz, voltage_mv;
+       for (i = 0; i <= cpufreq_cdev->max_level; i++) {
+               unsigned long freq = freq_table[i].frequency * 1000;
+               u32 freq_mhz = freq_table[i].frequency / 1000;
                u64 power;
+               u32 voltage_mv;
 
-               if (i >= num_opps) {
-                       ret = -EAGAIN;
-                       goto free_power_table;
+               /*
+                * Find ceil frequency as 'freq' may be slightly lower than OPP
+                * freq due to truncation while converting to kHz.
+                */
+               opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+               if (IS_ERR(opp)) {
+                       dev_err(dev, "failed to get opp for %lu frequency\n",
+                               freq);
+                       return -EINVAL;
                }
 
-               freq_mhz = freq / 1000000;
                voltage_mv = dev_pm_opp_get_voltage(opp) / 1000;
                dev_pm_opp_put(opp);
 
@@ -281,89 +254,73 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
                power = (u64)capacitance * freq_mhz * voltage_mv * voltage_mv;
                do_div(power, 1000000000);
 
-               /* frequency is stored in power_table in KHz */
-               power_table[i].frequency = freq / 1000;
-
                /* power is stored in mW */
-               power_table[i].power = power;
+               freq_table[i].power = power;
        }
 
-       if (i != num_opps) {
-               ret = PTR_ERR(opp);
-               goto free_power_table;
-       }
-
-       cpufreq_device->cpu_dev = dev;
-       cpufreq_device->dyn_power_table = power_table;
-       cpufreq_device->dyn_power_table_entries = i;
-
        return 0;
-
-free_power_table:
-       kfree(power_table);
-
-       return ret;
 }
 
-static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_device,
+static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev,
                             u32 freq)
 {
        int i;
-       struct power_table *pt = cpufreq_device->dyn_power_table;
+       struct freq_table *freq_table = cpufreq_cdev->freq_table;
 
-       for (i = 1; i < cpufreq_device->dyn_power_table_entries; i++)
-               if (freq < pt[i].frequency)
+       for (i = 1; i <= cpufreq_cdev->max_level; i++)
+               if (freq > freq_table[i].frequency)
                        break;
 
-       return pt[i - 1].power;
+       return freq_table[i - 1].power;
 }
 
-static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_device,
+static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
                             u32 power)
 {
        int i;
-       struct power_table *pt = cpufreq_device->dyn_power_table;
+       struct freq_table *freq_table = cpufreq_cdev->freq_table;
 
-       for (i = 1; i < cpufreq_device->dyn_power_table_entries; i++)
-               if (power < pt[i].power)
+       for (i = 1; i <= cpufreq_cdev->max_level; i++)
+               if (power > freq_table[i].power)
                        break;
 
-       return pt[i - 1].frequency;
+       return freq_table[i - 1].frequency;
 }
 
 /**
  * get_load() - get load for a cpu since last updated
- * @cpufreq_device:    &struct cpufreq_cooling_device for this cpu
+ * @cpufreq_cdev:      &struct cpufreq_cooling_device for this cpu
  * @cpu:       cpu number
- * @cpu_idx:   index of the cpu in cpufreq_device->allowed_cpus
+ * @cpu_idx:   index of the cpu in time_in_idle*
  *
  * Return: The average load of cpu @cpu in percentage since this
  * function was last called.
  */
-static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu,
+static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
                    int cpu_idx)
 {
        u32 load;
        u64 now, now_idle, delta_time, delta_idle;
+       struct time_in_idle *idle_time = &cpufreq_cdev->idle_time[cpu_idx];
 
        now_idle = get_cpu_idle_time(cpu, &now, 0);
-       delta_idle = now_idle - cpufreq_device->time_in_idle[cpu_idx];
-       delta_time = now - cpufreq_device->time_in_idle_timestamp[cpu_idx];
+       delta_idle = now_idle - idle_time->time;
+       delta_time = now - idle_time->timestamp;
 
        if (delta_time <= delta_idle)
                load = 0;
        else
                load = div64_u64(100 * (delta_time - delta_idle), delta_time);
 
-       cpufreq_device->time_in_idle[cpu_idx] = now_idle;
-       cpufreq_device->time_in_idle_timestamp[cpu_idx] = now;
+       idle_time->time = now_idle;
+       idle_time->timestamp = now;
 
        return load;
 }
 
 /**
  * get_static_power() - calculate the static power consumed by the cpus
- * @cpufreq_device:    struct &cpufreq_cooling_device for this cpu cdev
+ * @cpufreq_cdev:      struct &cpufreq_cooling_device for this cpu cdev
  * @tz:                thermal zone device in which we're operating
  * @freq:      frequency in KHz
  * @power:     pointer in which to store the calculated static power
@@ -376,26 +333,28 @@ static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu,
  *
  * Return: 0 on success, -E* on failure.
  */
-static int get_static_power(struct cpufreq_cooling_device *cpufreq_device,
+static int get_static_power(struct cpufreq_cooling_device *cpufreq_cdev,
                            struct thermal_zone_device *tz, unsigned long freq,
                            u32 *power)
 {
        struct dev_pm_opp *opp;
        unsigned long voltage;
-       struct cpumask *cpumask = &cpufreq_device->allowed_cpus;
+       struct cpufreq_policy *policy = cpufreq_cdev->policy;
+       struct cpumask *cpumask = policy->related_cpus;
        unsigned long freq_hz = freq * 1000;
+       struct device *dev;
 
-       if (!cpufreq_device->plat_get_static_power ||
-           !cpufreq_device->cpu_dev) {
+       if (!cpufreq_cdev->plat_get_static_power) {
                *power = 0;
                return 0;
        }
 
-       opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz,
-                                        true);
+       dev = get_cpu_device(policy->cpu);
+       WARN_ON(!dev);
+
+       opp = dev_pm_opp_find_freq_exact(dev, freq_hz, true);
        if (IS_ERR(opp)) {
-               dev_warn_ratelimited(cpufreq_device->cpu_dev,
-                                    "Failed to find OPP for frequency %lu: %ld\n",
+               dev_warn_ratelimited(dev, "Failed to find OPP for frequency %lu: %ld\n",
                                     freq_hz, PTR_ERR(opp));
                return -EINVAL;
        }
@@ -404,31 +363,30 @@ static int get_static_power(struct cpufreq_cooling_device *cpufreq_device,
        dev_pm_opp_put(opp);
 
        if (voltage == 0) {
-               dev_err_ratelimited(cpufreq_device->cpu_dev,
-                                   "Failed to get voltage for frequency %lu\n",
+               dev_err_ratelimited(dev, "Failed to get voltage for frequency %lu\n",
                                    freq_hz);
                return -EINVAL;
        }
 
-       return cpufreq_device->plat_get_static_power(cpumask, tz->passive_delay,
-                                                    voltage, power);
+       return cpufreq_cdev->plat_get_static_power(cpumask, tz->passive_delay,
+                                                 voltage, power);
 }
 
 /**
  * get_dynamic_power() - calculate the dynamic power
- * @cpufreq_device:    &cpufreq_cooling_device for this cdev
+ * @cpufreq_cdev:      &cpufreq_cooling_device for this cdev
  * @freq:      current frequency
  *
  * Return: the dynamic power consumed by the cpus described by
- * @cpufreq_device.
+ * @cpufreq_cdev.
  */
-static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_device,
+static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_cdev,
                             unsigned long freq)
 {
        u32 raw_cpu_power;
 
-       raw_cpu_power = cpu_freq_to_power(cpufreq_device, freq);
-       return (raw_cpu_power * cpufreq_device->last_load) / 100;
+       raw_cpu_power = cpu_freq_to_power(cpufreq_cdev, freq);
+       return (raw_cpu_power * cpufreq_cdev->last_load) / 100;
 }
 
 /* cpufreq cooling device callback functions are defined below */
@@ -446,9 +404,9 @@ static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_device,
 static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
                                 unsigned long *state)
 {
-       struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
+       struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
 
-       *state = cpufreq_device->max_level;
+       *state = cpufreq_cdev->max_level;
        return 0;
 }
 
@@ -465,9 +423,9 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
 static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
                                 unsigned long *state)
 {
-       struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
+       struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
 
-       *state = cpufreq_device->cpufreq_state;
+       *state = cpufreq_cdev->cpufreq_state;
 
        return 0;
 }
@@ -485,23 +443,22 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
 static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
                                 unsigned long state)
 {
-       struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
-       unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus);
+       struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
        unsigned int clip_freq;
 
        /* Request state should be less than max_level */
-       if (WARN_ON(state > cpufreq_device->max_level))
+       if (WARN_ON(state > cpufreq_cdev->max_level))
                return -EINVAL;
 
        /* Check if the old cooling action is same as new cooling action */
-       if (cpufreq_device->cpufreq_state == state)
+       if (cpufreq_cdev->cpufreq_state == state)
                return 0;
 
-       clip_freq = cpufreq_device->freq_table[state];
-       cpufreq_device->cpufreq_state = state;
-       cpufreq_device->clipped_freq = clip_freq;
+       clip_freq = cpufreq_cdev->freq_table[state].frequency;
+       cpufreq_cdev->cpufreq_state = state;
+       cpufreq_cdev->clipped_freq = clip_freq;
 
-       cpufreq_update_policy(cpu);
+       cpufreq_update_policy(cpufreq_cdev->policy->cpu);
 
        return 0;
 }
@@ -536,33 +493,23 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
        unsigned long freq;
        int i = 0, cpu, ret;
        u32 static_power, dynamic_power, total_load = 0;
-       struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
+       struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
+       struct cpufreq_policy *policy = cpufreq_cdev->policy;
        u32 *load_cpu = NULL;
 
-       cpu = cpumask_any_and(&cpufreq_device->allowed_cpus, cpu_online_mask);
-
-       /*
-        * All the CPUs are offline, thus the requested power by
-        * the cdev is 0
-        */
-       if (cpu >= nr_cpu_ids) {
-               *power = 0;
-               return 0;
-       }
-
-       freq = cpufreq_quick_get(cpu);
+       freq = cpufreq_quick_get(policy->cpu);
 
        if (trace_thermal_power_cpu_get_power_enabled()) {
-               u32 ncpus = cpumask_weight(&cpufreq_device->allowed_cpus);
+               u32 ncpus = cpumask_weight(policy->related_cpus);
 
                load_cpu = kcalloc(ncpus, sizeof(*load_cpu), GFP_KERNEL);
        }
 
-       for_each_cpu(cpu, &cpufreq_device->allowed_cpus) {
+       for_each_cpu(cpu, policy->related_cpus) {
                u32 load;
 
                if (cpu_online(cpu))
-                       load = get_load(cpufreq_device, cpu, i);
+                       load = get_load(cpufreq_cdev, cpu, i);
                else
                        load = 0;
 
@@ -573,19 +520,19 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
                i++;
        }
 
-       cpufreq_device->last_load = total_load;
+       cpufreq_cdev->last_load = total_load;
 
-       dynamic_power = get_dynamic_power(cpufreq_device, freq);
-       ret = get_static_power(cpufreq_device, tz, freq, &static_power);
+       dynamic_power = get_dynamic_power(cpufreq_cdev, freq);
+       ret = get_static_power(cpufreq_cdev, tz, freq, &static_power);
        if (ret) {
                kfree(load_cpu);
                return ret;
        }
 
        if (load_cpu) {
-               trace_thermal_power_cpu_get_power(
-                       &cpufreq_device->allowed_cpus,
-                       freq, load_cpu, i, dynamic_power, static_power);
+               trace_thermal_power_cpu_get_power(policy->related_cpus, freq,
+                                                 load_cpu, i, dynamic_power,
+                                                 static_power);
 
                kfree(load_cpu);
        }
@@ -614,38 +561,23 @@ static int cpufreq_state2power(struct thermal_cooling_device *cdev,
                               unsigned long state, u32 *power)
 {
        unsigned int freq, num_cpus;
-       cpumask_var_t cpumask;
        u32 static_power, dynamic_power;
        int ret;
-       struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
-
-       if (!alloc_cpumask_var(&cpumask, GFP_KERNEL))
-               return -ENOMEM;
-
-       cpumask_and(cpumask, &cpufreq_device->allowed_cpus, cpu_online_mask);
-       num_cpus = cpumask_weight(cpumask);
+       struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
 
-       /* None of our cpus are online, so no power */
-       if (num_cpus == 0) {
-               *power = 0;
-               ret = 0;
-               goto out;
-       }
+       /* Request state should be less than max_level */
+       if (WARN_ON(state > cpufreq_cdev->max_level))
+               return -EINVAL;
 
-       freq = cpufreq_device->freq_table[state];
-       if (!freq) {
-               ret = -EINVAL;
-               goto out;
-       }
+       num_cpus = cpumask_weight(cpufreq_cdev->policy->cpus);
 
-       dynamic_power = cpu_freq_to_power(cpufreq_device, freq) * num_cpus;
-       ret = get_static_power(cpufreq_device, tz, freq, &static_power);
+       freq = cpufreq_cdev->freq_table[state].frequency;
+       dynamic_power = cpu_freq_to_power(cpufreq_cdev, freq) * num_cpus;
+       ret = get_static_power(cpufreq_cdev, tz, freq, &static_power);
        if (ret)
-               goto out;
+               return ret;
 
        *power = static_power + dynamic_power;
-out:
-       free_cpumask_var(cpumask);
        return ret;
 }
 
@@ -673,39 +605,27 @@ static int cpufreq_power2state(struct thermal_cooling_device *cdev,
                               struct thermal_zone_device *tz, u32 power,
                               unsigned long *state)
 {
-       unsigned int cpu, cur_freq, target_freq;
+       unsigned int cur_freq, target_freq;
        int ret;
        s32 dyn_power;
        u32 last_load, normalised_power, static_power;
-       struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
+       struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
+       struct cpufreq_policy *policy = cpufreq_cdev->policy;
 
-       cpu = cpumask_any_and(&cpufreq_device->allowed_cpus, cpu_online_mask);
-
-       /* None of our cpus are online */
-       if (cpu >= nr_cpu_ids)
-               return -ENODEV;
-
-       cur_freq = cpufreq_quick_get(cpu);
-       ret = get_static_power(cpufreq_device, tz, cur_freq, &static_power);
+       cur_freq = cpufreq_quick_get(policy->cpu);
+       ret = get_static_power(cpufreq_cdev, tz, cur_freq, &static_power);
        if (ret)
                return ret;
 
        dyn_power = power - static_power;
        dyn_power = dyn_power > 0 ? dyn_power : 0;
-       last_load = cpufreq_device->last_load ?: 1;
+       last_load = cpufreq_cdev->last_load ?: 1;
        normalised_power = (dyn_power * 100) / last_load;
-       target_freq = cpu_power_to_freq(cpufreq_device, normalised_power);
+       target_freq = cpu_power_to_freq(cpufreq_cdev, normalised_power);
 
-       *state = cpufreq_cooling_get_level(cpu, target_freq);
-       if (*state == THERMAL_CSTATE_INVALID) {
-               dev_err_ratelimited(&cdev->device,
-                                   "Failed to convert %dKHz for cpu %d into a cdev state\n",
-                                   target_freq, cpu);
-               return -EINVAL;
-       }
-
-       trace_thermal_power_cpu_limit(&cpufreq_device->allowed_cpus,
-                                     target_freq, *state, power);
+       *state = get_level(cpufreq_cdev, target_freq);
+       trace_thermal_power_cpu_limit(policy->related_cpus, target_freq, *state,
+                                     power);
        return 0;
 }
 
@@ -748,7 +668,7 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table,
 /**
  * __cpufreq_cooling_register - helper function to create cpufreq cooling device
  * @np: a valid struct device_node to the cooling device device tree node
- * @clip_cpus: cpumask of cpus where the frequency constraints will happen.
+ * @policy: cpufreq policy
  * Normally this should be same as cpufreq policy->related_cpus.
  * @capacitance: dynamic power coefficient for these cpus
  * @plat_static_func: function to calculate the static power consumed by these
@@ -764,102 +684,68 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table,
  */
 static struct thermal_cooling_device *
 __cpufreq_cooling_register(struct device_node *np,
-                       const struct cpumask *clip_cpus, u32 capacitance,
+                       struct cpufreq_policy *policy, u32 capacitance,
                        get_static_t plat_static_func)
 {
-       struct cpufreq_policy *policy;
-       struct thermal_cooling_device *cool_dev;
-       struct cpufreq_cooling_device *cpufreq_dev;
+       struct thermal_cooling_device *cdev;
+       struct cpufreq_cooling_device *cpufreq_cdev;
        char dev_name[THERMAL_NAME_LENGTH];
-       struct cpufreq_frequency_table *pos, *table;
-       cpumask_var_t temp_mask;
        unsigned int freq, i, num_cpus;
        int ret;
        struct thermal_cooling_device_ops *cooling_ops;
        bool first;
 
-       if (!alloc_cpumask_var(&temp_mask, GFP_KERNEL))
-               return ERR_PTR(-ENOMEM);
-
-       cpumask_and(temp_mask, clip_cpus, cpu_online_mask);
-       policy = cpufreq_cpu_get(cpumask_first(temp_mask));
-       if (!policy) {
-               pr_debug("%s: CPUFreq policy not found\n", __func__);
-               cool_dev = ERR_PTR(-EPROBE_DEFER);
-               goto free_cpumask;
+       if (IS_ERR_OR_NULL(policy)) {
+               pr_err("%s: cpufreq policy isn't valid: %p", __func__, policy);
+               return ERR_PTR(-EINVAL);
        }
 
-       table = policy->freq_table;
-       if (!table) {
-               pr_debug("%s: CPUFreq table not found\n", __func__);
-               cool_dev = ERR_PTR(-ENODEV);
-               goto put_policy;
+       i = cpufreq_table_count_valid_entries(policy);
+       if (!i) {
+               pr_debug("%s: CPUFreq table not found or has no valid entries\n",
+                        __func__);
+               return ERR_PTR(-ENODEV);
        }
 
-       cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL);
-       if (!cpufreq_dev) {
-               cool_dev = ERR_PTR(-ENOMEM);
-               goto put_policy;
-       }
+       cpufreq_cdev = kzalloc(sizeof(*cpufreq_cdev), GFP_KERNEL);
+       if (!cpufreq_cdev)
+               return ERR_PTR(-ENOMEM);
 
-       num_cpus = cpumask_weight(clip_cpus);
-       cpufreq_dev->time_in_idle = kcalloc(num_cpus,
-                                           sizeof(*cpufreq_dev->time_in_idle),
-                                           GFP_KERNEL);
-       if (!cpufreq_dev->time_in_idle) {
-               cool_dev = ERR_PTR(-ENOMEM);
+       cpufreq_cdev->policy = policy;
+       num_cpus = cpumask_weight(policy->related_cpus);
+       cpufreq_cdev->idle_time = kcalloc(num_cpus,
+                                        sizeof(*cpufreq_cdev->idle_time),
+                                        GFP_KERNEL);
+       if (!cpufreq_cdev->idle_time) {
+               cdev = ERR_PTR(-ENOMEM);
                goto free_cdev;
        }
 
-       cpufreq_dev->time_in_idle_timestamp =
-               kcalloc(num_cpus, sizeof(*cpufreq_dev->time_in_idle_timestamp),
-                       GFP_KERNEL);
-       if (!cpufreq_dev->time_in_idle_timestamp) {
-               cool_dev = ERR_PTR(-ENOMEM);
-               goto free_time_in_idle;
-       }
-
-       /* Find max levels */
-       cpufreq_for_each_valid_entry(pos, table)
-               cpufreq_dev->max_level++;
-
-       cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) *
-                                         cpufreq_dev->max_level, GFP_KERNEL);
-       if (!cpufreq_dev->freq_table) {
-               cool_dev = ERR_PTR(-ENOMEM);
-               goto free_time_in_idle_timestamp;
-       }
-
        /* max_level is an index, not a counter */
-       cpufreq_dev->max_level--;
-
-       cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus);
-
-       if (capacitance) {
-               cpufreq_dev->plat_get_static_power = plat_static_func;
-
-               ret = build_dyn_power_table(cpufreq_dev, capacitance);
-               if (ret) {
-                       cool_dev = ERR_PTR(ret);
-                       goto free_table;
-               }
-
-               cooling_ops = &cpufreq_power_cooling_ops;
-       } else {
-               cooling_ops = &cpufreq_cooling_ops;
+       cpufreq_cdev->max_level = i - 1;
+
+       cpufreq_cdev->freq_table = kmalloc_array(i,
+                                       sizeof(*cpufreq_cdev->freq_table),
+                                       GFP_KERNEL);
+       if (!cpufreq_cdev->freq_table) {
+               cdev = ERR_PTR(-ENOMEM);
+               goto free_idle_time;
        }
 
        ret = ida_simple_get(&cpufreq_ida, 0, 0, GFP_KERNEL);
        if (ret < 0) {
-               cool_dev = ERR_PTR(ret);
-               goto free_power_table;
+               cdev = ERR_PTR(ret);
+               goto free_table;
        }
-       cpufreq_dev->id = ret;
+       cpufreq_cdev->id = ret;
+
+       snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
+                cpufreq_cdev->id);
 
        /* Fill freq-table in descending order of frequencies */
-       for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) {
-               freq = find_next_max(table, freq);
-               cpufreq_dev->freq_table[i] = freq;
+       for (i = 0, freq = -1; i <= cpufreq_cdev->max_level; i++) {
+               freq = find_next_max(policy->freq_table, freq);
+               cpufreq_cdev->freq_table[i].frequency = freq;
 
                /* Warn for duplicate entries */
                if (!freq)
@@ -868,51 +754,54 @@ __cpufreq_cooling_register(struct device_node *np,
                        pr_debug("%s: freq:%u KHz\n", __func__, freq);
        }
 
-       snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
-                cpufreq_dev->id);
+       if (capacitance) {
+               cpufreq_cdev->plat_get_static_power = plat_static_func;
+
+               ret = update_freq_table(cpufreq_cdev, capacitance);
+               if (ret) {
+                       cdev = ERR_PTR(ret);
+                       goto remove_ida;
+               }
+
+               cooling_ops = &cpufreq_power_cooling_ops;
+       } else {
+               cooling_ops = &cpufreq_cooling_ops;
+       }
 
-       cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev,
-                                                     cooling_ops);
-       if (IS_ERR(cool_dev))
+       cdev = thermal_of_cooling_device_register(np, dev_name, cpufreq_cdev,
+                                                 cooling_ops);
+       if (IS_ERR(cdev))
                goto remove_ida;
 
-       cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0];
-       cpufreq_dev->cool_dev = cool_dev;
+       cpufreq_cdev->clipped_freq = cpufreq_cdev->freq_table[0].frequency;
+       cpufreq_cdev->cdev = cdev;
 
        mutex_lock(&cooling_list_lock);
        /* Register the notifier for first cpufreq cooling device */
-       first = list_empty(&cpufreq_dev_list);
-       list_add(&cpufreq_dev->node, &cpufreq_dev_list);
+       first = list_empty(&cpufreq_cdev_list);
+       list_add(&cpufreq_cdev->node, &cpufreq_cdev_list);
        mutex_unlock(&cooling_list_lock);
 
        if (first)
                cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
                                          CPUFREQ_POLICY_NOTIFIER);
 
-       goto put_policy;
+       return cdev;
 
 remove_ida:
-       ida_simple_remove(&cpufreq_ida, cpufreq_dev->id);
-free_power_table:
-       kfree(cpufreq_dev->dyn_power_table);
+       ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
 free_table:
-       kfree(cpufreq_dev->freq_table);
-free_time_in_idle_timestamp:
-       kfree(cpufreq_dev->time_in_idle_timestamp);
-free_time_in_idle:
-       kfree(cpufreq_dev->time_in_idle);
+       kfree(cpufreq_cdev->freq_table);
+free_idle_time:
+       kfree(cpufreq_cdev->idle_time);
 free_cdev:
-       kfree(cpufreq_dev);
-put_policy:
-       cpufreq_cpu_put(policy);
-free_cpumask:
-       free_cpumask_var(temp_mask);
-       return cool_dev;
+       kfree(cpufreq_cdev);
+       return cdev;
 }
 
 /**
  * cpufreq_cooling_register - function to create cpufreq cooling device.
- * @clip_cpus: cpumask of cpus where the frequency constraints will happen.
+ * @policy: cpufreq policy
  *
  * This interface function registers the cpufreq cooling device with the name
  * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
@@ -922,16 +811,16 @@ free_cpumask:
  * on failure, it returns a corresponding ERR_PTR().
  */
 struct thermal_cooling_device *
-cpufreq_cooling_register(const struct cpumask *clip_cpus)
+cpufreq_cooling_register(struct cpufreq_policy *policy)
 {
-       return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL);
+       return __cpufreq_cooling_register(NULL, policy, 0, NULL);
 }
 EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
 
 /**
  * of_cpufreq_cooling_register - function to create cpufreq cooling device.
  * @np: a valid struct device_node to the cooling device device tree node
- * @clip_cpus: cpumask of cpus where the frequency constraints will happen.
+ * @policy: cpufreq policy
  *
  * This interface function registers the cpufreq cooling device with the name
  * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
@@ -943,18 +832,18 @@ EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
  */
 struct thermal_cooling_device *
 of_cpufreq_cooling_register(struct device_node *np,
-                           const struct cpumask *clip_cpus)
+                           struct cpufreq_policy *policy)
 {
        if (!np)
                return ERR_PTR(-EINVAL);
 
-       return __cpufreq_cooling_register(np, clip_cpus, 0, NULL);
+       return __cpufreq_cooling_register(np, policy, 0, NULL);
 }
 EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
 
 /**
  * cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions
- * @clip_cpus: cpumask of cpus where the frequency constraints will happen
+ * @policy:            cpufreq policy
  * @capacitance:       dynamic power coefficient for these cpus
  * @plat_static_func:  function to calculate the static power consumed by these
  *                     cpus (optional)
@@ -974,10 +863,10 @@ EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
  * on failure, it returns a corresponding ERR_PTR().
  */
 struct thermal_cooling_device *
-cpufreq_power_cooling_register(const struct cpumask *clip_cpus, u32 capacitance,
+cpufreq_power_cooling_register(struct cpufreq_policy *policy, u32 capacitance,
                               get_static_t plat_static_func)
 {
-       return __cpufreq_cooling_register(NULL, clip_cpus, capacitance,
+       return __cpufreq_cooling_register(NULL, policy, capacitance,
                                plat_static_func);
 }
 EXPORT_SYMBOL(cpufreq_power_cooling_register);
@@ -985,7 +874,7 @@ EXPORT_SYMBOL(cpufreq_power_cooling_register);
 /**
  * of_cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions
  * @np:        a valid struct device_node to the cooling device device tree node
- * @clip_cpus: cpumask of cpus where the frequency constraints will happen
+ * @policy: cpufreq policy
  * @capacitance:       dynamic power coefficient for these cpus
  * @plat_static_func:  function to calculate the static power consumed by these
  *                     cpus (optional)
@@ -1007,14 +896,14 @@ EXPORT_SYMBOL(cpufreq_power_cooling_register);
  */
 struct thermal_cooling_device *
 of_cpufreq_power_cooling_register(struct device_node *np,
-                                 const struct cpumask *clip_cpus,
+                                 struct cpufreq_policy *policy,
                                  u32 capacitance,
                                  get_static_t plat_static_func)
 {
        if (!np)
                return ERR_PTR(-EINVAL);
 
-       return __cpufreq_cooling_register(np, clip_cpus, capacitance,
+       return __cpufreq_cooling_register(np, policy, capacitance,
                                plat_static_func);
 }
 EXPORT_SYMBOL(of_cpufreq_power_cooling_register);
@@ -1027,30 +916,28 @@ EXPORT_SYMBOL(of_cpufreq_power_cooling_register);
  */
 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 {
-       struct cpufreq_cooling_device *cpufreq_dev;
+       struct cpufreq_cooling_device *cpufreq_cdev;
        bool last;
 
        if (!cdev)
                return;
 
-       cpufreq_dev = cdev->devdata;
+       cpufreq_cdev = cdev->devdata;
 
        mutex_lock(&cooling_list_lock);
-       list_del(&cpufreq_dev->node);
+       list_del(&cpufreq_cdev->node);
        /* Unregister the notifier for the last cpufreq cooling device */
-       last = list_empty(&cpufreq_dev_list);
+       last = list_empty(&cpufreq_cdev_list);
        mutex_unlock(&cooling_list_lock);
 
        if (last)
                cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
                                            CPUFREQ_POLICY_NOTIFIER);
 
-       thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
-       ida_simple_remove(&cpufreq_ida, cpufreq_dev->id);
-       kfree(cpufreq_dev->dyn_power_table);
-       kfree(cpufreq_dev->time_in_idle_timestamp);
-       kfree(cpufreq_dev->time_in_idle);
-       kfree(cpufreq_dev->freq_table);
-       kfree(cpufreq_dev);
+       thermal_cooling_device_unregister(cpufreq_cdev->cdev);
+       ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
+       kfree(cpufreq_cdev->idle_time);
+       kfree(cpufreq_cdev->freq_table);
+       kfree(cpufreq_cdev);
 }
 EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister);
index 68bd1b5..d3469fb 100644 (file)
@@ -71,6 +71,7 @@ static long get_target_state(struct thermal_zone_device *tz,
 /**
  * fair_share_throttle - throttles devices associated with the given zone
  * @tz - thermal_zone_device
+ * @trip - trip point index
  *
  * Throttling Logic: This uses three parameters to calculate the new
  * throttle state of the cooling devices associated with the given zone.
index f642966..9c3ce34 100644 (file)
@@ -397,8 +397,11 @@ static int hisi_thermal_suspend(struct device *dev)
 static int hisi_thermal_resume(struct device *dev)
 {
        struct hisi_thermal_data *data = dev_get_drvdata(dev);
+       int ret;
 
-       clk_prepare_enable(data->clk);
+       ret = clk_prepare_enable(data->clk);
+       if (ret)
+               return ret;
 
        data->irq_enabled = true;
        hisi_thermal_enable_bind_irq_sensor(data);
index fb648a4..4798b4b 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/cpufreq.h>
 #include <linux/cpu_cooling.h>
 #include <linux/delay.h>
 #include <linux/device.h>
@@ -88,6 +89,7 @@ static struct thermal_soc_data thermal_imx6sx_data = {
 };
 
 struct imx_thermal_data {
+       struct cpufreq_policy *policy;
        struct thermal_zone_device *tz;
        struct thermal_cooling_device *cdev;
        enum thermal_device_mode mode;
@@ -525,13 +527,18 @@ static int imx_thermal_probe(struct platform_device *pdev)
        regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF);
        regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
 
-       data->cdev = cpufreq_cooling_register(cpu_present_mask);
+       data->policy = cpufreq_cpu_get(0);
+       if (!data->policy) {
+               pr_debug("%s: CPUFreq policy not found\n", __func__);
+               return -EPROBE_DEFER;
+       }
+
+       data->cdev = cpufreq_cooling_register(data->policy);
        if (IS_ERR(data->cdev)) {
                ret = PTR_ERR(data->cdev);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(&pdev->dev,
-                               "failed to register cpufreq cooling device: %d\n",
-                               ret);
+               dev_err(&pdev->dev,
+                       "failed to register cpufreq cooling device: %d\n", ret);
+               cpufreq_cpu_put(data->policy);
                return ret;
        }
 
@@ -542,6 +549,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev,
                                "failed to get thermal clk: %d\n", ret);
                cpufreq_cooling_unregister(data->cdev);
+               cpufreq_cpu_put(data->policy);
                return ret;
        }
 
@@ -556,6 +564,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
                cpufreq_cooling_unregister(data->cdev);
+               cpufreq_cpu_put(data->policy);
                return ret;
        }
 
@@ -571,6 +580,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
                        "failed to register thermal zone device %d\n", ret);
                clk_disable_unprepare(data->thermal_clk);
                cpufreq_cooling_unregister(data->cdev);
+               cpufreq_cpu_put(data->policy);
                return ret;
        }
 
@@ -599,6 +609,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
                clk_disable_unprepare(data->thermal_clk);
                thermal_zone_device_unregister(data->tz);
                cpufreq_cooling_unregister(data->cdev);
+               cpufreq_cpu_put(data->policy);
                return ret;
        }
 
@@ -620,6 +631,7 @@ static int imx_thermal_remove(struct platform_device *pdev)
 
        thermal_zone_device_unregister(data->tz);
        cpufreq_cooling_unregister(data->cdev);
+       cpufreq_cpu_put(data->policy);
 
        return 0;
 }
@@ -648,8 +660,11 @@ static int imx_thermal_resume(struct device *dev)
 {
        struct imx_thermal_data *data = dev_get_drvdata(dev);
        struct regmap *map = data->tempmon;
+       int ret;
 
-       clk_prepare_enable(data->thermal_clk);
+       ret = clk_prepare_enable(data->thermal_clk);
+       if (ret)
+               return ret;
        /* Enabled thermal sensor after resume */
        regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
        regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
index 2c2ec76..51ceb80 100644 (file)
@@ -62,8 +62,8 @@ static int acpi_thermal_rel_release(struct inode *inode, struct file *file)
  * acpi_parse_trt - Thermal Relationship Table _TRT for passive cooling
  *
  * @handle: ACPI handle of the device contains _TRT
- * @art_count: the number of valid entries resulted from parsing _TRT
- * @artp: pointer to pointer of array of art entries in parsing result
+ * @trt_count: the number of valid entries resulted from parsing _TRT
+ * @trtp: pointer to pointer of array of _TRT entries in parsing result
  * @create_dev: whether to create platform devices for target and source
  *
  */
@@ -208,7 +208,7 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
                if (art->target) {
                        result = acpi_bus_get_device(art->target, &adev);
                        if (result)
-                               pr_warn("Failed to get source ACPI device\n");
+                               pr_warn("Failed to get target ACPI device\n");
                }
        }
 
index c4890c9..8a7f24d 100644 (file)
@@ -238,8 +238,16 @@ static int int3403_add(struct platform_device *pdev)
        status = acpi_evaluate_integer(priv->adev->handle, "PTYP",
                                       NULL, &priv->type);
        if (ACPI_FAILURE(status)) {
-               result = -EINVAL;
-               goto err;
+               unsigned long long tmp;
+
+               status = acpi_evaluate_integer(priv->adev->handle, "_TMP",
+                                              NULL, &tmp);
+               if (ACPI_FAILURE(status)) {
+                       result = -EINVAL;
+                       goto err;
+               } else {
+                       priv->type = INT3403_TYPE_SENSOR;
+               }
        }
 
        platform_set_drvdata(pdev, priv);
index bcef2e7..be95826 100644 (file)
@@ -186,8 +186,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
 /**
  * step_wise_throttle - throttles devices associated with the given zone
  * @tz - thermal_zone_device
- * @trip - the trip point
- * @trip_type - type of the trip point
+ * @trip - trip point index
  *
  * Throttling Logic: This uses the trend of the thermal zone to throttle.
  * If the thermal zone is 'heating up' this throttles all the cooling
index 02790f6..c211a8e 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/workqueue.h>
 #include <linux/thermal.h>
+#include <linux/cpufreq.h>
 #include <linux/cpumask.h>
 #include <linux/cpu_cooling.h>
 #include <linux/of.h>
@@ -37,6 +38,7 @@
 
 /* common data structures */
 struct ti_thermal_data {
+       struct cpufreq_policy *policy;
        struct thermal_zone_device *ti_thermal;
        struct thermal_zone_device *pcb_tz;
        struct thermal_cooling_device *cool_dev;
@@ -247,15 +249,19 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
        if (!data)
                return -EINVAL;
 
+       data->policy = cpufreq_cpu_get(0);
+       if (!data->policy) {
+               pr_debug("%s: CPUFreq policy not found\n", __func__);
+               return -EPROBE_DEFER;
+       }
+
        /* Register cooling device */
-       data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
+       data->cool_dev = cpufreq_cooling_register(data->policy);
        if (IS_ERR(data->cool_dev)) {
                int ret = PTR_ERR(data->cool_dev);
-
-               if (ret != -EPROBE_DEFER)
-                       dev_err(bgp->dev,
-                               "Failed to register cpu cooling device %d\n",
-                               ret);
+               dev_err(bgp->dev, "Failed to register cpu cooling device %d\n",
+                       ret);
+               cpufreq_cpu_put(data->policy);
 
                return ret;
        }
@@ -270,8 +276,10 @@ int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
 
        data = ti_bandgap_get_sensor_data(bgp, id);
 
-       if (data)
+       if (data) {
                cpufreq_cooling_unregister(data->cool_dev);
+               cpufreq_cpu_put(data->policy);
+       }
 
        return 0;
 }
index c908150..8e92a06 100644 (file)
 
 #include <linux/thermal.h>
 #include <linux/slab.h>
+
 #include "thermal_core.h"
 
 /**
  * notify_user_space - Notifies user space about thermal events
  * @tz - thermal_zone_device
- * @trip - Trip point index
+ * @trip - trip point index
  *
  * This function notifies the user space through UEvents.
  */
index ab3e8f4..e9391bb 100644 (file)
@@ -30,7 +30,7 @@ static DEFINE_IDA(nvm_ida);
 
 struct nvm_auth_status {
        struct list_head list;
-       uuid_be uuid;
+       uuid_t uuid;
        u32 status;
 };
 
@@ -47,7 +47,7 @@ static struct nvm_auth_status *__nvm_get_auth_status(const struct tb_switch *sw)
        struct nvm_auth_status *st;
 
        list_for_each_entry(st, &nvm_auth_status_cache, list) {
-               if (!uuid_be_cmp(st->uuid, *sw->uuid))
+               if (uuid_equal(&st->uuid, sw->uuid))
                        return st;
        }
 
@@ -281,9 +281,11 @@ static struct nvmem_device *register_nvmem(struct tb_switch *sw, int id,
        if (active) {
                config.name = "nvm_active";
                config.reg_read = tb_switch_nvm_read;
+               config.read_only = true;
        } else {
                config.name = "nvm_non_active";
                config.reg_write = tb_switch_nvm_write;
+               config.root_only = true;
        }
 
        config.id = id;
@@ -292,7 +294,6 @@ static struct nvmem_device *register_nvmem(struct tb_switch *sw, int id,
        config.size = size;
        config.dev = &sw->dev;
        config.owner = THIS_MODULE;
-       config.root_only = true;
        config.priv = sw;
 
        return nvmem_register(&config);
@@ -1460,7 +1461,7 @@ struct tb_sw_lookup {
        struct tb *tb;
        u8 link;
        u8 depth;
-       const uuid_be *uuid;
+       const uuid_t *uuid;
 };
 
 static int tb_switch_match(struct device *dev, void *data)
@@ -1517,7 +1518,7 @@ struct tb_switch *tb_switch_find_by_link_depth(struct tb *tb, u8 link, u8 depth)
  * Returned switch has reference count increased so the caller needs to
  * call tb_switch_put() when done with the switch.
  */
-struct tb_switch *tb_switch_find_by_uuid(struct tb *tb, const uuid_be *uuid)
+struct tb_switch *tb_switch_find_by_uuid(struct tb *tb, const uuid_t *uuid)
 {
        struct tb_sw_lookup lookup;
        struct device *dev;
index 3d9f646..e0deee4 100644 (file)
@@ -101,7 +101,7 @@ struct tb_switch {
        struct tb_dma_port *dma_port;
        struct tb *tb;
        u64 uid;
-       uuid_be *uuid;
+       uuid_t *uuid;
        u16 vendor;
        u16 device;
        const char *vendor_name;
@@ -407,7 +407,7 @@ void tb_sw_set_unplugged(struct tb_switch *sw);
 struct tb_switch *get_switch_at_route(struct tb_switch *sw, u64 route);
 struct tb_switch *tb_switch_find_by_link_depth(struct tb *tb, u8 link,
                                               u8 depth);
-struct tb_switch *tb_switch_find_by_uuid(struct tb *tb, const uuid_be *uuid);
+struct tb_switch *tb_switch_find_by_uuid(struct tb *tb, const uuid_t *uuid);
 
 static inline unsigned int tb_switch_phy_port_from_link(unsigned int link)
 {
index 85b6d33..de6441e 100644 (file)
@@ -179,7 +179,7 @@ struct icm_fr_pkg_get_topology_response {
 
 struct icm_fr_event_device_connected {
        struct icm_pkg_header hdr;
-       uuid_be ep_uuid;
+       uuid_t ep_uuid;
        u8 connection_key;
        u8 connection_id;
        u16 link_info;
@@ -193,7 +193,7 @@ struct icm_fr_event_device_connected {
 
 struct icm_fr_pkg_approve_device {
        struct icm_pkg_header hdr;
-       uuid_be ep_uuid;
+       uuid_t ep_uuid;
        u8 connection_key;
        u8 connection_id;
        u16 reserved;
@@ -207,7 +207,7 @@ struct icm_fr_event_device_disconnected {
 
 struct icm_fr_pkg_add_device_key {
        struct icm_pkg_header hdr;
-       uuid_be ep_uuid;
+       uuid_t ep_uuid;
        u8 connection_key;
        u8 connection_id;
        u16 reserved;
@@ -216,7 +216,7 @@ struct icm_fr_pkg_add_device_key {
 
 struct icm_fr_pkg_add_device_key_response {
        struct icm_pkg_header hdr;
-       uuid_be ep_uuid;
+       uuid_t ep_uuid;
        u8 connection_key;
        u8 connection_id;
        u16 reserved;
@@ -224,7 +224,7 @@ struct icm_fr_pkg_add_device_key_response {
 
 struct icm_fr_pkg_challenge_device {
        struct icm_pkg_header hdr;
-       uuid_be ep_uuid;
+       uuid_t ep_uuid;
        u8 connection_key;
        u8 connection_id;
        u16 reserved;
@@ -233,7 +233,7 @@ struct icm_fr_pkg_challenge_device {
 
 struct icm_fr_pkg_challenge_device_response {
        struct icm_pkg_header hdr;
-       uuid_be ep_uuid;
+       uuid_t ep_uuid;
        u8 connection_key;
        u8 connection_id;
        u16 reserved;
index d1399aa..284749f 100644 (file)
@@ -448,48 +448,6 @@ err:
        return retval;
 }
 
-/**
- *     pty_open_peer - open the peer of a pty
- *     @tty: the peer of the pty being opened
- *
- *     Open the cached dentry in tty->link, providing a safe way for userspace
- *     to get the slave end of a pty (where they have the master fd and cannot
- *     access or trust the mount namespace /dev/pts was mounted inside).
- */
-static struct file *pty_open_peer(struct tty_struct *tty, int flags)
-{
-       if (tty->driver->subtype != PTY_TYPE_MASTER)
-               return ERR_PTR(-EIO);
-       return dentry_open(tty->link->driver_data, flags, current_cred());
-}
-
-static int pty_get_peer(struct tty_struct *tty, int flags)
-{
-       int fd = -1;
-       struct file *filp = NULL;
-       int retval = -EINVAL;
-
-       fd = get_unused_fd_flags(0);
-       if (fd < 0) {
-               retval = fd;
-               goto err;
-       }
-
-       filp = pty_open_peer(tty, flags);
-       if (IS_ERR(filp)) {
-               retval = PTR_ERR(filp);
-               goto err_put;
-       }
-
-       fd_install(fd, filp);
-       return fd;
-
-err_put:
-       put_unused_fd(fd);
-err:
-       return retval;
-}
-
 static void pty_cleanup(struct tty_struct *tty)
 {
        tty_port_put(tty->port);
@@ -646,9 +604,50 @@ static inline void legacy_pty_init(void) { }
 
 /* Unix98 devices */
 #ifdef CONFIG_UNIX98_PTYS
-
 static struct cdev ptmx_cdev;
 
+/**
+ *     pty_open_peer - open the peer of a pty
+ *     @tty: the peer of the pty being opened
+ *
+ *     Open the cached dentry in tty->link, providing a safe way for userspace
+ *     to get the slave end of a pty (where they have the master fd and cannot
+ *     access or trust the mount namespace /dev/pts was mounted inside).
+ */
+static struct file *pty_open_peer(struct tty_struct *tty, int flags)
+{
+       if (tty->driver->subtype != PTY_TYPE_MASTER)
+               return ERR_PTR(-EIO);
+       return dentry_open(tty->link->driver_data, flags, current_cred());
+}
+
+static int pty_get_peer(struct tty_struct *tty, int flags)
+{
+       int fd = -1;
+       struct file *filp = NULL;
+       int retval = -EINVAL;
+
+       fd = get_unused_fd_flags(0);
+       if (fd < 0) {
+               retval = fd;
+               goto err;
+       }
+
+       filp = pty_open_peer(tty, flags);
+       if (IS_ERR(filp)) {
+               retval = PTR_ERR(filp);
+               goto err_put;
+       }
+
+       fd_install(fd, filp);
+       return fd;
+
+err_put:
+       put_unused_fd(fd);
+err:
+       return retval;
+}
+
 static int pty_unix98_ioctl(struct tty_struct *tty,
                            unsigned int cmd, unsigned long arg)
 {
index 343de8c..898dcb0 100644 (file)
@@ -619,6 +619,12 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port)
                TIOCSER_TEMT : 0;
 }
 
+static bool lpuart_is_32(struct lpuart_port *sport)
+{
+       return sport->port.iotype == UPIO_MEM32 ||
+              sport->port.iotype ==  UPIO_MEM32BE;
+}
+
 static irqreturn_t lpuart_txint(int irq, void *dev_id)
 {
        struct lpuart_port *sport = dev_id;
@@ -627,7 +633,7 @@ static irqreturn_t lpuart_txint(int irq, void *dev_id)
 
        spin_lock_irqsave(&sport->port.lock, flags);
        if (sport->port.x_char) {
-               if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
+               if (lpuart_is_32(sport))
                        lpuart32_write(&sport->port, sport->port.x_char, UARTDATA);
                else
                        writeb(sport->port.x_char, sport->port.membase + UARTDR);
@@ -635,14 +641,14 @@ static irqreturn_t lpuart_txint(int irq, void *dev_id)
        }
 
        if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
-               if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
+               if (lpuart_is_32(sport))
                        lpuart32_stop_tx(&sport->port);
                else
                        lpuart_stop_tx(&sport->port);
                goto out;
        }
 
-       if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
+       if (lpuart_is_32(sport))
                lpuart32_transmit_buffer(sport);
        else
                lpuart_transmit_buffer(sport);
@@ -1978,12 +1984,12 @@ static int __init lpuart_console_setup(struct console *co, char *options)
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
        else
-               if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
+               if (lpuart_is_32(sport))
                        lpuart32_console_get_options(sport, &baud, &parity, &bits);
                else
                        lpuart_console_get_options(sport, &baud, &parity, &bits);
 
-       if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
+       if (lpuart_is_32(sport))
                lpuart32_setup_watermark(sport);
        else
                lpuart_setup_watermark(sport);
@@ -2118,7 +2124,7 @@ static int lpuart_probe(struct platform_device *pdev)
        }
        sport->port.irq = ret;
        sport->port.iotype = sdata->iotype;
-       if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
+       if (lpuart_is_32(sport))
                sport->port.ops = &lpuart32_pops;
        else
                sport->port.ops = &lpuart_pops;
@@ -2145,7 +2151,7 @@ static int lpuart_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, &sport->port);
 
-       if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
+       if (lpuart_is_32(sport))
                lpuart_reg.cons = LPUART32_CONSOLE;
        else
                lpuart_reg.cons = LPUART_CONSOLE;
@@ -2198,7 +2204,7 @@ static int lpuart_suspend(struct device *dev)
        struct lpuart_port *sport = dev_get_drvdata(dev);
        unsigned long temp;
 
-       if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) {
+       if (lpuart_is_32(sport)) {
                /* disable Rx/Tx and interrupts */
                temp = lpuart32_read(&sport->port, UARTCTRL);
                temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
@@ -2249,7 +2255,7 @@ static int lpuart_resume(struct device *dev)
        if (sport->port.suspended && !sport->port.irq_wake)
                clk_prepare_enable(sport->clk);
 
-       if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) {
+       if (lpuart_is_32(sport)) {
                lpuart32_setup_watermark(sport);
                temp = lpuart32_read(&sport->port, UARTCTRL);
                temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE |
index 9e3162b..80934e7 100644 (file)
 
 #define UART_NR 8
 
-/* RX DMA buffer periods */
-#define RX_DMA_PERIODS 4
-#define RX_BUF_SIZE    (PAGE_SIZE)
-
-
 /* i.MX21 type uart runs on all i.mx except i.MX1 and i.MX6q */
 enum imx_uart_type {
        IMX1_UART,
@@ -226,7 +221,6 @@ struct imx_port {
        struct dma_chan         *dma_chan_rx, *dma_chan_tx;
        struct scatterlist      rx_sgl, tx_sgl[2];
        void                    *rx_buf;
-       unsigned int            rx_buf_size;
        struct circ_buf         rx_ring;
        unsigned int            rx_periods;
        dma_cookie_t            rx_cookie;
@@ -464,7 +458,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
                }
        }
 
-       while (!uart_circ_empty(xmit) &&
+       while (!uart_circ_empty(xmit) && !sport->dma_is_txing &&
               !(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) {
                /* send xmit->buf[xmit->tail]
                 * out the port here */
@@ -967,6 +961,8 @@ static void imx_timeout(unsigned long data)
        }
 }
 
+#define RX_BUF_SIZE    (PAGE_SIZE)
+
 /*
  * There are two kinds of RX DMA interrupts(such as in the MX6Q):
  *   [1] the RX DMA buffer is full.
@@ -1049,6 +1045,9 @@ static void dma_rx_callback(void *data)
        }
 }
 
+/* RX DMA buffer periods */
+#define RX_DMA_PERIODS 4
+
 static int start_rx_dma(struct imx_port *sport)
 {
        struct scatterlist *sgl = &sport->rx_sgl;
@@ -1059,8 +1058,9 @@ static int start_rx_dma(struct imx_port *sport)
 
        sport->rx_ring.head = 0;
        sport->rx_ring.tail = 0;
+       sport->rx_periods = RX_DMA_PERIODS;
 
-       sg_init_one(sgl, sport->rx_buf, sport->rx_buf_size);
+       sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE);
        ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE);
        if (ret == 0) {
                dev_err(dev, "DMA mapping error for RX.\n");
@@ -1171,7 +1171,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
                goto err;
        }
 
-       sport->rx_buf = kzalloc(sport->rx_buf_size, GFP_KERNEL);
+       sport->rx_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
        if (!sport->rx_buf) {
                ret = -ENOMEM;
                goto err;
@@ -2036,7 +2036,6 @@ static int serial_imx_probe_dt(struct imx_port *sport,
 {
        struct device_node *np = pdev->dev.of_node;
        int ret;
-       u32 dma_buf_size[2];
 
        sport->devdata = of_device_get_match_data(&pdev->dev);
        if (!sport->devdata)
@@ -2060,14 +2059,6 @@ static int serial_imx_probe_dt(struct imx_port *sport,
        if (of_get_property(np, "rts-gpios", NULL))
                sport->have_rtsgpio = 1;
 
-       if (!of_property_read_u32_array(np, "fsl,dma-size", dma_buf_size, 2)) {
-               sport->rx_buf_size = dma_buf_size[0] * dma_buf_size[1];
-               sport->rx_periods = dma_buf_size[1];
-       } else {
-               sport->rx_buf_size = RX_BUF_SIZE;
-               sport->rx_periods = RX_DMA_PERIODS;
-       }
-
        return 0;
 }
 #else
index 2a61dd6..906ee77 100644 (file)
@@ -377,7 +377,7 @@ static struct ioc3_port *get_ioc3_port(struct uart_port *the_port)
  *                     called per port from attach...
  * @port: port to initialize
  */
-static int inline port_init(struct ioc3_port *port)
+static inline int port_init(struct ioc3_port *port)
 {
        uint32_t sio_cr;
        struct port_hooks *hooks = port->ip_hooks;
@@ -1430,7 +1430,7 @@ static int receive_chars(struct uart_port *the_port)
  * @pending: interrupts to handle
  */
 
-static int inline
+static inline int
 ioc3uart_intr_one(struct ioc3_submodule *is,
                        struct ioc3_driver_data *idd,
                        unsigned int pending)
index f96bcf9..43d7d32 100644 (file)
@@ -824,7 +824,7 @@ pending_intrs(struct ioc4_soft *soft, int type)
  *                     called per port from attach...
  * @port: port to initialize
  */
-static int inline port_init(struct ioc4_port *port)
+static inline int port_init(struct ioc4_port *port)
 {
        uint32_t sio_cr;
        struct hooks *hooks = port->ip_hooks;
@@ -1048,7 +1048,7 @@ static irqreturn_t ioc4_intr(int irq, void *arg)
  *                     IOC4 with serial ports in the system.
  * @idd: Master module data for this IOC4
  */
-static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
+static inline int ioc4_attach_local(struct ioc4_driver_data *idd)
 {
        struct ioc4_port *port;
        struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS];
index da5ddfc..e08b16b 100644 (file)
@@ -1085,10 +1085,12 @@ static ssize_t rx_trigger_store(struct device *dev,
 {
        struct uart_port *port = dev_get_drvdata(dev);
        struct sci_port *sci = to_sci_port(port);
+       int ret;
        long r;
 
-       if (kstrtol(buf, 0, &r) == -EINVAL)
-               return -EINVAL;
+       ret = kstrtol(buf, 0, &r);
+       if (ret)
+               return ret;
 
        sci->rx_trigger = scif_set_rtrg(port, r);
        if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
@@ -1116,10 +1118,12 @@ static ssize_t rx_fifo_timeout_store(struct device *dev,
 {
        struct uart_port *port = dev_get_drvdata(dev);
        struct sci_port *sci = to_sci_port(port);
+       int ret;
        long r;
 
-       if (kstrtol(buf, 0, &r) == -EINVAL)
-               return -EINVAL;
+       ret = kstrtol(buf, 0, &r);
+       if (ret)
+               return ret;
        sci->rx_fifo_timeout = r;
        scif_set_rtrg(port, 1);
        if (r > 0)
index f5335be..6b0ca65 100644 (file)
@@ -758,6 +758,7 @@ static int asc_init_port(struct asc_port *ascport,
        if (IS_ERR(ascport->pinctrl)) {
                ret = PTR_ERR(ascport->pinctrl);
                dev_err(&pdev->dev, "Failed to get Pinctrl: %d\n", ret);
+               return ret;
        }
 
        ascport->states[DEFAULT] =
index 5357d83..5e05606 100644 (file)
@@ -1829,6 +1829,9 @@ static const struct usb_device_id acm_ids[] = {
        { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */
        .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
        },
+       { USB_DEVICE(0xfff0, 0x0100), /* DATECS FP-2000 */
+       .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
+       },
 
        { USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */
        .driver_info = CLEAR_HALT_CONDITIONS,
index bc3b3fd..c4066cd 100644 (file)
@@ -3573,6 +3573,9 @@ irq_retry:
                /* Report disconnection if it is not already done. */
                dwc2_hsotg_disconnect(hsotg);
 
+               /* Reset device address to zero */
+               __bic32(hsotg->regs + DCFG, DCFG_DEVADDR_MASK);
+
                if (usb_status & GOTGCTL_BSESVLD && connected)
                        dwc2_hsotg_core_init_disconnected(hsotg, true);
        }
index 326b302..03474d3 100644 (file)
@@ -766,15 +766,15 @@ static int dwc3_core_init(struct dwc3 *dwc)
                        dwc->maximum_speed = USB_SPEED_HIGH;
        }
 
-       ret = dwc3_core_soft_reset(dwc);
+       ret = dwc3_core_get_phy(dwc);
        if (ret)
                goto err0;
 
-       ret = dwc3_phy_setup(dwc);
+       ret = dwc3_core_soft_reset(dwc);
        if (ret)
                goto err0;
 
-       ret = dwc3_core_get_phy(dwc);
+       ret = dwc3_phy_setup(dwc);
        if (ret)
                goto err0;
 
index 9892650..f5aaa0c 100644 (file)
@@ -512,15 +512,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
 
        /* check the DMA Status */
        reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
-       irq_set_status_flags(omap->irq, IRQ_NOAUTOEN);
-       ret = devm_request_threaded_irq(dev, omap->irq, dwc3_omap_interrupt,
-                                       dwc3_omap_interrupt_thread, IRQF_SHARED,
-                                       "dwc3-omap", omap);
-       if (ret) {
-               dev_err(dev, "failed to request IRQ #%d --> %d\n",
-                               omap->irq, ret);
-               goto err1;
-       }
 
        ret = dwc3_omap_extcon_register(omap);
        if (ret < 0)
@@ -532,8 +523,15 @@ static int dwc3_omap_probe(struct platform_device *pdev)
                goto err1;
        }
 
+       ret = devm_request_threaded_irq(dev, omap->irq, dwc3_omap_interrupt,
+                                       dwc3_omap_interrupt_thread, IRQF_SHARED,
+                                       "dwc3-omap", omap);
+       if (ret) {
+               dev_err(dev, "failed to request IRQ #%d --> %d\n",
+                       omap->irq, ret);
+               goto err1;
+       }
        dwc3_omap_enable_irqs(omap);
-       enable_irq(omap->irq);
        return 0;
 
 err1:
index 9e41605..6b299c7 100644 (file)
@@ -191,14 +191,16 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
 
        req->started = false;
        list_del(&req->list);
-       req->trb = NULL;
        req->remaining = 0;
 
        if (req->request.status == -EINPROGRESS)
                req->request.status = status;
 
-       usb_gadget_unmap_request_by_dev(dwc->sysdev,
-                                       &req->request, req->direction);
+       if (req->trb)
+               usb_gadget_unmap_request_by_dev(dwc->sysdev,
+                                               &req->request, req->direction);
+
+       req->trb = NULL;
 
        trace_dwc3_gadget_giveback(req);
 
index e80b9c1..f95bddd 100644 (file)
@@ -2490,7 +2490,7 @@ static int fsg_main_thread(void *common_)
                int i;
 
                down_write(&common->filesem);
-               for (i = 0; i < ARRAY_SIZE(common->luns); --i) {
+               for (i = 0; i < ARRAY_SIZE(common->luns); i++) {
                        struct fsg_lun *curlun = common->luns[i];
                        if (!curlun || !fsg_lun_is_open(curlun))
                                continue;
index 8656f84..29efbed 100644 (file)
@@ -92,9 +92,9 @@ static struct uac_input_terminal_descriptor usb_out_it_desc = {
        .bDescriptorType =      USB_DT_CS_INTERFACE,
        .bDescriptorSubtype =   UAC_INPUT_TERMINAL,
        .bTerminalID =          USB_OUT_IT_ID,
-       .wTerminalType =        UAC_TERMINAL_STREAMING,
+       .wTerminalType =        cpu_to_le16(UAC_TERMINAL_STREAMING),
        .bAssocTerminal =       0,
-       .wChannelConfig =       0x3,
+       .wChannelConfig =       cpu_to_le16(0x3),
 };
 
 #define IO_OUT_OT_ID   2
@@ -103,7 +103,7 @@ static struct uac1_output_terminal_descriptor io_out_ot_desc = {
        .bDescriptorType        = USB_DT_CS_INTERFACE,
        .bDescriptorSubtype     = UAC_OUTPUT_TERMINAL,
        .bTerminalID            = IO_OUT_OT_ID,
-       .wTerminalType          = UAC_OUTPUT_TERMINAL_SPEAKER,
+       .wTerminalType          = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER),
        .bAssocTerminal         = 0,
        .bSourceID              = USB_OUT_IT_ID,
 };
@@ -114,9 +114,9 @@ static struct uac_input_terminal_descriptor io_in_it_desc = {
        .bDescriptorType        = USB_DT_CS_INTERFACE,
        .bDescriptorSubtype     = UAC_INPUT_TERMINAL,
        .bTerminalID            = IO_IN_IT_ID,
-       .wTerminalType          = UAC_INPUT_TERMINAL_MICROPHONE,
+       .wTerminalType          = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE),
        .bAssocTerminal         = 0,
-       .wChannelConfig         = 0x3,
+       .wChannelConfig         = cpu_to_le16(0x3),
 };
 
 #define USB_IN_OT_ID   4
@@ -125,7 +125,7 @@ static struct uac1_output_terminal_descriptor usb_in_ot_desc = {
        .bDescriptorType =      USB_DT_CS_INTERFACE,
        .bDescriptorSubtype =   UAC_OUTPUT_TERMINAL,
        .bTerminalID =          USB_IN_OT_ID,
-       .wTerminalType =        UAC_TERMINAL_STREAMING,
+       .wTerminalType =        cpu_to_le16(UAC_TERMINAL_STREAMING),
        .bAssocTerminal =       0,
        .bSourceID =            IO_IN_IT_ID,
 };
@@ -174,7 +174,7 @@ static struct uac1_as_header_descriptor as_out_header_desc = {
        .bDescriptorSubtype =   UAC_AS_GENERAL,
        .bTerminalLink =        USB_OUT_IT_ID,
        .bDelay =               1,
-       .wFormatTag =           UAC_FORMAT_TYPE_I_PCM,
+       .wFormatTag =           cpu_to_le16(UAC_FORMAT_TYPE_I_PCM),
 };
 
 static struct uac1_as_header_descriptor as_in_header_desc = {
@@ -183,7 +183,7 @@ static struct uac1_as_header_descriptor as_in_header_desc = {
        .bDescriptorSubtype =   UAC_AS_GENERAL,
        .bTerminalLink =        USB_IN_OT_ID,
        .bDelay =               1,
-       .wFormatTag =           UAC_FORMAT_TYPE_I_PCM,
+       .wFormatTag =           cpu_to_le16(UAC_FORMAT_TYPE_I_PCM),
 };
 
 DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
@@ -606,8 +606,8 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
        if (status)
                goto fail;
 
-       audio->out_ep_maxpsize = as_out_ep_desc.wMaxPacketSize;
-       audio->in_ep_maxpsize = as_in_ep_desc.wMaxPacketSize;
+       audio->out_ep_maxpsize = le16_to_cpu(as_out_ep_desc.wMaxPacketSize);
+       audio->in_ep_maxpsize = le16_to_cpu(as_in_ep_desc.wMaxPacketSize);
        audio->params.c_chmask = audio_opts->c_chmask;
        audio->params.c_srate = audio_opts->c_srate;
        audio->params.c_ssize = audio_opts->c_ssize;
index 9082ce2..f05c3f3 100644 (file)
@@ -168,7 +168,7 @@ static struct uac2_input_terminal_descriptor usb_out_it_desc = {
        .bAssocTerminal = 0,
        .bCSourceID = USB_OUT_CLK_ID,
        .iChannelNames = 0,
-       .bmControls = (CONTROL_RDWR << COPY_CTRL),
+       .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
 };
 
 /* Input Terminal for I/O-In */
@@ -182,7 +182,7 @@ static struct uac2_input_terminal_descriptor io_in_it_desc = {
        .bAssocTerminal = 0,
        .bCSourceID = USB_IN_CLK_ID,
        .iChannelNames = 0,
-       .bmControls = (CONTROL_RDWR << COPY_CTRL),
+       .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
 };
 
 /* Ouput Terminal for USB_IN */
@@ -196,7 +196,7 @@ static struct uac2_output_terminal_descriptor usb_in_ot_desc = {
        .bAssocTerminal = 0,
        .bSourceID = IO_IN_IT_ID,
        .bCSourceID = USB_IN_CLK_ID,
-       .bmControls = (CONTROL_RDWR << COPY_CTRL),
+       .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
 };
 
 /* Ouput Terminal for I/O-Out */
@@ -210,7 +210,7 @@ static struct uac2_output_terminal_descriptor io_out_ot_desc = {
        .bAssocTerminal = 0,
        .bSourceID = USB_OUT_IT_ID,
        .bCSourceID = USB_OUT_CLK_ID,
-       .bmControls = (CONTROL_RDWR << COPY_CTRL),
+       .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
 };
 
 static struct uac2_ac_header_descriptor ac_hdr_desc = {
@@ -220,9 +220,10 @@ static struct uac2_ac_header_descriptor ac_hdr_desc = {
        .bDescriptorSubtype = UAC_MS_HEADER,
        .bcdADC = cpu_to_le16(0x200),
        .bCategory = UAC2_FUNCTION_IO_BOX,
-       .wTotalLength = sizeof in_clk_src_desc + sizeof out_clk_src_desc
-                        + sizeof usb_out_it_desc + sizeof io_in_it_desc
-                       + sizeof usb_in_ot_desc + sizeof io_out_ot_desc,
+       .wTotalLength = cpu_to_le16(sizeof in_clk_src_desc
+                       + sizeof out_clk_src_desc + sizeof usb_out_it_desc
+                       + sizeof io_in_it_desc + sizeof usb_in_ot_desc
+                       + sizeof io_out_ot_desc),
        .bmControls = 0,
 };
 
@@ -569,10 +570,12 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
                return ret;
        }
 
-       agdev->in_ep_maxpsize = max(fs_epin_desc.wMaxPacketSize,
-                                       hs_epin_desc.wMaxPacketSize);
-       agdev->out_ep_maxpsize = max(fs_epout_desc.wMaxPacketSize,
-                                       hs_epout_desc.wMaxPacketSize);
+       agdev->in_ep_maxpsize = max_t(u16,
+                               le16_to_cpu(fs_epin_desc.wMaxPacketSize),
+                               le16_to_cpu(hs_epin_desc.wMaxPacketSize));
+       agdev->out_ep_maxpsize = max_t(u16,
+                               le16_to_cpu(fs_epout_desc.wMaxPacketSize),
+                               le16_to_cpu(hs_epout_desc.wMaxPacketSize));
 
        hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
        hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
index 9ffb11e..7cd5c96 100644 (file)
@@ -192,7 +192,7 @@ config USB_RENESAS_USBHS_UDC
 config USB_RENESAS_USB3
        tristate 'Renesas USB3.0 Peripheral controller'
        depends on ARCH_RENESAS || COMPILE_TEST
-       depends on EXTCON
+       depends on EXTCON && HAS_DMA
        help
           Renesas USB3.0 Peripheral controller is a USB peripheral controller
           that supports super, high, and full speed USB 3.0 data transfers.
@@ -257,6 +257,7 @@ config USB_MV_U3D
 
 config USB_SNP_CORE
        depends on (USB_AMD5536UDC || USB_SNP_UDC_PLAT)
+       depends on HAS_DMA
        tristate
        help
          This enables core driver support for Synopsys USB 2.0 Device
@@ -271,7 +272,7 @@ config USB_SNP_CORE
 
 config USB_SNP_UDC_PLAT
        tristate "Synopsys USB 2.0 Device controller"
-       depends on (USB_GADGET && OF)
+       depends on USB_GADGET && OF && HAS_DMA
        select USB_GADGET_DUALSPEED
        select USB_SNP_CORE
        default ARCH_BCM_IPROC
index d827832..62dc9c7 100644 (file)
@@ -89,6 +89,9 @@
 
 /* USB_COM_CON */
 #define USB_COM_CON_CONF               BIT(24)
+#define USB_COM_CON_PN_WDATAIF_NL      BIT(23)
+#define USB_COM_CON_PN_RDATAIF_NL      BIT(22)
+#define USB_COM_CON_PN_LSTTR_PP                BIT(21)
 #define USB_COM_CON_SPD_MODE           BIT(17)
 #define USB_COM_CON_EP0_EN             BIT(16)
 #define USB_COM_CON_DEV_ADDR_SHIFT     8
@@ -686,6 +689,9 @@ static void renesas_usb3_init_controller(struct renesas_usb3 *usb3)
 {
        usb3_init_axi_bridge(usb3);
        usb3_init_epc_registers(usb3);
+       usb3_set_bit(usb3, USB_COM_CON_PN_WDATAIF_NL |
+                    USB_COM_CON_PN_RDATAIF_NL | USB_COM_CON_PN_LSTTR_PP,
+                    USB3_USB_COM_CON);
        usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_STA);
        usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_ENA);
 
@@ -1369,7 +1375,7 @@ static int renesas_usb3_dma_free_prd(struct renesas_usb3 *usb3,
 
        usb3_for_each_dma(usb3, dma, i) {
                if (dma->prd) {
-                       dma_free_coherent(dev, USB3_DMA_MAX_XFER_SIZE,
+                       dma_free_coherent(dev, USB3_DMA_PRD_SIZE,
                                          dma->prd, dma->prd_dma);
                        dma->prd = NULL;
                }
@@ -1409,12 +1415,12 @@ static void usb3_start_pipen(struct renesas_usb3_ep *usb3_ep,
        int ret = -EAGAIN;
        u32 enable_bits = 0;
 
+       spin_lock_irqsave(&usb3->lock, flags);
        if (usb3_ep->halt || usb3_ep->started)
-               return;
+               goto out;
        if (usb3_req != usb3_req_first)
-               return;
+               goto out;
 
-       spin_lock_irqsave(&usb3->lock, flags);
        if (usb3_pn_change(usb3, usb3_ep->num) < 0)
                goto out;
 
index 2e11f19..f7b4d0f 100644 (file)
@@ -28,7 +28,7 @@
 /* description */
 #define UDC_MOD_DESCRIPTION     "Synopsys UDC platform driver"
 
-void start_udc(struct udc *udc)
+static void start_udc(struct udc *udc)
 {
        if (udc->driver) {
                dev_info(udc->dev, "Connecting...\n");
@@ -38,7 +38,7 @@ void start_udc(struct udc *udc)
        }
 }
 
-void stop_udc(struct udc *udc)
+static void stop_udc(struct udc *udc)
 {
        int tmp;
        u32 reg;
@@ -76,7 +76,7 @@ void stop_udc(struct udc *udc)
        dev_info(udc->dev, "Device disconnected\n");
 }
 
-void udc_drd_work(struct work_struct *work)
+static void udc_drd_work(struct work_struct *work)
 {
        struct udc *udc;
 
index a9a1e4c..c8989c6 100644 (file)
 #define USB_INTEL_USB3_PSSEN   0xD8
 #define USB_INTEL_USB3PRM      0xDC
 
+/* ASMEDIA quirk use */
+#define ASMT_DATA_WRITE0_REG   0xF8
+#define ASMT_DATA_WRITE1_REG   0xFC
+#define ASMT_CONTROL_REG       0xE0
+#define ASMT_CONTROL_WRITE_BIT 0x02
+#define ASMT_WRITEREG_CMD      0x10423
+#define ASMT_FLOWCTL_ADDR      0xFA30
+#define ASMT_FLOWCTL_DATA      0xBA
+#define ASMT_PSEUDO_DATA       0
+
 /*
  * amd_chipset_gen values represent AMD different chipset generations
  */
@@ -412,6 +422,50 @@ void usb_amd_quirk_pll_disable(void)
 }
 EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_disable);
 
+static int usb_asmedia_wait_write(struct pci_dev *pdev)
+{
+       unsigned long retry_count;
+       unsigned char value;
+
+       for (retry_count = 1000; retry_count > 0; --retry_count) {
+
+               pci_read_config_byte(pdev, ASMT_CONTROL_REG, &value);
+
+               if (value == 0xff) {
+                       dev_err(&pdev->dev, "%s: check_ready ERROR", __func__);
+                       return -EIO;
+               }
+
+               if ((value & ASMT_CONTROL_WRITE_BIT) == 0)
+                       return 0;
+
+               usleep_range(40, 60);
+       }
+
+       dev_warn(&pdev->dev, "%s: check_write_ready timeout", __func__);
+       return -ETIMEDOUT;
+}
+
+void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev)
+{
+       if (usb_asmedia_wait_write(pdev) != 0)
+               return;
+
+       /* send command and address to device */
+       pci_write_config_dword(pdev, ASMT_DATA_WRITE0_REG, ASMT_WRITEREG_CMD);
+       pci_write_config_dword(pdev, ASMT_DATA_WRITE1_REG, ASMT_FLOWCTL_ADDR);
+       pci_write_config_byte(pdev, ASMT_CONTROL_REG, ASMT_CONTROL_WRITE_BIT);
+
+       if (usb_asmedia_wait_write(pdev) != 0)
+               return;
+
+       /* send data to device */
+       pci_write_config_dword(pdev, ASMT_DATA_WRITE0_REG, ASMT_FLOWCTL_DATA);
+       pci_write_config_dword(pdev, ASMT_DATA_WRITE1_REG, ASMT_PSEUDO_DATA);
+       pci_write_config_byte(pdev, ASMT_CONTROL_REG, ASMT_CONTROL_WRITE_BIT);
+}
+EXPORT_SYMBOL_GPL(usb_asmedia_modifyflowcontrol);
+
 void usb_amd_quirk_pll_enable(void)
 {
        usb_amd_quirk_pll(0);
index 0222195..6559944 100644 (file)
@@ -11,6 +11,7 @@ bool usb_amd_prefetch_quirk(void);
 void usb_amd_dev_put(void);
 void usb_amd_quirk_pll_disable(void);
 void usb_amd_quirk_pll_enable(void);
+void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev);
 void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
 void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
 void sb800_prefetch(struct device *dev, int on);
@@ -18,6 +19,7 @@ void sb800_prefetch(struct device *dev, int on);
 struct pci_dev;
 static inline void usb_amd_quirk_pll_disable(void) {}
 static inline void usb_amd_quirk_pll_enable(void) {}
+static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {}
 static inline void usb_amd_dev_put(void) {}
 static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
 static inline void sb800_prefetch(struct device *dev, int on) {}
index 1adae9e..00721e8 100644 (file)
@@ -398,14 +398,21 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
        spin_lock_irqsave(&xhci->lock, flags);
        for (i = LAST_EP_INDEX; i > 0; i--) {
                if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) {
+                       struct xhci_ep_ctx *ep_ctx;
                        struct xhci_command *command;
+
+                       ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->out_ctx, i);
+
+                       /* Check ep is running, required by AMD SNPS 3.1 xHC */
+                       if (GET_EP_CTX_STATE(ep_ctx) != EP_STATE_RUNNING)
+                               continue;
+
                        command = xhci_alloc_command(xhci, false, false,
                                                     GFP_NOWAIT);
                        if (!command) {
                                spin_unlock_irqrestore(&xhci->lock, flags);
                                xhci_free_command(xhci, cmd);
                                return -ENOMEM;
-
                        }
                        xhci_queue_stop_endpoint(xhci, command, slot_id, i,
                                                 suspend);
@@ -603,12 +610,14 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
 
        /* Disable all Device Slots */
        xhci_dbg(xhci, "Disable all slots\n");
+       spin_unlock_irqrestore(&xhci->lock, *flags);
        for (i = 1; i <= HCS_MAX_SLOTS(xhci->hcs_params1); i++) {
                retval = xhci_disable_slot(xhci, NULL, i);
                if (retval)
                        xhci_err(xhci, "Failed to disable slot %d, %d. Enter test mode anyway\n",
                                 i, retval);
        }
+       spin_lock_irqsave(&xhci->lock, *flags);
        /* Put all ports to the Disable state by clear PP */
        xhci_dbg(xhci, "Disable all port (PP = 0)\n");
        /* Power off USB3 ports*/
@@ -897,6 +906,9 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
                        clear_bit(wIndex, &bus_state->resuming_ports);
 
                        set_bit(wIndex, &bus_state->rexit_ports);
+
+                       xhci_test_and_clear_bit(xhci, port_array, wIndex,
+                                               PORT_PLC);
                        xhci_set_link_state(xhci, port_array, wIndex,
                                        XDEV_U0);
 
index 53882e2..5b0fa55 100644 (file)
@@ -59,6 +59,8 @@
 #define PCI_DEVICE_ID_AMD_PROMONTORYA_2                        0x43bb
 #define PCI_DEVICE_ID_AMD_PROMONTORYA_1                        0x43bc
 
+#define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI               0x1142
+
 static const char hcd_name[] = "xhci_hcd";
 
 static struct hc_driver __read_mostly xhci_pci_hc_driver;
@@ -217,6 +219,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                        pdev->device == 0x1142)
                xhci->quirks |= XHCI_TRUST_TX_LENGTH;
 
+       if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+               pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI)
+               xhci->quirks |= XHCI_ASMEDIA_MODIFY_FLOWCONTROL;
+
        if (pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241)
                xhci->quirks |= XHCI_LIMIT_ENDPOINT_INTERVAL_7;
 
index c50c902..cc368ad 100644 (file)
@@ -864,13 +864,16 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci,
                        (ep->ep_state & EP_GETTING_NO_STREAMS)) {
                int stream_id;
 
-               for (stream_id = 0; stream_id < ep->stream_info->num_streams;
+               for (stream_id = 1; stream_id < ep->stream_info->num_streams;
                                stream_id++) {
+                       ring = ep->stream_info->stream_rings[stream_id];
+                       if (!ring)
+                               continue;
+
                        xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
                                        "Killing URBs for slot ID %u, ep index %u, stream %u",
-                                       slot_id, ep_index, stream_id + 1);
-                       xhci_kill_ring_urbs(xhci,
-                                       ep->stream_info->stream_rings[stream_id]);
+                                       slot_id, ep_index, stream_id);
+                       xhci_kill_ring_urbs(xhci, ring);
                }
        } else {
                ring = ep->ring;
index 56f85df..b2ff1ff 100644 (file)
@@ -198,6 +198,9 @@ int xhci_reset(struct xhci_hcd *xhci)
        if (ret)
                return ret;
 
+       if (xhci->quirks & XHCI_ASMEDIA_MODIFY_FLOWCONTROL)
+               usb_asmedia_modifyflowcontrol(to_pci_dev(xhci_to_hcd(xhci)->self.controller));
+
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                         "Wait for controller to be ready for doorbell rings");
        /*
@@ -622,8 +625,10 @@ int xhci_run(struct usb_hcd *hcd)
                if (!command)
                        return -ENOMEM;
 
-               xhci_queue_vendor_command(xhci, command, 0, 0, 0,
+               ret = xhci_queue_vendor_command(xhci, command, 0, 0, 0,
                                TRB_TYPE(TRB_NEC_GET_FW));
+               if (ret)
+                       xhci_free_command(xhci, command);
        }
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "Finished xhci_run for USB2 roothub");
@@ -1085,6 +1090,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
        if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !comp_timer_running)
                compliance_mode_recovery_timer_init(xhci);
 
+       if (xhci->quirks & XHCI_ASMEDIA_MODIFY_FLOWCONTROL)
+               usb_asmedia_modifyflowcontrol(to_pci_dev(hcd->self.controller));
+
        /* Re-enable port polling. */
        xhci_dbg(xhci, "%s: starting port polling.\n", __func__);
        set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
index 3c6da1f..e3e9352 100644 (file)
@@ -1820,6 +1820,7 @@ struct xhci_hcd {
 #define XHCI_BROKEN_PORT_PED   (1 << 25)
 #define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
 #define XHCI_U2_DISABLE_WAKE   (1 << 27)
+#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL        (1 << 28)
 
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
index 623c513..f0ce304 100644 (file)
@@ -752,8 +752,10 @@ static int usbhsc_resume(struct device *dev)
        struct usbhs_priv *priv = dev_get_drvdata(dev);
        struct platform_device *pdev = usbhs_priv_to_pdev(priv);
 
-       if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+       if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
                usbhsc_power_ctrl(priv, 1);
+               usbhs_mod_autonomy_mode(priv);
+       }
 
        usbhs_platform_call(priv, phy_reset, pdev);
 
index 5bc7a61..93fba90 100644 (file)
@@ -37,6 +37,7 @@ struct usbhsg_gpriv;
 struct usbhsg_uep {
        struct usb_ep            ep;
        struct usbhs_pipe       *pipe;
+       spinlock_t              lock;   /* protect the pipe */
 
        char ep_name[EP_NAME_SIZE];
 
@@ -636,10 +637,16 @@ usbhsg_ep_enable_end:
 static int usbhsg_ep_disable(struct usb_ep *ep)
 {
        struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep);
-       struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
+       struct usbhs_pipe *pipe;
+       unsigned long flags;
+       int ret = 0;
 
-       if (!pipe)
-               return -EINVAL;
+       spin_lock_irqsave(&uep->lock, flags);
+       pipe = usbhsg_uep_to_pipe(uep);
+       if (!pipe) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        usbhsg_pipe_disable(uep);
        usbhs_pipe_free(pipe);
@@ -647,6 +654,9 @@ static int usbhsg_ep_disable(struct usb_ep *ep)
        uep->pipe->mod_private  = NULL;
        uep->pipe               = NULL;
 
+out:
+       spin_unlock_irqrestore(&uep->lock, flags);
+
        return 0;
 }
 
@@ -696,8 +706,11 @@ static int usbhsg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
 {
        struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep);
        struct usbhsg_request *ureq = usbhsg_req_to_ureq(req);
-       struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
+       struct usbhs_pipe *pipe;
+       unsigned long flags;
 
+       spin_lock_irqsave(&uep->lock, flags);
+       pipe = usbhsg_uep_to_pipe(uep);
        if (pipe)
                usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq));
 
@@ -706,6 +719,7 @@ static int usbhsg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
         * even if the pipe is NULL.
         */
        usbhsg_queue_pop(uep, ureq, -ECONNRESET);
+       spin_unlock_irqrestore(&uep->lock, flags);
 
        return 0;
 }
@@ -852,10 +866,10 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
 {
        struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
        struct usbhs_mod *mod = usbhs_mod_get_current(priv);
-       struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv);
+       struct usbhsg_uep *uep;
        struct device *dev = usbhs_priv_to_dev(priv);
        unsigned long flags;
-       int ret = 0;
+       int ret = 0, i;
 
        /********************  spin lock ********************/
        usbhs_lock(priv, flags);
@@ -887,7 +901,9 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
        usbhs_sys_set_test_mode(priv, 0);
        usbhs_sys_function_ctrl(priv, 0);
 
-       usbhsg_ep_disable(&dcp->ep);
+       /* disable all eps */
+       usbhsg_for_each_uep_with_dcp(uep, gpriv, i)
+               usbhsg_ep_disable(&uep->ep);
 
        dev_dbg(dev, "stop gadget\n");
 
@@ -1069,6 +1085,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
                ret = -ENOMEM;
                goto usbhs_mod_gadget_probe_err_gpriv;
        }
+       spin_lock_init(&uep->lock);
 
        gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED);
        dev_info(dev, "%stransceiver found\n",
index 8a069aa..27d7a70 100644 (file)
@@ -180,7 +180,7 @@ static const __u16 crc10_table[256] = {
  * Perform a memcpy and calculate fcs using ppp 10bit CRC algorithm. Return
  * new 10 bit FCS.
  */
-static __u16 __inline__ fcs_compute10(unsigned char *sp, int len, __u16 fcs)
+static inline __u16 fcs_compute10(unsigned char *sp, int len, __u16 fcs)
 {
        for (; len-- > 0; fcs = CRC10_FCS(fcs, *sp++));
        return fcs;
index fba4005..6a7720e 100644 (file)
@@ -1529,8 +1529,11 @@ static void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
 
        /* Make sure driver was initialized */
 
-       if (us->extra == NULL)
+       if (us->extra == NULL) {
                usb_stor_dbg(us, "ERROR Driver not initialized\n");
+               srb->result = DID_ERROR << 16;
+               return;
+       }
 
        scsi_set_resid(srb, 0);
        /* scsi_bufflen might change in protocol translation to ata */
index 6b0d2f0..8a88f45 100644 (file)
@@ -3,6 +3,7 @@
 #define __DRIVER_USB_TYPEC_UCSI_H
 
 #include <linux/bitops.h>
+#include <linux/device.h>
 #include <linux/types.h>
 
 /* -------------------------------------------------------------------------- */
index 324c52e..063c1ce 100644 (file)
@@ -195,11 +195,11 @@ static bool vfio_pci_nointx(struct pci_dev *pdev)
        switch (pdev->vendor) {
        case PCI_VENDOR_ID_INTEL:
                switch (pdev->device) {
-               /* All i40e (XL710/X710) 10/20/40GbE NICs */
+               /* All i40e (XL710/X710/XXV710) 10/20/25/40GbE NICs */
                case 0x1572:
                case 0x1574:
                case 0x1580 ... 0x1581:
-               case 0x1583 ... 0x1589:
+               case 0x1583 ... 0x158b:
                case 0x37d0 ... 0x37d2:
                        return true;
                default:
index 561084a..330d505 100644 (file)
@@ -382,7 +382,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
        if (IS_ERR(dev)) {
                vfio_free_group_minor(minor);
                vfio_group_unlock_and_free(group);
-               return (struct vfio_group *)dev; /* ERR_PTR */
+               return ERR_CAST(dev);
        }
 
        group->minor = minor;
@@ -423,6 +423,34 @@ static void vfio_group_put(struct vfio_group *group)
        kref_put_mutex(&group->kref, vfio_group_release, &vfio.group_lock);
 }
 
+struct vfio_group_put_work {
+       struct work_struct work;
+       struct vfio_group *group;
+};
+
+static void vfio_group_put_bg(struct work_struct *work)
+{
+       struct vfio_group_put_work *do_work;
+
+       do_work = container_of(work, struct vfio_group_put_work, work);
+
+       vfio_group_put(do_work->group);
+       kfree(do_work);
+}
+
+static void vfio_group_schedule_put(struct vfio_group *group)
+{
+       struct vfio_group_put_work *do_work;
+
+       do_work = kmalloc(sizeof(*do_work), GFP_KERNEL);
+       if (WARN_ON(!do_work))
+               return;
+
+       INIT_WORK(&do_work->work, vfio_group_put_bg);
+       do_work->group = group;
+       schedule_work(&do_work->work);
+}
+
 /* Assume group_lock or group reference is held */
 static void vfio_group_get(struct vfio_group *group)
 {
@@ -762,7 +790,14 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
                break;
        }
 
-       vfio_group_put(group);
+       /*
+        * If we're the last reference to the group, the group will be
+        * released, which includes unregistering the iommu group notifier.
+        * We hold a read-lock on that notifier list, unregistering needs
+        * a write-lock... deadlock.  Release our reference asynchronously
+        * to avoid that situation.
+        */
+       vfio_group_schedule_put(group);
        return NOTIFY_OK;
 }
 
@@ -1140,15 +1175,11 @@ static long vfio_fops_unl_ioctl(struct file *filep,
                ret = vfio_ioctl_set_iommu(container, arg);
                break;
        default:
-               down_read(&container->group_lock);
-
                driver = container->iommu_driver;
                data = container->iommu_data;
 
                if (driver) /* passthrough all unrecognized ioctls */
                        ret = driver->ops->ioctl(data, cmd, arg);
-
-               up_read(&container->group_lock);
        }
 
        return ret;
@@ -1202,15 +1233,11 @@ static ssize_t vfio_fops_read(struct file *filep, char __user *buf,
        struct vfio_iommu_driver *driver;
        ssize_t ret = -EINVAL;
 
-       down_read(&container->group_lock);
-
        driver = container->iommu_driver;
        if (likely(driver && driver->ops->read))
                ret = driver->ops->read(container->iommu_data,
                                        buf, count, ppos);
 
-       up_read(&container->group_lock);
-
        return ret;
 }
 
@@ -1221,15 +1248,11 @@ static ssize_t vfio_fops_write(struct file *filep, const char __user *buf,
        struct vfio_iommu_driver *driver;
        ssize_t ret = -EINVAL;
 
-       down_read(&container->group_lock);
-
        driver = container->iommu_driver;
        if (likely(driver && driver->ops->write))
                ret = driver->ops->write(container->iommu_data,
                                         buf, count, ppos);
 
-       up_read(&container->group_lock);
-
        return ret;
 }
 
@@ -1239,14 +1262,10 @@ static int vfio_fops_mmap(struct file *filep, struct vm_area_struct *vma)
        struct vfio_iommu_driver *driver;
        int ret = -EINVAL;
 
-       down_read(&container->group_lock);
-
        driver = container->iommu_driver;
        if (likely(driver && driver->ops->mmap))
                ret = driver->ops->mmap(container->iommu_data, vma);
 
-       up_read(&container->group_lock);
-
        return ret;
 }
 
@@ -1741,6 +1760,15 @@ void vfio_group_put_external_user(struct vfio_group *group)
 }
 EXPORT_SYMBOL_GPL(vfio_group_put_external_user);
 
+bool vfio_external_group_match_file(struct vfio_group *test_group,
+                                   struct file *filep)
+{
+       struct vfio_group *group = filep->private_data;
+
+       return (filep->f_op == &vfio_group_fops) && (group == test_group);
+}
+EXPORT_SYMBOL_GPL(vfio_external_group_match_file);
+
 int vfio_external_user_iommu_id(struct vfio_group *group)
 {
        return iommu_group_id(group->iommu_group);
@@ -1949,8 +1977,6 @@ int vfio_pin_pages(struct device *dev, unsigned long *user_pfn, int npage,
                goto err_pin_pages;
 
        container = group->container;
-       down_read(&container->group_lock);
-
        driver = container->iommu_driver;
        if (likely(driver && driver->ops->pin_pages))
                ret = driver->ops->pin_pages(container->iommu_data, user_pfn,
@@ -1958,7 +1984,6 @@ int vfio_pin_pages(struct device *dev, unsigned long *user_pfn, int npage,
        else
                ret = -ENOTTY;
 
-       up_read(&container->group_lock);
        vfio_group_try_dissolve_container(group);
 
 err_pin_pages:
@@ -1998,8 +2023,6 @@ int vfio_unpin_pages(struct device *dev, unsigned long *user_pfn, int npage)
                goto err_unpin_pages;
 
        container = group->container;
-       down_read(&container->group_lock);
-
        driver = container->iommu_driver;
        if (likely(driver && driver->ops->unpin_pages))
                ret = driver->ops->unpin_pages(container->iommu_data, user_pfn,
@@ -2007,7 +2030,6 @@ int vfio_unpin_pages(struct device *dev, unsigned long *user_pfn, int npage)
        else
                ret = -ENOTTY;
 
-       up_read(&container->group_lock);
        vfio_group_try_dissolve_container(group);
 
 err_unpin_pages:
@@ -2029,8 +2051,6 @@ static int vfio_register_iommu_notifier(struct vfio_group *group,
                return -EINVAL;
 
        container = group->container;
-       down_read(&container->group_lock);
-
        driver = container->iommu_driver;
        if (likely(driver && driver->ops->register_notifier))
                ret = driver->ops->register_notifier(container->iommu_data,
@@ -2038,7 +2058,6 @@ static int vfio_register_iommu_notifier(struct vfio_group *group,
        else
                ret = -ENOTTY;
 
-       up_read(&container->group_lock);
        vfio_group_try_dissolve_container(group);
 
        return ret;
@@ -2056,8 +2075,6 @@ static int vfio_unregister_iommu_notifier(struct vfio_group *group,
                return -EINVAL;
 
        container = group->container;
-       down_read(&container->group_lock);
-
        driver = container->iommu_driver;
        if (likely(driver && driver->ops->unregister_notifier))
                ret = driver->ops->unregister_notifier(container->iommu_data,
@@ -2065,7 +2082,6 @@ static int vfio_unregister_iommu_notifier(struct vfio_group *group,
        else
                ret = -ENOTTY;
 
-       up_read(&container->group_lock);
        vfio_group_try_dissolve_container(group);
 
        return ret;
@@ -2083,7 +2099,6 @@ static int vfio_register_group_notifier(struct vfio_group *group,
                                        unsigned long *events,
                                        struct notifier_block *nb)
 {
-       struct vfio_container *container;
        int ret;
        bool set_kvm = false;
 
@@ -2101,9 +2116,6 @@ static int vfio_register_group_notifier(struct vfio_group *group,
        if (ret)
                return -EINVAL;
 
-       container = group->container;
-       down_read(&container->group_lock);
-
        ret = blocking_notifier_chain_register(&group->notifier, nb);
 
        /*
@@ -2114,7 +2126,6 @@ static int vfio_register_group_notifier(struct vfio_group *group,
                blocking_notifier_call_chain(&group->notifier,
                                        VFIO_GROUP_NOTIFY_SET_KVM, group->kvm);
 
-       up_read(&container->group_lock);
        vfio_group_try_dissolve_container(group);
 
        return ret;
@@ -2123,19 +2134,14 @@ static int vfio_register_group_notifier(struct vfio_group *group,
 static int vfio_unregister_group_notifier(struct vfio_group *group,
                                         struct notifier_block *nb)
 {
-       struct vfio_container *container;
        int ret;
 
        ret = vfio_group_add_container_user(group);
        if (ret)
                return -EINVAL;
 
-       container = group->container;
-       down_read(&container->group_lock);
-
        ret = blocking_notifier_chain_unregister(&group->notifier, nb);
 
-       up_read(&container->group_lock);
        vfio_group_try_dissolve_container(group);
 
        return ret;
index e3d7ea1..06d0448 100644 (file)
@@ -897,7 +897,7 @@ static int vhost_net_open(struct inode *inode, struct file *f)
        struct sk_buff **queue;
        int i;
 
-       n = kvmalloc(sizeof *n, GFP_KERNEL | __GFP_REPEAT);
+       n = kvmalloc(sizeof *n, GFP_KERNEL | __GFP_RETRY_MAYFAIL);
        if (!n)
                return -ENOMEM;
        vqs = kmalloc(VHOST_NET_VQ_MAX * sizeof(*vqs), GFP_KERNEL);
index fd6c8b6..046f6d2 100644 (file)
@@ -496,14 +496,12 @@ static void vhost_scsi_evt_work(struct vhost_work *work)
        struct vhost_scsi *vs = container_of(work, struct vhost_scsi,
                                        vs_event_work);
        struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
-       struct vhost_scsi_evt *evt;
+       struct vhost_scsi_evt *evt, *t;
        struct llist_node *llnode;
 
        mutex_lock(&vq->mutex);
        llnode = llist_del_all(&vs->vs_event_list);
-       while (llnode) {
-               evt = llist_entry(llnode, struct vhost_scsi_evt, list);
-               llnode = llist_next(llnode);
+       llist_for_each_entry_safe(evt, t, llnode, list) {
                vhost_scsi_do_evt_work(vs, evt);
                vhost_scsi_free_evt(vs, evt);
        }
@@ -529,10 +527,7 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
 
        bitmap_zero(signal, VHOST_SCSI_MAX_VQ);
        llnode = llist_del_all(&vs->vs_completion_list);
-       while (llnode) {
-               cmd = llist_entry(llnode, struct vhost_scsi_cmd,
-                                    tvc_completion_list);
-               llnode = llist_next(llnode);
+       llist_for_each_entry(cmd, llnode, tvc_completion_list) {
                se_cmd = &cmd->tvc_se_cmd;
 
                pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__,
@@ -1404,7 +1399,7 @@ static int vhost_scsi_open(struct inode *inode, struct file *f)
        struct vhost_virtqueue **vqs;
        int r = -ENOMEM, i;
 
-       vs = kzalloc(sizeof(*vs), GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
+       vs = kzalloc(sizeof(*vs), GFP_KERNEL | __GFP_NOWARN | __GFP_RETRY_MAYFAIL);
        if (!vs) {
                vs = vzalloc(sizeof(*vs));
                if (!vs)
index e4613a3..9cb3f72 100644 (file)
@@ -308,7 +308,6 @@ static void vhost_vq_reset(struct vhost_dev *dev,
        vq->avail = NULL;
        vq->used = NULL;
        vq->last_avail_idx = 0;
-       vq->last_used_event = 0;
        vq->avail_idx = 0;
        vq->last_used_idx = 0;
        vq->signalled_used = 0;
@@ -1402,7 +1401,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
                        r = -EINVAL;
                        break;
                }
-               vq->last_avail_idx = vq->last_used_event = s.num;
+               vq->last_avail_idx = s.num;
                /* Forget the cached index value. */
                vq->avail_idx = vq->last_avail_idx;
                break;
@@ -2241,6 +2240,10 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
        __u16 old, new;
        __virtio16 event;
        bool v;
+       /* Flush out used index updates. This is paired
+        * with the barrier that the Guest executes when enabling
+        * interrupts. */
+       smp_mb();
 
        if (vhost_has_feature(vq, VIRTIO_F_NOTIFY_ON_EMPTY) &&
            unlikely(vq->avail_idx == vq->last_avail_idx))
@@ -2248,10 +2251,6 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 
        if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) {
                __virtio16 flags;
-               /* Flush out used index updates. This is paired
-                * with the barrier that the Guest executes when enabling
-                * interrupts. */
-               smp_mb();
                if (vhost_get_avail(vq, flags, &vq->avail->flags)) {
                        vq_err(vq, "Failed to get flags");
                        return true;
@@ -2266,26 +2265,11 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
        if (unlikely(!v))
                return true;
 
-       /* We're sure if the following conditions are met, there's no
-        * need to notify guest:
-        * 1) cached used event is ahead of new
-        * 2) old to new updating does not cross cached used event. */
-       if (vring_need_event(vq->last_used_event, new + vq->num, new) &&
-           !vring_need_event(vq->last_used_event, new, old))
-               return false;
-
-       /* Flush out used index updates. This is paired
-        * with the barrier that the Guest executes when enabling
-        * interrupts. */
-       smp_mb();
-
        if (vhost_get_avail(vq, event, vhost_used_event(vq))) {
                vq_err(vq, "Failed to get used event idx");
                return true;
        }
-       vq->last_used_event = vhost16_to_cpu(vq, event);
-
-       return vring_need_event(vq->last_used_event, new, old);
+       return vring_need_event(vhost16_to_cpu(vq, event), new, old);
 }
 
 /* This actually signals the guest, using eventfd. */
index f720958..bb7c29b 100644 (file)
@@ -115,9 +115,6 @@ struct vhost_virtqueue {
        /* Last index we used. */
        u16 last_used_idx;
 
-       /* Last used evet we've seen */
-       u16 last_used_event;
-
        /* Used flags */
        u16 used_flags;
 
index 3f63e03..c9de9c4 100644 (file)
@@ -508,7 +508,7 @@ static int vhost_vsock_dev_open(struct inode *inode, struct file *file)
        /* This struct is large and allocation could fail, fall back to vmalloc
         * if there is no other way.
         */
-       vsock = kvmalloc(sizeof(*vsock), GFP_KERNEL | __GFP_REPEAT);
+       vsock = kvmalloc(sizeof(*vsock), GFP_KERNEL | __GFP_RETRY_MAYFAIL);
        if (!vsock)
                return -ENOMEM;
 
index ec192a1..d0d427a 100644 (file)
@@ -48,7 +48,7 @@ static DEFINE_SPINLOCK(mda_lock);
 
 /* description of the hardware layout */
 
-static unsigned long   mda_vram_base;          /* Base of video memory */
+static u16             *mda_vram_base;         /* Base of video memory */
 static unsigned long   mda_vram_len;           /* Size of video memory */
 static unsigned int    mda_num_columns;        /* Number of text columns */
 static unsigned int    mda_num_lines;          /* Number of text lines */
@@ -205,13 +205,20 @@ static int mda_detect(void)
 
        /* do a memory check */
 
-       p = (u16 *) mda_vram_base;
-       q = (u16 *) (mda_vram_base + 0x01000);
+       p = mda_vram_base;
+       q = mda_vram_base + 0x01000 / 2;
 
-       p_save = scr_readw(p); q_save = scr_readw(q);
+       p_save = scr_readw(p);
+       q_save = scr_readw(q);
+
+       scr_writew(0xAA55, p);
+       if (scr_readw(p) == 0xAA55)
+               count++;
+
+       scr_writew(0x55AA, p);
+       if (scr_readw(p) == 0x55AA)
+               count++;
 
-       scr_writew(0xAA55, p); if (scr_readw(p) == 0xAA55) count++;
-       scr_writew(0x55AA, p); if (scr_readw(p) == 0x55AA) count++;
        scr_writew(p_save, p);
 
        if (count != 2) {
@@ -220,13 +227,18 @@ static int mda_detect(void)
 
        /* check if we have 4K or 8K */
 
-       scr_writew(0xA55A, q); scr_writew(0x0000, p);
-       if (scr_readw(q) == 0xA55A) count++;
+       scr_writew(0xA55A, q);
+       scr_writew(0x0000, p);
+       if (scr_readw(q) == 0xA55A)
+               count++;
        
-       scr_writew(0x5AA5, q); scr_writew(0x0000, p);
-       if (scr_readw(q) == 0x5AA5) count++;
+       scr_writew(0x5AA5, q);
+       scr_writew(0x0000, p);
+       if (scr_readw(q) == 0x5AA5)
+               count++;
 
-       scr_writew(p_save, p); scr_writew(q_save, q);
+       scr_writew(p_save, p);
+       scr_writew(q_save, q);
        
        if (count == 4) {
                mda_vram_len = 0x02000;
@@ -240,14 +252,12 @@ static int mda_detect(void)
        /* Edward: These two mess `tests' mess up my cursor on bootup */
 
        /* cursor low register */
-       if (! test_mda_b(0x66, 0x0f)) {
+       if (!test_mda_b(0x66, 0x0f))
                return 0;
-       }
 
        /* cursor low register */
-       if (! test_mda_b(0x99, 0x0f)) {
+       if (!test_mda_b(0x99, 0x0f))
                return 0;
-       }
 #endif
 
        /* See if the card is a Hercules, by checking whether the vsync
@@ -257,25 +267,25 @@ static int mda_detect(void)
        
        p_save = q_save = inb_p(mda_status_port) & MDA_STATUS_VSYNC;
 
-       for (count=0; count < 50000 && p_save == q_save; count++) {
+       for (count = 0; count < 50000 && p_save == q_save; count++) {
                q_save = inb(mda_status_port) & MDA_STATUS_VSYNC;
                udelay(2);
        }
 
        if (p_save != q_save) {
                switch (inb_p(mda_status_port) & 0x70) {
-                       case 0x10:
-                               mda_type = TYPE_HERCPLUS;
-                               mda_type_name = "HerculesPlus";
-                               break;
-                       case 0x50:
-                               mda_type = TYPE_HERCCOLOR;
-                               mda_type_name = "HerculesColor";
-                               break;
-                       default:
-                               mda_type = TYPE_HERC;
-                               mda_type_name = "Hercules";
-                               break;
+               case 0x10:
+                       mda_type = TYPE_HERCPLUS;
+                       mda_type_name = "HerculesPlus";
+                       break;
+               case 0x50:
+                       mda_type = TYPE_HERCCOLOR;
+                       mda_type_name = "HerculesColor";
+                       break;
+               default:
+                       mda_type = TYPE_HERC;
+                       mda_type_name = "Hercules";
+                       break;
                }
        }
 
@@ -313,7 +323,7 @@ static const char *mdacon_startup(void)
        mda_num_lines   = 25;
 
        mda_vram_len  = 0x01000;
-       mda_vram_base = VGA_MAP_MEM(0xb0000, mda_vram_len);
+       mda_vram_base = (u16 *)VGA_MAP_MEM(0xb0000, mda_vram_len);
 
        mda_index_port  = 0x3b4;
        mda_value_port  = 0x3b5;
@@ -410,17 +420,20 @@ static void mdacon_invert_region(struct vc_data *c, u16 *p, int count)
        }
 }
 
-#define MDA_ADDR(x,y)  ((u16 *) mda_vram_base + (y)*mda_num_columns + (x))
+static inline u16 *mda_addr(unsigned int x, unsigned int y)
+{
+       return mda_vram_base + y * mda_num_columns + x;
+}
 
 static void mdacon_putc(struct vc_data *c, int ch, int y, int x)
 {
-       scr_writew(mda_convert_attr(ch), MDA_ADDR(x, y));
+       scr_writew(mda_convert_attr(ch), mda_addr(x, y));
 }
 
 static void mdacon_putcs(struct vc_data *c, const unsigned short *s,
                         int count, int y, int x)
 {
-       u16 *dest = MDA_ADDR(x, y);
+       u16 *dest = mda_addr(x, y);
 
        for (; count > 0; count--) {
                scr_writew(mda_convert_attr(scr_readw(s++)), dest++);
@@ -430,7 +443,7 @@ static void mdacon_putcs(struct vc_data *c, const unsigned short *s,
 static void mdacon_clear(struct vc_data *c, int y, int x, 
                          int height, int width)
 {
-       u16 *dest = MDA_ADDR(x, y);
+       u16 *dest = mda_addr(x, y);
        u16 eattr = mda_convert_attr(c->vc_video_erase_char);
 
        if (width <= 0 || height <= 0)
@@ -453,7 +466,7 @@ static int mdacon_blank(struct vc_data *c, int blank, int mode_switch)
 {
        if (mda_type == TYPE_MDA) {
                if (blank) 
-                       scr_memsetw((void *)mda_vram_base, 
+                       scr_memsetw(mda_vram_base,
                                mda_convert_attr(c->vc_video_erase_char),
                                c->vc_screenbuf_size);
                /* Tell console.c that it has to restore the screen itself */
@@ -502,16 +515,16 @@ static bool mdacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
        switch (dir) {
 
        case SM_UP:
-               scr_memmovew(MDA_ADDR(0,t), MDA_ADDR(0,t+lines),
+               scr_memmovew(mda_addr(0, t), mda_addr(0, t + lines),
                                (b-t-lines)*mda_num_columns*2);
-               scr_memsetw(MDA_ADDR(0,b-lines), eattr,
+               scr_memsetw(mda_addr(0, b - lines), eattr,
                                lines*mda_num_columns*2);
                break;
 
        case SM_DOWN:
-               scr_memmovew(MDA_ADDR(0,t+lines), MDA_ADDR(0,t),
+               scr_memmovew(mda_addr(0, t + lines), mda_addr(0, t),
                                (b-t-lines)*mda_num_columns*2);
-               scr_memsetw(MDA_ADDR(0,t), eattr, lines*mda_num_columns*2);
+               scr_memsetw(mda_addr(0, t), eattr, lines*mda_num_columns*2);
                break;
        }
 
index 11026e7..b55fdac 100644 (file)
@@ -802,7 +802,7 @@ static int aty_var_to_crtc(const struct fb_info *info,
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
        u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
-       u32 sync, vmode, vdisplay;
+       u32 sync, vmode;
        u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol;
        u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync;
        u32 pix_width, dp_pix_width, dp_chain_mask;
@@ -984,12 +984,6 @@ static int aty_var_to_crtc(const struct fb_info *info,
                v_total <<= 1;
        }
 
-       vdisplay = yres;
-#ifdef CONFIG_FB_ATY_GENERIC_LCD
-       if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON))
-               vdisplay  = par->lcd_height;
-#endif
-
        v_disp--;
        v_sync_strt--;
        v_sync_end--;
@@ -1036,7 +1030,7 @@ static int aty_var_to_crtc(const struct fb_info *info,
                crtc->gen_cntl |= CRTC_INTERLACE_EN;
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
        if (par->lcd_table != 0) {
-               vdisplay = yres;
+               u32 vdisplay = yres;
                if (vmode & FB_VMODE_DOUBLE)
                        vdisplay <<= 1;
                crtc->gen_cntl &= ~(CRTC2_EN | CRTC2_PIX_WIDTH);
index 5324358..7a42238 100644 (file)
@@ -1483,7 +1483,7 @@ __releases(&info->lock)
        return 0;
 }
 
-#ifdef CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA
+#if defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && !defined(CONFIG_MMU)
 unsigned long get_fb_unmapped_area(struct file *filp,
                                   unsigned long addr, unsigned long len,
                                   unsigned long pgoff, unsigned long flags)
@@ -1510,7 +1510,8 @@ static const struct file_operations fb_fops = {
        .open =         fb_open,
        .release =      fb_release,
 #if defined(HAVE_ARCH_FB_UNMAPPED_AREA) || \
-    defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA)
+       (defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && \
+        !defined(CONFIG_MMU))
        .get_unmapped_area = get_fb_unmapped_area,
 #endif
 #ifdef CONFIG_FB_DEFERRED_IO
index ca3d6b3..25abbcf 100644 (file)
@@ -388,7 +388,7 @@ struct fsl_diu_data {
 /* Determine the DMA address of a member of the fsl_diu_data structure */
 #define DMA_ADDR(p, f) ((p)->dma_addr + offsetof(struct fsl_diu_data, f))
 
-static struct mfb_info mfb_template[] = {
+static const struct mfb_info mfb_template[] = {
        {
                .index = PLANE0,
                .id = "Panel0",
@@ -1868,7 +1868,7 @@ static int __init fsl_diu_setup(char *options)
 }
 #endif
 
-static struct of_device_id fsl_diu_match[] = {
+static const struct of_device_id fsl_diu_match[] = {
 #ifdef CONFIG_PPC_MPC512x
        {
                .compatible = "fsl,mpc5121-diu",
index 6b44440..ffc3912 100644 (file)
@@ -907,7 +907,7 @@ static void intelfb_pci_unregister(struct pci_dev *pdev)
  *                       helper functions                      *
  ***************************************************************/
 
-int __inline__ intelfb_var_to_depth(const struct fb_var_screeninfo *var)
+__inline__ int intelfb_var_to_depth(const struct fb_var_screeninfo *var)
 {
        DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n",
                var->bits_per_pixel, var->green.length);
index 11eb094..f6a0b9a 100644 (file)
@@ -2001,7 +2001,7 @@ static void matroxfb_register_device(struct matrox_fb_info* minfo) {
        for (drv = matroxfb_driver_l(matroxfb_driver_list.next);
             drv != matroxfb_driver_l(&matroxfb_driver_list);
             drv = matroxfb_driver_l(drv->node.next)) {
-               if (drv && drv->probe) {
+               if (drv->probe) {
                        void *p = drv->probe(minfo);
                        if (p) {
                                minfo->drivers_data[i] = p;
index e3d9b9e..938cba0 100644 (file)
@@ -79,12 +79,12 @@ static struct omap_lcd_controller {
        unsigned long           vram_size;
 } lcdc;
 
-static void inline enable_irqs(int mask)
+static inline void enable_irqs(int mask)
 {
        lcdc.irq_mask |= mask;
 }
 
-static void inline disable_irqs(int mask)
+static inline void disable_irqs(int mask)
 {
        lcdc.irq_mask &= ~mask;
 }
@@ -466,7 +466,7 @@ static void calc_ck_div(int is_tft, int pck, int *pck_div)
        }
 }
 
-static void inline setup_regs(void)
+static inline void setup_regs(void)
 {
        u32 l;
        struct lcd_panel *panel = lcdc.fbdev->panel;
index f4cbfb3..3479a47 100644 (file)
@@ -62,7 +62,7 @@ struct caps_table_struct {
        const char *name;
 };
 
-static struct caps_table_struct ctrl_caps[] = {
+static const struct caps_table_struct ctrl_caps[] = {
        { OMAPFB_CAPS_MANUAL_UPDATE,  "manual update" },
        { OMAPFB_CAPS_TEARSYNC,       "tearing synchronization" },
        { OMAPFB_CAPS_PLANE_RELOCATE_MEM, "relocate plane memory" },
@@ -74,7 +74,7 @@ static struct caps_table_struct ctrl_caps[] = {
        { OMAPFB_CAPS_SET_BACKLIGHT,  "backlight setting" },
 };
 
-static struct caps_table_struct color_caps[] = {
+static const struct caps_table_struct color_caps[] = {
        { 1 << OMAPFB_COLOR_RGB565,     "RGB565", },
        { 1 << OMAPFB_COLOR_YUV422,     "YUV422", },
        { 1 << OMAPFB_COLOR_YUV420,     "YUV420", },
@@ -1384,7 +1384,7 @@ static struct attribute *panel_attrs[] = {
        NULL,
 };
 
-static struct attribute_group panel_attr_grp = {
+static const struct attribute_group panel_attr_grp = {
        .name  = "panel",
        .attrs = panel_attrs,
 };
@@ -1406,7 +1406,7 @@ static struct attribute *ctrl_attrs[] = {
        NULL,
 };
 
-static struct attribute_group ctrl_attr_grp = {
+static const struct attribute_group ctrl_attr_grp = {
        .name  = "ctrl",
        .attrs = ctrl_attrs,
 };
index fd2b372..bef4315 100644 (file)
@@ -100,7 +100,7 @@ static void hw_guard_wait(struct panel_drv_data *ddata)
 {
        unsigned long wait = ddata->hw_guard_end - jiffies;
 
-       if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
+       if ((long)wait > 0 && time_before_eq(wait, ddata->hw_guard_wait)) {
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout(wait);
        }
@@ -559,7 +559,7 @@ static struct attribute *dsicm_attrs[] = {
        NULL,
 };
 
-static struct attribute_group dsicm_attr_group = {
+static const struct attribute_group dsicm_attr_group = {
        .attrs = dsicm_attrs,
 };
 
index 9e2a67f..44b96af 100644 (file)
@@ -182,22 +182,16 @@ static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
 static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
                                            const char *buf, size_t size)
 {
-       enum omap_dss_trans_key_type key_type;
        struct omap_overlay_manager_info info;
        int r;
 
-       for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
-                       key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
-               if (sysfs_streq(buf, trans_key_type_str[key_type]))
-                       break;
-       }
-
-       if (key_type == ARRAY_SIZE(trans_key_type_str))
-               return -EINVAL;
+       r = sysfs_match_string(trans_key_type_str, buf);
+       if (r < 0)
+               return r;
 
        mgr->get_manager_info(mgr, &info);
 
-       info.trans_key_type = key_type;
+       info.trans_key_type = r;
 
        r = mgr->set_manager_info(mgr, &info);
        if (r)
index b21a89b..c3d49e1 100644 (file)
@@ -1436,7 +1436,10 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
        pr_debug("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3);
 
        /* enable LCD controller clock */
-       clk_prepare_enable(fbi->clk);
+       if (clk_prepare_enable(fbi->clk)) {
+               pr_err("%s: Failed to prepare clock\n", __func__);
+               return;
+       }
 
        if (fbi->lccr0 & LCCR0_LCDT)
                return;
index 885ee3a..c3a4650 100644 (file)
@@ -2301,7 +2301,7 @@ static int sh_mobile_lcdc_check_fb(struct backlight_device *bdev,
        return (info->bl_dev == bdev);
 }
 
-static struct backlight_ops sh_mobile_lcdc_bl_ops = {
+static const struct backlight_ops sh_mobile_lcdc_bl_ops = {
        .options        = BL_CORE_SUSPENDRESUME,
        .update_status  = sh_mobile_lcdc_update_bl,
        .get_brightness = sh_mobile_lcdc_get_brightness,
index 98af9e0..dc0e8d9 100644 (file)
@@ -5,6 +5,9 @@
  *     Loosely based upon the vesafb driver.
  *
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -149,8 +152,8 @@ static int uvesafb_exec(struct uvesafb_ktask *task)
         * allowed by connector.
         */
        if (sizeof(*m) + len > CONNECTOR_MAX_MSG_SIZE) {
-               printk(KERN_WARNING "uvesafb: message too long (%d), "
-                       "can't execute task\n", (int)(sizeof(*m) + len));
+               pr_warn("message too long (%d), can't execute task\n",
+                       (int)(sizeof(*m) + len));
                return -E2BIG;
        }
 
@@ -198,10 +201,8 @@ static int uvesafb_exec(struct uvesafb_ktask *task)
                 */
                err = uvesafb_helper_start();
                if (err) {
-                       printk(KERN_ERR "uvesafb: failed to execute %s\n",
-                                       v86d_path);
-                       printk(KERN_ERR "uvesafb: make sure that the v86d "
-                                       "helper is installed and executable\n");
+                       pr_err("failed to execute %s\n", v86d_path);
+                       pr_err("make sure that the v86d helper is installed and executable\n");
                } else {
                        v86d_started = 1;
                        err = cn_netlink_send(m, 0, 0, gfp_any());
@@ -375,9 +376,8 @@ static u8 *uvesafb_vbe_state_save(struct uvesafb_par *par)
        err = uvesafb_exec(task);
 
        if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
-               printk(KERN_WARNING "uvesafb: VBE get state call "
-                               "failed (eax=0x%x, err=%d)\n",
-                               task->t.regs.eax, err);
+               pr_warn("VBE get state call failed (eax=0x%x, err=%d)\n",
+                       task->t.regs.eax, err);
                kfree(state);
                state = NULL;
        }
@@ -407,9 +407,8 @@ static void uvesafb_vbe_state_restore(struct uvesafb_par *par, u8 *state_buf)
 
        err = uvesafb_exec(task);
        if (err || (task->t.regs.eax & 0xffff) != 0x004f)
-               printk(KERN_WARNING "uvesafb: VBE state restore call "
-                               "failed (eax=0x%x, err=%d)\n",
-                               task->t.regs.eax, err);
+               pr_warn("VBE state restore call failed (eax=0x%x, err=%d)\n",
+                       task->t.regs.eax, err);
 
        uvesafb_free(task);
 }
@@ -427,24 +426,22 @@ static int uvesafb_vbe_getinfo(struct uvesafb_ktask *task,
 
        err = uvesafb_exec(task);
        if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
-               printk(KERN_ERR "uvesafb: Getting VBE info block failed "
-                               "(eax=0x%x, err=%d)\n", (u32)task->t.regs.eax,
-                               err);
+               pr_err("Getting VBE info block failed (eax=0x%x, err=%d)\n",
+                      (u32)task->t.regs.eax, err);
                return -EINVAL;
        }
 
        if (par->vbe_ib.vbe_version < 0x0200) {
-               printk(KERN_ERR "uvesafb: Sorry, pre-VBE 2.0 cards are "
-                               "not supported.\n");
+               pr_err("Sorry, pre-VBE 2.0 cards are not supported\n");
                return -EINVAL;
        }
 
        if (!par->vbe_ib.mode_list_ptr) {
-               printk(KERN_ERR "uvesafb: Missing mode list!\n");
+               pr_err("Missing mode list!\n");
                return -EINVAL;
        }
 
-       printk(KERN_INFO "uvesafb: ");
+       pr_info("");
 
        /*
         * Convert string pointers and the mode list pointer into
@@ -452,23 +449,24 @@ static int uvesafb_vbe_getinfo(struct uvesafb_ktask *task,
         * video adapter and its vendor.
         */
        if (par->vbe_ib.oem_vendor_name_ptr)
-               printk("%s, ",
+               pr_cont("%s, ",
                        ((char *)task->buf) + par->vbe_ib.oem_vendor_name_ptr);
 
        if (par->vbe_ib.oem_product_name_ptr)
-               printk("%s, ",
+               pr_cont("%s, ",
                        ((char *)task->buf) + par->vbe_ib.oem_product_name_ptr);
 
        if (par->vbe_ib.oem_product_rev_ptr)
-               printk("%s, ",
+               pr_cont("%s, ",
                        ((char *)task->buf) + par->vbe_ib.oem_product_rev_ptr);
 
        if (par->vbe_ib.oem_string_ptr)
-               printk("OEM: %s, ",
+               pr_cont("OEM: %s, ",
                        ((char *)task->buf) + par->vbe_ib.oem_string_ptr);
 
-       printk("VBE v%d.%d\n", ((par->vbe_ib.vbe_version & 0xff00) >> 8),
-                       par->vbe_ib.vbe_version & 0xff);
+       pr_cont("VBE v%d.%d\n",
+               (par->vbe_ib.vbe_version & 0xff00) >> 8,
+               par->vbe_ib.vbe_version & 0xff);
 
        return 0;
 }
@@ -507,8 +505,7 @@ static int uvesafb_vbe_getmodes(struct uvesafb_ktask *task,
 
                err = uvesafb_exec(task);
                if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
-                       printk(KERN_WARNING "uvesafb: Getting mode info block "
-                               "for mode 0x%x failed (eax=0x%x, err=%d)\n",
+                       pr_warn("Getting mode info block for mode 0x%x failed (eax=0x%x, err=%d)\n",
                                *mode, (u32)task->t.regs.eax, err);
                        mode++;
                        par->vbe_modes_cnt--;
@@ -569,23 +566,20 @@ static int uvesafb_vbe_getpmi(struct uvesafb_ktask *task,
                                                + task->t.regs.edi);
                par->pmi_start = (u8 *)par->pmi_base + par->pmi_base[1];
                par->pmi_pal = (u8 *)par->pmi_base + par->pmi_base[2];
-               printk(KERN_INFO "uvesafb: protected mode interface info at "
-                                "%04x:%04x\n",
-                                (u16)task->t.regs.es, (u16)task->t.regs.edi);
-               printk(KERN_INFO "uvesafb: pmi: set display start = %p, "
-                                "set palette = %p\n", par->pmi_start,
-                                par->pmi_pal);
+               pr_info("protected mode interface info at %04x:%04x\n",
+                       (u16)task->t.regs.es, (u16)task->t.regs.edi);
+               pr_info("pmi: set display start = %p, set palette = %p\n",
+                       par->pmi_start, par->pmi_pal);
 
                if (par->pmi_base[3]) {
-                       printk(KERN_INFO "uvesafb: pmi: ports = ");
+                       pr_info("pmi: ports =");
                        for (i = par->pmi_base[3]/2;
                                        par->pmi_base[i] != 0xffff; i++)
-                               printk("%x ", par->pmi_base[i]);
-                       printk("\n");
+                               pr_cont(" %x", par->pmi_base[i]);
+                       pr_cont("\n");
 
                        if (par->pmi_base[i] != 0xffff) {
-                               printk(KERN_INFO "uvesafb: can't handle memory"
-                                                " requests, pmi disabled\n");
+                               pr_info("can't handle memory requests, pmi disabled\n");
                                par->ypan = par->pmi_setpal = 0;
                        }
                }
@@ -634,17 +628,13 @@ static int uvesafb_vbe_getedid(struct uvesafb_ktask *task, struct fb_info *info)
                return -EINVAL;
 
        if ((task->t.regs.ebx & 0x3) == 3) {
-               printk(KERN_INFO "uvesafb: VBIOS/hardware supports both "
-                                "DDC1 and DDC2 transfers\n");
+               pr_info("VBIOS/hardware supports both DDC1 and DDC2 transfers\n");
        } else if ((task->t.regs.ebx & 0x3) == 2) {
-               printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC2 "
-                                "transfers\n");
+               pr_info("VBIOS/hardware supports DDC2 transfers\n");
        } else if ((task->t.regs.ebx & 0x3) == 1) {
-               printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC1 "
-                                "transfers\n");
+               pr_info("VBIOS/hardware supports DDC1 transfers\n");
        } else {
-               printk(KERN_INFO "uvesafb: VBIOS/hardware doesn't support "
-                                "DDC transfers\n");
+               pr_info("VBIOS/hardware doesn't support DDC transfers\n");
                return -EINVAL;
        }
 
@@ -718,14 +708,12 @@ static void uvesafb_vbe_getmonspecs(struct uvesafb_ktask *task,
        }
 
        if (info->monspecs.gtf)
-               printk(KERN_INFO
-                       "uvesafb: monitor limits: vf = %d Hz, hf = %d kHz, "
-                       "clk = %d MHz\n", info->monspecs.vfmax,
+               pr_info("monitor limits: vf = %d Hz, hf = %d kHz, clk = %d MHz\n",
+                       info->monspecs.vfmax,
                        (int)(info->monspecs.hfmax / 1000),
                        (int)(info->monspecs.dclkmax / 1000000));
        else
-               printk(KERN_INFO "uvesafb: no monitor limits have been set, "
-                                "default refresh rate will be used\n");
+               pr_info("no monitor limits have been set, default refresh rate will be used\n");
 
        /* Add VBE modes to the modelist. */
        for (i = 0; i < par->vbe_modes_cnt; i++) {
@@ -779,8 +767,7 @@ static void uvesafb_vbe_getstatesize(struct uvesafb_ktask *task,
        err = uvesafb_exec(task);
 
        if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
-               printk(KERN_WARNING "uvesafb: VBE state buffer size "
-                       "cannot be determined (eax=0x%x, err=%d)\n",
+               pr_warn("VBE state buffer size cannot be determined (eax=0x%x, err=%d)\n",
                        task->t.regs.eax, err);
                par->vbe_state_size = 0;
                return;
@@ -815,8 +802,7 @@ static int uvesafb_vbe_init(struct fb_info *info)
        if (par->pmi_setpal || par->ypan) {
                if (__supported_pte_mask & _PAGE_NX) {
                        par->pmi_setpal = par->ypan = 0;
-                       printk(KERN_WARNING "uvesafb: NX protection is active, "
-                                           "better not use the PMI.\n");
+                       pr_warn("NX protection is active, better not use the PMI\n");
                } else {
                        uvesafb_vbe_getpmi(task, par);
                }
@@ -859,8 +845,7 @@ static int uvesafb_vbe_init_mode(struct fb_info *info)
                                goto gotmode;
                        }
                }
-               printk(KERN_INFO "uvesafb: requested VBE mode 0x%x is "
-                                "unavailable\n", vbemode);
+               pr_info("requested VBE mode 0x%x is unavailable\n", vbemode);
                vbemode = 0;
        }
 
@@ -1181,8 +1166,8 @@ static int uvesafb_open(struct fb_info *info, int user)
        if (!cnt && par->vbe_state_size) {
                buf =  uvesafb_vbe_state_save(par);
                if (IS_ERR(buf)) {
-                       printk(KERN_WARNING "uvesafb: save hardware state"
-                               "failed, error code is %ld!\n", PTR_ERR(buf));
+                       pr_warn("save hardware state failed, error code is %ld!\n",
+                               PTR_ERR(buf));
                } else {
                        par->vbe_state_orig = buf;
                }
@@ -1293,17 +1278,16 @@ setmode:
                 * use our own timings.  Try again with the default timings.
                 */
                if (crtc != NULL) {
-                       printk(KERN_WARNING "uvesafb: mode switch failed "
-                               "(eax=0x%x, err=%d). Trying again with "
-                               "default timings.\n", task->t.regs.eax, err);
+                       pr_warn("mode switch failed (eax=0x%x, err=%d) - trying again with default timings\n",
+                               task->t.regs.eax, err);
                        uvesafb_reset(task);
                        kfree(crtc);
                        crtc = NULL;
                        info->var.pixclock = 0;
                        goto setmode;
                } else {
-                       printk(KERN_ERR "uvesafb: mode switch failed (eax="
-                               "0x%x, err=%d)\n", task->t.regs.eax, err);
+                       pr_err("mode switch failed (eax=0x%x, err=%d)\n",
+                              task->t.regs.eax, err);
                        err = -EINVAL;
                        goto out;
                }
@@ -1510,13 +1494,11 @@ static void uvesafb_init_info(struct fb_info *info, struct vbe_mode_ib *mode)
                                 mode->bytes_per_scan_line;
 
        if (par->ypan && info->var.yres_virtual > info->var.yres) {
-               printk(KERN_INFO "uvesafb: scrolling: %s "
-                       "using protected mode interface, "
-                       "yres_virtual=%d\n",
+               pr_info("scrolling: %s using protected mode interface, yres_virtual=%d\n",
                        (par->ypan > 1) ? "ywrap" : "ypan",
                        info->var.yres_virtual);
        } else {
-               printk(KERN_INFO "uvesafb: scrolling: redraw\n");
+               pr_info("scrolling: redraw\n");
                info->var.yres_virtual = info->var.yres;
                par->ypan = 0;
        }
@@ -1704,7 +1686,7 @@ static int uvesafb_probe(struct platform_device *dev)
 
        err = uvesafb_vbe_init(info);
        if (err) {
-               printk(KERN_ERR "uvesafb: vbe_init() failed with %d\n", err);
+               pr_err("vbe_init() failed with %d\n", err);
                goto out;
        }
 
@@ -1726,15 +1708,15 @@ static int uvesafb_probe(struct platform_device *dev)
        uvesafb_init_info(info, mode);
 
        if (!request_region(0x3c0, 32, "uvesafb")) {
-               printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n");
+               pr_err("request region 0x3c0-0x3e0 failed\n");
                err = -EIO;
                goto out_mode;
        }
 
        if (!request_mem_region(info->fix.smem_start, info->fix.smem_len,
                                "uvesafb")) {
-               printk(KERN_ERR "uvesafb: cannot reserve video memory at "
-                               "0x%lx\n", info->fix.smem_start);
+               pr_err("cannot reserve video memory at 0x%lx\n",
+                      info->fix.smem_start);
                err = -EIO;
                goto out_reg;
        }
@@ -1743,10 +1725,8 @@ static int uvesafb_probe(struct platform_device *dev)
        uvesafb_ioremap(info);
 
        if (!info->screen_base) {
-               printk(KERN_ERR
-                       "uvesafb: abort, cannot ioremap 0x%x bytes of video "
-                       "memory at 0x%lx\n",
-                       info->fix.smem_len, info->fix.smem_start);
+               pr_err("abort, cannot ioremap 0x%x bytes of video memory at 0x%lx\n",
+                      info->fix.smem_len, info->fix.smem_start);
                err = -EIO;
                goto out_mem;
        }
@@ -1754,16 +1734,14 @@ static int uvesafb_probe(struct platform_device *dev)
        platform_set_drvdata(dev, info);
 
        if (register_framebuffer(info) < 0) {
-               printk(KERN_ERR
-                       "uvesafb: failed to register framebuffer device\n");
+               pr_err("failed to register framebuffer device\n");
                err = -EINVAL;
                goto out_unmap;
        }
 
-       printk(KERN_INFO "uvesafb: framebuffer at 0x%lx, mapped to 0x%p, "
-                       "using %dk, total %dk\n", info->fix.smem_start,
-                       info->screen_base, info->fix.smem_len/1024,
-                       par->vbe_ib.total_memory * 64);
+       pr_info("framebuffer at 0x%lx, mapped to 0x%p, using %dk, total %dk\n",
+               info->fix.smem_start, info->screen_base,
+               info->fix.smem_len / 1024, par->vbe_ib.total_memory * 64);
        fb_info(info, "%s frame buffer device\n", info->fix.id);
 
        err = sysfs_create_group(&dev->dev.kobj, &uvesafb_dev_attgrp);
@@ -1871,8 +1849,7 @@ static int uvesafb_setup(char *options)
                else if (this_opt[0] >= '0' && this_opt[0] <= '9') {
                        mode_option = this_opt;
                } else {
-                       printk(KERN_WARNING
-                               "uvesafb: unrecognized option %s\n", this_opt);
+                       pr_warn("unrecognized option %s\n", this_opt);
                }
        }
 
@@ -1931,8 +1908,7 @@ static int uvesafb_init(void)
                err = driver_create_file(&uvesafb_driver.driver,
                                &driver_attr_v86d);
                if (err) {
-                       printk(KERN_WARNING "uvesafb: failed to register "
-                                       "attributes\n");
+                       pr_warn("failed to register attributes\n");
                        err = 0;
                }
        }
index ebc6e6e..ba105c8 100644 (file)
@@ -185,6 +185,7 @@ static int __init cr_pll_init(void)
        if (err) {
                printk(KERN_ERR
                       "Carillo Ranch failed to initialize vml_sys.\n");
+               iounmap(mch_regs_base);
                pci_dev_put(mch_dev);
                return err;
        }
index 22caf80..f0b3a0b 100644 (file)
@@ -104,12 +104,6 @@ static u32 page_to_balloon_pfn(struct page *page)
        return pfn * VIRTIO_BALLOON_PAGES_PER_PAGE;
 }
 
-static struct page *balloon_pfn_to_page(u32 pfn)
-{
-       BUG_ON(pfn % VIRTIO_BALLOON_PAGES_PER_PAGE);
-       return pfn_to_page(pfn / VIRTIO_BALLOON_PAGES_PER_PAGE);
-}
-
 static void balloon_ack(struct virtqueue *vq)
 {
        struct virtio_balloon *vb = vq->vdev->priv;
@@ -138,8 +132,10 @@ static void set_page_pfns(struct virtio_balloon *vb,
 {
        unsigned int i;
 
-       /* Set balloon pfns pointing at this page.
-        * Note that the first pfn points at start of the page. */
+       /*
+        * Set balloon pfns pointing at this page.
+        * Note that the first pfn points at start of the page.
+        */
        for (i = 0; i < VIRTIO_BALLOON_PAGES_PER_PAGE; i++)
                pfns[i] = cpu_to_virtio32(vb->vdev,
                                          page_to_balloon_pfn(page) + i);
@@ -182,18 +178,16 @@ static unsigned fill_balloon(struct virtio_balloon *vb, size_t num)
        return num_allocated_pages;
 }
 
-static void release_pages_balloon(struct virtio_balloon *vb)
+static void release_pages_balloon(struct virtio_balloon *vb,
+                                struct list_head *pages)
 {
-       unsigned int i;
-       struct page *page;
+       struct page *page, *next;
 
-       /* Find pfns pointing at start of each page, get pages and free them. */
-       for (i = 0; i < vb->num_pfns; i += VIRTIO_BALLOON_PAGES_PER_PAGE) {
-               page = balloon_pfn_to_page(virtio32_to_cpu(vb->vdev,
-                                                          vb->pfns[i]));
+       list_for_each_entry_safe(page, next, pages, lru) {
                if (!virtio_has_feature(vb->vdev,
                                        VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
                        adjust_managed_page_count(page, 1);
+               list_del(&page->lru);
                put_page(page); /* balloon reference */
        }
 }
@@ -203,6 +197,7 @@ static unsigned leak_balloon(struct virtio_balloon *vb, size_t num)
        unsigned num_freed_pages;
        struct page *page;
        struct balloon_dev_info *vb_dev_info = &vb->vb_dev_info;
+       LIST_HEAD(pages);
 
        /* We can only do one array worth at a time. */
        num = min(num, ARRAY_SIZE(vb->pfns));
@@ -216,6 +211,7 @@ static unsigned leak_balloon(struct virtio_balloon *vb, size_t num)
                if (!page)
                        break;
                set_page_pfns(vb, vb->pfns + vb->num_pfns, page);
+               list_add(&page->lru, &pages);
                vb->num_pages -= VIRTIO_BALLOON_PAGES_PER_PAGE;
        }
 
@@ -227,7 +223,7 @@ static unsigned leak_balloon(struct virtio_balloon *vb, size_t num)
         */
        if (vb->num_pfns != 0)
                tell_host(vb, vb->deflate_vq);
-       release_pages_balloon(vb);
+       release_pages_balloon(vb, &pages);
        mutex_unlock(&vb->balloon_lock);
        return num_freed_pages;
 }
index 5e1b548..9aaa177 100644 (file)
@@ -391,7 +391,7 @@ static inline int virtqueue_add(struct virtqueue *_vq,
        vq->desc_state[head].data = data;
        if (indirect)
                vq->desc_state[head].indir_desc = desc;
-       if (ctx)
+       else
                vq->desc_state[head].indir_desc = ctx;
 
        /* Put entry in available array (but don't update avail->idx until they
index 3612542..83fc9aa 100644 (file)
@@ -704,7 +704,8 @@ static int omap_hdq_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               ret = -ENXIO;
+               dev_dbg(&pdev->dev, "Failed to get IRQ: %d\n", irq);
+               ret = irq;
                goto err_irq;
        }
 
index 95ea7e6..74471e7 100644 (file)
@@ -728,6 +728,7 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
        memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
        atomic_set(&sl->refcnt, 1);
        atomic_inc(&sl->master->refcnt);
+       dev->slave_count++;
 
        /* slave modules need to be loaded in a context with unlocked mutex */
        mutex_unlock(&dev->mutex);
@@ -747,11 +748,11 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
 
        sl->family = f;
 
-
        err = __w1_attach_slave_device(sl);
        if (err < 0) {
                dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__,
                         sl->name);
+               dev->slave_count--;
                w1_family_put(sl->family);
                atomic_dec(&sl->master->refcnt);
                kfree(sl);
@@ -759,7 +760,6 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
        }
 
        sl->ttl = dev->slave_ttl;
-       dev->slave_count++;
 
        memcpy(msg.id.id, rn, sizeof(msg.id));
        msg.type = W1_SLAVE_ADD;
index 50dcb68..ab60925 100644 (file)
@@ -780,6 +780,9 @@ static int __init balloon_init(void)
        }
 #endif
 
+       /* Init the xen-balloon driver. */
+       xen_balloon_init();
+
        return 0;
 }
 subsys_initcall(balloon_init);
index b241bfa..bae1f5d 100644 (file)
@@ -343,14 +343,6 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
        info->cpu = cpu;
 }
 
-static void xen_evtchn_mask_all(void)
-{
-       unsigned int evtchn;
-
-       for (evtchn = 0; evtchn < xen_evtchn_nr_channels(); evtchn++)
-               mask_evtchn(evtchn);
-}
-
 /**
  * notify_remote_via_irq - send event to remote end of event channel via irq
  * @irq: irq of event channel to send event to
@@ -1573,7 +1565,6 @@ void xen_irq_resume(void)
        struct irq_info *info;
 
        /* New event-channel space is not 'live' yet. */
-       xen_evtchn_mask_all();
        xen_evtchn_resume();
 
        /* No IRQ <-> event-channel mappings. */
@@ -1681,6 +1672,7 @@ module_param(fifo_events, bool, 0);
 void __init xen_init_IRQ(void)
 {
        int ret = -EINVAL;
+       unsigned int evtchn;
 
        if (fifo_events)
                ret = xen_evtchn_fifo_init();
@@ -1692,7 +1684,8 @@ void __init xen_init_IRQ(void)
        BUG_ON(!evtchn_to_irq);
 
        /* No event channels are 'live' right now. */
-       xen_evtchn_mask_all();
+       for (evtchn = 0; evtchn < xen_evtchn_nr_channels(); evtchn++)
+               mask_evtchn(evtchn);
 
        pirq_needs_eoi = pirq_needs_eoi_flag;
 
index d6786b8..2c6a911 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/delay.h>
 #include <linux/hardirq.h>
 #include <linux/workqueue.h>
+#include <linux/ratelimit.h>
 
 #include <xen/xen.h>
 #include <xen/interface/xen.h>
@@ -1072,8 +1073,14 @@ static int gnttab_expand(unsigned int req_entries)
        cur = nr_grant_frames;
        extra = ((req_entries + (grefs_per_grant_frame-1)) /
                 grefs_per_grant_frame);
-       if (cur + extra > gnttab_max_grant_frames())
+       if (cur + extra > gnttab_max_grant_frames()) {
+               pr_warn_ratelimited("xen/grant-table: max_grant_frames reached"
+                                   " cur=%u extra=%u limit=%u"
+                                   " gnttab_free_count=%u req_entries=%u\n",
+                                   cur, extra, gnttab_max_grant_frames(),
+                                   gnttab_free_count, req_entries);
                return -ENOSPC;
+       }
 
        rc = gnttab_map(cur, cur + extra - 1);
        if (rc == 0)
index e7715cb..e89136a 100644 (file)
@@ -59,6 +59,8 @@ static void watch_target(struct xenbus_watch *watch,
 {
        unsigned long long new_target;
        int err;
+       static bool watch_fired;
+       static long target_diff;
 
        err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target);
        if (err != 1) {
@@ -69,7 +71,14 @@ static void watch_target(struct xenbus_watch *watch,
        /* The given memory/target value is in KiB, so it needs converting to
         * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10.
         */
-       balloon_set_new_target(new_target >> (PAGE_SHIFT - 10));
+       new_target >>= PAGE_SHIFT - 10;
+       if (watch_fired) {
+               balloon_set_new_target(new_target - target_diff);
+               return;
+       }
+
+       watch_fired = true;
+       target_diff = new_target - balloon_stats.target_pages;
 }
 static struct xenbus_watch target_watch = {
        .node = "memory/target",
@@ -94,22 +103,15 @@ static struct notifier_block xenstore_notifier = {
        .notifier_call = balloon_init_watcher,
 };
 
-static int __init balloon_init(void)
+void xen_balloon_init(void)
 {
-       if (!xen_domain())
-               return -ENODEV;
-
-       pr_info("Initialising balloon driver\n");
-
        register_balloon(&balloon_dev);
 
        register_xen_selfballooning(&balloon_dev);
 
        register_xenstore_notifier(&xenstore_notifier);
-
-       return 0;
 }
-subsys_initcall(balloon_init);
+EXPORT_SYMBOL_GPL(xen_balloon_init);
 
 #define BALLOON_SHOW(name, format, args...)                            \
        static ssize_t show_##name(struct device *dev,                  \
index d6950e0..7bc88fd 100644 (file)
@@ -134,11 +134,8 @@ struct vscsibk_pend {
        struct page *pages[VSCSI_MAX_GRANTS];
 
        struct se_cmd se_cmd;
-};
 
-struct scsiback_tmr {
-       atomic_t tmr_complete;
-       wait_queue_head_t tmr_wait;
+       struct completion tmr_done;
 };
 
 #define VSCSI_DEFAULT_SESSION_TAGS     128
@@ -599,36 +596,28 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req,
        struct scsiback_tpg *tpg = pending_req->v2p->tpg;
        struct scsiback_nexus *nexus = tpg->tpg_nexus;
        struct se_cmd *se_cmd = &pending_req->se_cmd;
-       struct scsiback_tmr *tmr;
        u64 unpacked_lun = pending_req->v2p->lun;
        int rc, err = FAILED;
 
-       tmr = kzalloc(sizeof(struct scsiback_tmr), GFP_KERNEL);
-       if (!tmr) {
-               target_put_sess_cmd(se_cmd);
-               goto err;
-       }
-
-       init_waitqueue_head(&tmr->tmr_wait);
+       init_completion(&pending_req->tmr_done);
 
        rc = target_submit_tmr(&pending_req->se_cmd, nexus->tvn_se_sess,
                               &pending_req->sense_buffer[0],
-                              unpacked_lun, tmr, act, GFP_KERNEL,
+                              unpacked_lun, NULL, act, GFP_KERNEL,
                               tag, TARGET_SCF_ACK_KREF);
        if (rc)
                goto err;
 
-       wait_event(tmr->tmr_wait, atomic_read(&tmr->tmr_complete));
+       wait_for_completion(&pending_req->tmr_done);
 
        err = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ?
                SUCCESS : FAILED;
 
        scsiback_do_resp_with_sense(NULL, err, 0, pending_req);
-       transport_generic_free_cmd(&pending_req->se_cmd, 1);
+       transport_generic_free_cmd(&pending_req->se_cmd, 0);
        return;
+
 err:
-       if (tmr)
-               kfree(tmr);
        scsiback_do_resp_with_sense(NULL, err, 0, pending_req);
 }
 
@@ -1389,12 +1378,6 @@ static int scsiback_check_stop_free(struct se_cmd *se_cmd)
 static void scsiback_release_cmd(struct se_cmd *se_cmd)
 {
        struct se_session *se_sess = se_cmd->se_sess;
-       struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
-
-       if (se_tmr && se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) {
-               struct scsiback_tmr *tmr = se_tmr->fabric_tmr_ptr;
-               kfree(tmr);
-       }
 
        percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag);
 }
@@ -1455,11 +1438,10 @@ static int scsiback_queue_status(struct se_cmd *se_cmd)
 
 static void scsiback_queue_tm_rsp(struct se_cmd *se_cmd)
 {
-       struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
-       struct scsiback_tmr *tmr = se_tmr->fabric_tmr_ptr;
+       struct vscsibk_pend *pending_req = container_of(se_cmd,
+                               struct vscsibk_pend, se_cmd);
 
-       atomic_set(&tmr->tmr_complete, 1);
-       wake_up(&tmr->tmr_wait);
+       complete(&pending_req->tmr_done);
 }
 
 static void scsiback_aborted_task(struct se_cmd *se_cmd)
index 6662071..a67e955 100644 (file)
@@ -151,8 +151,8 @@ static unsigned long frontswap_inertia_counter;
 static void frontswap_selfshrink(void)
 {
        static unsigned long cur_frontswap_pages;
-       static unsigned long last_frontswap_pages;
-       static unsigned long tgt_frontswap_pages;
+       unsigned long last_frontswap_pages;
+       unsigned long tgt_frontswap_pages;
 
        last_frontswap_pages = cur_frontswap_pages;
        cur_frontswap_pages = frontswap_curr_pages();
index 967f069..71ddfb4 100644 (file)
@@ -87,7 +87,6 @@ static int __init xenfs_init(void)
        if (xen_domain())
                return register_filesystem(&xenfs_type);
 
-       pr_info("not registering filesystem on non-xen platform\n");
        return 0;
 }
 
index c202930..8fb89dd 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/parser.h>
 #include <linux/idr.h>
 #include <linux/slab.h>
+#include <linux/seq_file.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 #include <net/9p/transport.h>
@@ -82,6 +83,13 @@ static const match_table_t tokens = {
        {Opt_err, NULL}
 };
 
+static const char *const v9fs_cache_modes[nr__p9_cache_modes] = {
+       [CACHE_NONE]    = "none",
+       [CACHE_MMAP]    = "mmap",
+       [CACHE_LOOSE]   = "loose",
+       [CACHE_FSCACHE] = "fscache",
+};
+
 /* Interpret mount options for cache mode */
 static int get_cache_mode(char *s)
 {
@@ -104,6 +112,58 @@ static int get_cache_mode(char *s)
        return version;
 }
 
+/*
+ * Display the mount options in /proc/mounts.
+ */
+int v9fs_show_options(struct seq_file *m, struct dentry *root)
+{
+       struct v9fs_session_info *v9ses = root->d_sb->s_fs_info;
+
+       if (v9ses->debug)
+               seq_printf(m, ",debug=%x", v9ses->debug);
+       if (!uid_eq(v9ses->dfltuid, V9FS_DEFUID))
+               seq_printf(m, ",dfltuid=%u",
+                          from_kuid_munged(&init_user_ns, v9ses->dfltuid));
+       if (!gid_eq(v9ses->dfltgid, V9FS_DEFGID))
+               seq_printf(m, ",dfltgid=%u",
+                          from_kgid_munged(&init_user_ns, v9ses->dfltgid));
+       if (v9ses->afid != ~0)
+               seq_printf(m, ",afid=%u", v9ses->afid);
+       if (strcmp(v9ses->uname, V9FS_DEFUSER) != 0)
+               seq_printf(m, ",uname=%s", v9ses->uname);
+       if (strcmp(v9ses->aname, V9FS_DEFANAME) != 0)
+               seq_printf(m, ",aname=%s", v9ses->aname);
+       if (v9ses->nodev)
+               seq_puts(m, ",nodevmap");
+       if (v9ses->cache)
+               seq_printf(m, ",%s", v9fs_cache_modes[v9ses->cache]);
+#ifdef CONFIG_9P_FSCACHE
+       if (v9ses->cachetag && v9ses->cache == CACHE_FSCACHE)
+               seq_printf(m, ",cachetag=%s", v9ses->cachetag);
+#endif
+
+       switch (v9ses->flags & V9FS_ACCESS_MASK) {
+       case V9FS_ACCESS_USER:
+               seq_puts(m, ",access=user");
+               break;
+       case V9FS_ACCESS_ANY:
+               seq_puts(m, ",access=any");
+               break;
+       case V9FS_ACCESS_CLIENT:
+               seq_puts(m, ",access=client");
+               break;
+       case V9FS_ACCESS_SINGLE:
+               seq_printf(m, ",access=%u",
+                          from_kuid_munged(&init_user_ns, v9ses->uid));
+               break;
+       }
+
+       if (v9ses->flags & V9FS_POSIX_ACL)
+               seq_puts(m, ",posixacl");
+
+       return p9_show_client_options(m, v9ses->clnt);
+}
+
 /**
  * v9fs_parse_options - parse mount options into session structure
  * @v9ses: existing v9fs session information
@@ -230,6 +290,7 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
                        break;
                case Opt_cachetag:
 #ifdef CONFIG_9P_FSCACHE
+                       kfree(v9ses->cachetag);
                        v9ses->cachetag = match_strdup(&args[0]);
 #endif
                        break;
index 76eaf49..982e017 100644 (file)
@@ -67,6 +67,7 @@ enum p9_cache_modes {
        CACHE_MMAP,
        CACHE_LOOSE,
        CACHE_FSCACHE,
+       nr__p9_cache_modes
 };
 
 /**
@@ -137,6 +138,8 @@ static inline struct v9fs_inode *V9FS_I(const struct inode *inode)
        return container_of(inode, struct v9fs_inode, vfs_inode);
 }
 
+extern int v9fs_show_options(struct seq_file *m, struct dentry *root);
+
 struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *,
                                                                        char *);
 extern void v9fs_session_close(struct v9fs_session_info *v9ses);
index a0965fb..8b75463 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/string.h>
 #include <linux/inet.h>
 #include <linux/pagemap.h>
-#include <linux/seq_file.h>
 #include <linux/mount.h>
 #include <linux/idr.h>
 #include <linux/sched.h>
@@ -104,7 +103,6 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
                sb->s_flags |= MS_POSIXACL;
 #endif
 
-       save_mount_options(sb, data);
        return 0;
 }
 
@@ -349,7 +347,7 @@ static const struct super_operations v9fs_super_ops = {
        .destroy_inode = v9fs_destroy_inode,
        .statfs = simple_statfs,
        .evict_inode = v9fs_evict_inode,
-       .show_options = generic_show_options,
+       .show_options = v9fs_show_options,
        .umount_begin = v9fs_umount_begin,
        .write_inode = v9fs_write_inode,
 };
@@ -360,7 +358,7 @@ static const struct super_operations v9fs_super_ops_dotl = {
        .statfs = v9fs_statfs,
        .drop_inode = v9fs_drop_inode,
        .evict_inode = v9fs_evict_inode,
-       .show_options = generic_show_options,
+       .show_options = v9fs_show_options,
        .umount_begin = v9fs_umount_begin,
        .write_inode = v9fs_write_inode_dotl,
 };
index b0e42b6..7aee6d6 100644 (file)
@@ -80,7 +80,6 @@ config EXPORTFS_BLOCK_OPS
 config FILE_LOCKING
        bool "Enable POSIX file locking API" if EXPERT
        default y
-       select PERCPU_RWSEM
        help
          This option enables standard file locking support, required
           for filesystems like NFS and for the flock() system
index c2c27a8..7bf47a4 100644 (file)
 #include <linux/slab.h>
 #include <linux/writeback.h>
 #include <linux/blkdev.h>
+#include <linux/seq_file.h>
 #include "affs.h"
 
 static int affs_statfs(struct dentry *dentry, struct kstatfs *buf);
+static int affs_show_options(struct seq_file *m, struct dentry *root);
 static int affs_remount (struct super_block *sb, int *flags, char *data);
 
 static void
@@ -159,7 +161,7 @@ static const struct super_operations affs_sops = {
        .sync_fs        = affs_sync_fs,
        .statfs         = affs_statfs,
        .remount_fs     = affs_remount,
-       .show_options   = generic_show_options,
+       .show_options   = affs_show_options,
 };
 
 enum {
@@ -293,6 +295,40 @@ parse_options(char *options, kuid_t *uid, kgid_t *gid, int *mode, int *reserved,
        return 1;
 }
 
+static int affs_show_options(struct seq_file *m, struct dentry *root)
+{
+       struct super_block *sb = root->d_sb;
+       struct affs_sb_info *sbi = AFFS_SB(sb);
+
+       if (sb->s_blocksize)
+               seq_printf(m, ",bs=%lu", sb->s_blocksize);
+       if (affs_test_opt(sbi->s_flags, SF_SETMODE))
+               seq_printf(m, ",mode=%o", sbi->s_mode);
+       if (affs_test_opt(sbi->s_flags, SF_MUFS))
+               seq_puts(m, ",mufs");
+       if (affs_test_opt(sbi->s_flags, SF_NO_TRUNCATE))
+               seq_puts(m, ",nofilenametruncate");
+       if (affs_test_opt(sbi->s_flags, SF_PREFIX))
+               seq_printf(m, ",prefix=%s", sbi->s_prefix);
+       if (affs_test_opt(sbi->s_flags, SF_IMMUTABLE))
+               seq_puts(m, ",protect");
+       if (sbi->s_reserved != 2)
+               seq_printf(m, ",reserved=%u", sbi->s_reserved);
+       if (sbi->s_root_block != (sbi->s_reserved + sbi->s_partition_size - 1) / 2)
+               seq_printf(m, ",root=%u", sbi->s_root_block);
+       if (affs_test_opt(sbi->s_flags, SF_SETGID))
+               seq_printf(m, ",setgid=%u",
+                          from_kgid_munged(&init_user_ns, sbi->s_gid));
+       if (affs_test_opt(sbi->s_flags, SF_SETUID))
+               seq_printf(m, ",setuid=%u",
+                          from_kuid_munged(&init_user_ns, sbi->s_uid));
+       if (affs_test_opt(sbi->s_flags, SF_VERBOSE))
+               seq_puts(m, ",verbose");
+       if (sbi->s_volume[0])
+               seq_printf(m, ",volume=%s", sbi->s_volume);
+       return 0;
+}
+
 /* This function definitely needs to be split up. Some fine day I'll
  * hopefully have the guts to do so. Until then: sorry for the mess.
  */
@@ -316,8 +352,6 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
        u8                       sig[4];
        int                      ret;
 
-       save_mount_options(sb, data);
-
        pr_debug("read_super(%s)\n", data ? (const char *)data : "no options");
 
        sb->s_magic             = AFFS_SUPER_MAGIC;
@@ -548,8 +582,6 @@ affs_remount(struct super_block *sb, int *flags, char *data)
        }
 
        flush_delayed_work(&sbi->sb_work);
-       if (new_opts)
-               replace_mount_options(sb, new_opts);
 
        sbi->s_flags = mount_flags;
        sbi->s_mode  = mode;
index 100b207..c05f1f1 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
-#include <rxrpc/packet.h>
 #include "internal.h"
 #include "afs_fs.h"
 
index 02781e7..1074304 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <net/sock.h>
 #include <net/af_rxrpc.h>
-#include <rxrpc/packet.h>
 #include "internal.h"
 #include "afs_cm.h"
 
index 67680c2..689173c 100644 (file)
@@ -37,6 +37,8 @@ static void afs_kill_super(struct super_block *sb);
 static struct inode *afs_alloc_inode(struct super_block *sb);
 static void afs_destroy_inode(struct inode *inode);
 static int afs_statfs(struct dentry *dentry, struct kstatfs *buf);
+static int afs_show_devname(struct seq_file *m, struct dentry *root);
+static int afs_show_options(struct seq_file *m, struct dentry *root);
 
 struct file_system_type afs_fs_type = {
        .owner          = THIS_MODULE,
@@ -53,7 +55,8 @@ static const struct super_operations afs_super_ops = {
        .drop_inode     = afs_drop_inode,
        .destroy_inode  = afs_destroy_inode,
        .evict_inode    = afs_evict_inode,
-       .show_options   = generic_show_options,
+       .show_devname   = afs_show_devname,
+       .show_options   = afs_show_options,
 };
 
 static struct kmem_cache *afs_inode_cachep;
@@ -136,6 +139,45 @@ void __exit afs_fs_exit(void)
 }
 
 /*
+ * Display the mount device name in /proc/mounts.
+ */
+static int afs_show_devname(struct seq_file *m, struct dentry *root)
+{
+       struct afs_super_info *as = root->d_sb->s_fs_info;
+       struct afs_volume *volume = as->volume;
+       struct afs_cell *cell = volume->cell;
+       const char *suf = "";
+       char pref = '%';
+
+       switch (volume->type) {
+       case AFSVL_RWVOL:
+               break;
+       case AFSVL_ROVOL:
+               pref = '#';
+               if (volume->type_force)
+                       suf = ".readonly";
+               break;
+       case AFSVL_BACKVOL:
+               pref = '#';
+               suf = ".backup";
+               break;
+       }
+
+       seq_printf(m, "%c%s:%s%s", pref, cell->name, volume->vlocation->vldb.name, suf);
+       return 0;
+}
+
+/*
+ * Display the mount options in /proc/mounts.
+ */
+static int afs_show_options(struct seq_file *m, struct dentry *root)
+{
+       if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags))
+               seq_puts(m, "autocell");
+       return 0;
+}
+
+/*
  * parse the mount options
  * - this function has been shamelessly adapted from the ext3 fs which
  *   shamelessly adapted it from the msdos fs
@@ -427,7 +469,6 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
                        deactivate_locked_super(sb);
                        goto error;
                }
-               save_mount_options(sb, new_opts);
                sb->s_flags |= MS_ACTIVE;
        } else {
                _debug("reuse");
index d509887..1b7e0f7 100644 (file)
@@ -120,18 +120,15 @@ static int befs_compare_strings(const void *key1, int keylen1,
                                const void *key2, int keylen2);
 
 /**
- * befs_bt_read_super - read in btree superblock convert to cpu byteorder
- * @sb: Filesystem superblock
- * @ds: Datastream to read from
- * @sup: Buffer in which to place the btree superblock
+ * befs_bt_read_super() - read in btree superblock convert to cpu byteorder
+ * @sb:        Filesystem superblock
+ * @ds:        Datastream to read from
+ * @sup:       Buffer in which to place the btree superblock
  *
  * Calls befs_read_datastream to read in the btree superblock and
  * makes sure it is in cpu byteorder, byteswapping if necessary.
- *
- * On success, returns BEFS_OK and *@sup contains the btree superblock,
- * in cpu byte order.
- *
- * On failure, BEFS_ERR is returned.
+ * Return: BEFS_OK on success and if *@sup contains the btree superblock in cpu
+ * byte order. Otherwise return BEFS_ERR on error.
  */
 static int
 befs_bt_read_super(struct super_block *sb, const befs_data_stream *ds,
index 63e7c47..4a4a5a3 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/sched.h>
 #include <linux/cred.h>
 #include <linux/exportfs.h>
+#include <linux/seq_file.h>
 
 #include "befs.h"
 #include "btree.h"
@@ -53,6 +54,7 @@ static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
 static void befs_put_super(struct super_block *);
 static int befs_remount(struct super_block *, int *, char *);
 static int befs_statfs(struct dentry *, struct kstatfs *);
+static int befs_show_options(struct seq_file *, struct dentry *);
 static int parse_options(char *, struct befs_mount_options *);
 static struct dentry *befs_fh_to_dentry(struct super_block *sb,
                                struct fid *fid, int fh_len, int fh_type);
@@ -66,7 +68,7 @@ static const struct super_operations befs_sops = {
        .put_super      = befs_put_super,       /* uninit super */
        .statfs         = befs_statfs,  /* statfs */
        .remount_fs     = befs_remount,
-       .show_options   = generic_show_options,
+       .show_options   = befs_show_options,
 };
 
 /* slab cache for befs_inode_info objects */
@@ -771,6 +773,24 @@ parse_options(char *options, struct befs_mount_options *opts)
        return 1;
 }
 
+static int befs_show_options(struct seq_file *m, struct dentry *root)
+{
+       struct befs_sb_info *befs_sb = BEFS_SB(root->d_sb);
+       struct befs_mount_options *opts = &befs_sb->mount_opts;
+
+       if (!uid_eq(opts->uid, GLOBAL_ROOT_UID))
+               seq_printf(m, ",uid=%u",
+                          from_kuid_munged(&init_user_ns, opts->uid));
+       if (!gid_eq(opts->gid, GLOBAL_ROOT_GID))
+               seq_printf(m, ",gid=%u",
+                          from_kgid_munged(&init_user_ns, opts->gid));
+       if (opts->iocharset)
+               seq_printf(m, ",charset=%s", opts->iocharset);
+       if (opts->debug)
+               seq_puts(m, ",debug");
+       return 0;
+}
+
 /* This function has the responsibiltiy of getting the
  * filesystem ready for unmounting.
  * Basically, we free everything that we allocated in
@@ -804,8 +824,6 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
        const off_t x86_sb_off = 512;
        int blocksize;
 
-       save_mount_options(sb, data);
-
        sb->s_fs_info = kzalloc(sizeof(*befs_sb), GFP_KERNEL);
        if (sb->s_fs_info == NULL)
                goto unacquire_none;
index 25e312c..9a69392 100644 (file)
@@ -419,7 +419,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
                if (i_sblock > info->si_blocks ||
                        i_eblock > info->si_blocks ||
                        i_sblock > i_eblock ||
-                       i_eoff > s_size ||
+                       (i_eoff != le32_to_cpu(-1) && i_eoff > s_size) ||
                        i_sblock * BFS_BSIZE > i_eoff) {
 
                        printf("Inode 0x%08x corrupted\n", i);
index 2edcefc..a1e6860 100644 (file)
@@ -422,9 +422,9 @@ static int load_flat_file(struct linux_binprm *bprm,
 {
        struct flat_hdr *hdr;
        unsigned long textpos, datapos, realdatastart;
-       unsigned long text_len, data_len, bss_len, stack_len, full_data, flags;
+       u32 text_len, data_len, bss_len, stack_len, full_data, flags;
        unsigned long len, memp, memp_size, extra, rlim;
-       unsigned long __user *reloc, *rp;
+       u32 __user *reloc, *rp;
        struct inode *inode;
        int i, rev, relocs;
        loff_t fpos;
@@ -574,7 +574,7 @@ static int load_flat_file(struct linux_binprm *bprm,
                                MAX_SHARED_LIBS * sizeof(unsigned long),
                                FLAT_DATA_ALIGN);
 
-               pr_debug("Allocated data+bss+stack (%ld bytes): %lx\n",
+               pr_debug("Allocated data+bss+stack (%u bytes): %lx\n",
                         data_len + bss_len + stack_len, datapos);
 
                fpos = ntohl(hdr->data_start);
@@ -596,13 +596,13 @@ static int load_flat_file(struct linux_binprm *bprm,
                        goto err;
                }
 
-               reloc = (unsigned long __user *)
+               reloc = (u32 __user *)
                        (datapos + (ntohl(hdr->reloc_start) - text_len));
                memp = realdatastart;
                memp_size = len;
        } else {
 
-               len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
+               len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(u32);
                len = PAGE_ALIGN(len);
                textpos = vm_mmap(NULL, 0, len,
                        PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
@@ -618,10 +618,10 @@ static int load_flat_file(struct linux_binprm *bprm,
 
                realdatastart = textpos + ntohl(hdr->data_start);
                datapos = ALIGN(realdatastart +
-                               MAX_SHARED_LIBS * sizeof(unsigned long),
+                               MAX_SHARED_LIBS * sizeof(u32),
                                FLAT_DATA_ALIGN);
 
-               reloc = (unsigned long __user *)
+               reloc = (u32 __user *)
                        (datapos + (ntohl(hdr->reloc_start) - text_len));
                memp = textpos;
                memp_size = len;
@@ -694,7 +694,7 @@ static int load_flat_file(struct linux_binprm *bprm,
                        ret = result;
                        pr_err("Unable to read code+data+bss, errno %d\n", ret);
                        vm_munmap(textpos, text_len + data_len + extra +
-                               MAX_SHARED_LIBS * sizeof(unsigned long));
+                               MAX_SHARED_LIBS * sizeof(u32));
                        goto err;
                }
        }
@@ -754,8 +754,8 @@ static int load_flat_file(struct linux_binprm *bprm,
         * image.
         */
        if (flags & FLAT_FLAG_GOTPIC) {
-               for (rp = (unsigned long __user *)datapos; ; rp++) {
-                       unsigned long addr, rp_val;
+               for (rp = (u32 __user *)datapos; ; rp++) {
+                       u32 addr, rp_val;
                        if (get_user(rp_val, rp))
                                return -EFAULT;
                        if (rp_val == 0xffffffff)
@@ -784,9 +784,9 @@ static int load_flat_file(struct linux_binprm *bprm,
         * __start to address 4 so that is okay).
         */
        if (rev > OLD_FLAT_VERSION) {
-               unsigned long __maybe_unused persistent = 0;
+               u32 __maybe_unused persistent = 0;
                for (i = 0; i < relocs; i++) {
-                       unsigned long addr, relval;
+                       u32 addr, relval;
 
                        /*
                         * Get the address of the pointer to be
@@ -799,15 +799,18 @@ static int load_flat_file(struct linux_binprm *bprm,
                        if (flat_set_persistent(relval, &persistent))
                                continue;
                        addr = flat_get_relocate_addr(relval);
-                       rp = (unsigned long __user *)calc_reloc(addr, libinfo, id, 1);
-                       if (rp == (unsigned long __user *)RELOC_FAILED) {
+                       rp = (u32 __user *)calc_reloc(addr, libinfo, id, 1);
+                       if (rp == (u32 __user *)RELOC_FAILED) {
                                ret = -ENOEXEC;
                                goto err;
                        }
 
                        /* Get the pointer's value.  */
-                       addr = flat_get_addr_from_rp(rp, relval, flags,
-                                                       &persistent);
+                       ret = flat_get_addr_from_rp(rp, relval, flags,
+                                                       &addr, &persistent);
+                       if (unlikely(ret))
+                               goto err;
+
                        if (addr != 0) {
                                /*
                                 * Do the relocation.  PIC relocs in the data section are
@@ -822,12 +825,14 @@ static int load_flat_file(struct linux_binprm *bprm,
                                }
 
                                /* Write back the relocated pointer.  */
-                               flat_put_addr_at_rp(rp, addr, relval);
+                               ret = flat_put_addr_at_rp(rp, addr, relval);
+                               if (unlikely(ret))
+                                       goto err;
                        }
                }
        } else {
                for (i = 0; i < relocs; i++) {
-                       unsigned long relval;
+                       u32 relval;
                        if (get_user(relval, reloc + i))
                                return -EFAULT;
                        relval = ntohl(relval);
index 2c0b7b5..d2ef9ac 100644 (file)
@@ -152,6 +152,7 @@ csum_failed:
                 * we have verified the checksum already, set page
                 * checked so the end_io handlers know about it
                 */
+               ASSERT(!bio_flagged(bio, BIO_CLONED));
                bio_for_each_segment_all(bvec, cb->orig_bio, i)
                        SetPageChecked(bvec->bv_page);
 
index 086dcba..080e2eb 100644 (file)
@@ -964,6 +964,7 @@ static blk_status_t btree_csum_one_bio(struct bio *bio)
        struct btrfs_root *root;
        int i, ret = 0;
 
+       ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, i) {
                root = BTRFS_I(bvec->bv_page->mapping->host)->root;
                ret = csum_dirty_buffer(root->fs_info, bvec->bv_page);
index 375f8c7..e3b0b41 100644 (file)
@@ -4825,10 +4825,6 @@ skip_async:
                else
                        flush = BTRFS_RESERVE_NO_FLUSH;
                spin_lock(&space_info->lock);
-               if (can_overcommit(fs_info, space_info, orig, flush, false)) {
-                       spin_unlock(&space_info->lock);
-                       break;
-               }
                if (list_empty(&space_info->tickets) &&
                    list_empty(&space_info->priority_tickets)) {
                        spin_unlock(&space_info->lock);
@@ -7589,6 +7585,10 @@ search:
                u64 offset;
                int cached;
 
+               /* If the block group is read-only, we can skip it entirely. */
+               if (unlikely(block_group->ro))
+                       continue;
+
                btrfs_grab_block_group(block_group, delalloc);
                search_start = block_group->key.objectid;
 
@@ -7624,8 +7624,6 @@ have_block_group:
 
                if (unlikely(block_group->cached == BTRFS_CACHE_ERROR))
                        goto loop;
-               if (unlikely(block_group->ro))
-                       goto loop;
 
                /*
                 * Ok we want to try and use the cluster allocator, so
@@ -7839,6 +7837,7 @@ loop:
                failed_alloc = false;
                BUG_ON(index != get_block_group_index(block_group));
                btrfs_release_block_group(block_group, delalloc);
+               cond_resched();
        }
        up_read(&space_info->groups_sem);
 
index 556484c..0aff9b2 100644 (file)
@@ -2258,7 +2258,7 @@ int btrfs_get_io_failure_record(struct inode *inode, u64 start, u64 end,
        return 0;
 }
 
-int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
+bool btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
                           struct io_failure_record *failrec, int failed_mirror)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
@@ -2274,7 +2274,7 @@ int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
                btrfs_debug(fs_info,
                        "Check Repairable: cannot repair, num_copies=%d, next_mirror %d, failed_mirror %d",
                        num_copies, failrec->this_mirror, failed_mirror);
-               return 0;
+               return false;
        }
 
        /*
@@ -2315,10 +2315,10 @@ int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
                btrfs_debug(fs_info,
                        "Check Repairable: (fail) num_copies=%d, next_mirror %d, failed_mirror %d",
                        num_copies, failrec->this_mirror, failed_mirror);
-               return 0;
+               return false;
        }
 
-       return 1;
+       return true;
 }
 
 
@@ -2382,8 +2382,8 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
        if (ret)
                return ret;
 
-       ret = btrfs_check_repairable(inode, failed_bio, failrec, failed_mirror);
-       if (!ret) {
+       if (!btrfs_check_repairable(inode, failed_bio, failrec,
+                                   failed_mirror)) {
                free_io_failure(failure_tree, tree, failrec);
                return -EIO;
        }
@@ -2396,10 +2396,6 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
                                      start - page_offset(page),
                                      (int)phy_offset, failed_bio->bi_end_io,
                                      NULL);
-       if (!bio) {
-               free_io_failure(failure_tree, tree, failrec);
-               return -EIO;
-       }
        bio_set_op_attrs(bio, REQ_OP_READ, read_mode);
 
        btrfs_debug(btrfs_sb(inode->i_sb),
@@ -2456,6 +2452,7 @@ static void end_bio_extent_writepage(struct bio *bio)
        u64 end;
        int i;
 
+       ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
                struct inode *inode = page->mapping->host;
@@ -2526,6 +2523,7 @@ static void end_bio_extent_readpage(struct bio *bio)
        int ret;
        int i;
 
+       ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
                struct inode *inode = page->mapping->host;
@@ -3680,6 +3678,7 @@ static void end_bio_extent_buffer_writepage(struct bio *bio)
        struct extent_buffer *eb;
        int i, done;
 
+       ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
 
index 3fb8513..4f03091 100644 (file)
@@ -539,8 +539,8 @@ void btrfs_free_io_failure_record(struct btrfs_inode *inode, u64 start,
                u64 end);
 int btrfs_get_io_failure_record(struct inode *inode, u64 start, u64 end,
                                struct io_failure_record **failrec_ret);
-int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
-                          struct io_failure_record *failrec, int fail_mirror);
+bool btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
+                           struct io_failure_record *failrec, int fail_mirror);
 struct bio *btrfs_create_repair_bio(struct inode *inode, struct bio *failed_bio,
                                    struct io_failure_record *failrec,
                                    struct page *page, int pg_offset, int icsum,
index 06dea7c..95c2120 100644 (file)
@@ -8016,10 +8016,6 @@ static int dio_read_error(struct inode *inode, struct bio *failed_bio,
        isector >>= inode->i_sb->s_blocksize_bits;
        bio = btrfs_create_repair_bio(inode, failed_bio, failrec, page,
                                pgoff, isector, repair_endio, repair_arg);
-       if (!bio) {
-               free_io_failure(failure_tree, io_tree, failrec);
-               return -EIO;
-       }
        bio_set_op_attrs(bio, REQ_OP_READ, read_mode);
 
        btrfs_debug(BTRFS_I(inode)->root->fs_info,
@@ -8059,6 +8055,7 @@ static void btrfs_retry_endio_nocsum(struct bio *bio)
        ASSERT(bio->bi_io_vec->bv_len == btrfs_inode_sectorsize(inode));
 
        done->uptodate = 1;
+       ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, i)
                clean_io_failure(BTRFS_I(inode)->root->fs_info, failure_tree,
                                 io_tree, done->start, bvec->bv_page,
@@ -8150,6 +8147,7 @@ static void btrfs_retry_endio(struct bio *bio)
        io_tree = &BTRFS_I(inode)->io_tree;
        failure_tree = &BTRFS_I(inode)->io_failure_tree;
 
+       ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, i) {
                ret = __readpage_endio_check(inode, io_bio, i, bvec->bv_page,
                                             bvec->bv_offset, done->start,
index 6f845d2..2086383 100644 (file)
@@ -1136,20 +1136,27 @@ static void validate_rbio_for_rmw(struct btrfs_raid_bio *rbio)
 static void index_rbio_pages(struct btrfs_raid_bio *rbio)
 {
        struct bio *bio;
-       struct bio_vec *bvec;
        u64 start;
        unsigned long stripe_offset;
        unsigned long page_index;
-       int i;
 
        spin_lock_irq(&rbio->bio_list_lock);
        bio_list_for_each(bio, &rbio->bio_list) {
+               struct bio_vec bvec;
+               struct bvec_iter iter;
+               int i = 0;
+
                start = (u64)bio->bi_iter.bi_sector << 9;
                stripe_offset = start - rbio->bbio->raid_map[0];
                page_index = stripe_offset >> PAGE_SHIFT;
 
-               bio_for_each_segment_all(bvec, bio, i)
-                       rbio->bio_pages[page_index + i] = bvec->bv_page;
+               if (bio_flagged(bio, BIO_CLONED))
+                       bio->bi_iter = btrfs_io_bio(bio)->iter;
+
+               bio_for_each_segment(bvec, bio, iter) {
+                       rbio->bio_pages[page_index + i] = bvec.bv_page;
+                       i++;
+               }
        }
        spin_unlock_irq(&rbio->bio_list_lock);
 }
@@ -1423,11 +1430,14 @@ static int fail_bio_stripe(struct btrfs_raid_bio *rbio,
  */
 static void set_bio_pages_uptodate(struct bio *bio)
 {
-       struct bio_vec *bvec;
-       int i;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
+
+       if (bio_flagged(bio, BIO_CLONED))
+               bio->bi_iter = btrfs_io_bio(bio)->iter;
 
-       bio_for_each_segment_all(bvec, bio, i)
-               SetPageUptodate(bvec->bv_page);
+       bio_for_each_segment(bvec, bio, iter)
+               SetPageUptodate(bvec.bv_page);
 }
 
 /*
index e937c10..b082210 100644 (file)
@@ -1856,7 +1856,7 @@ out:
  */
 static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
                              const char *name, int name_len,
-                             u64 *who_ino, u64 *who_gen)
+                             u64 *who_ino, u64 *who_gen, u64 *who_mode)
 {
        int ret = 0;
        u64 gen;
@@ -1905,7 +1905,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
        if (other_inode > sctx->send_progress ||
            is_waiting_for_move(sctx, other_inode)) {
                ret = get_inode_info(sctx->parent_root, other_inode, NULL,
-                               who_gen, NULL, NULL, NULL, NULL);
+                               who_gen, who_mode, NULL, NULL, NULL);
                if (ret < 0)
                        goto out;
 
@@ -3683,6 +3683,36 @@ out:
        return ret;
 }
 
+static int update_ref_path(struct send_ctx *sctx, struct recorded_ref *ref)
+{
+       int ret;
+       struct fs_path *new_path;
+
+       /*
+        * Our reference's name member points to its full_path member string, so
+        * we use here a new path.
+        */
+       new_path = fs_path_alloc();
+       if (!new_path)
+               return -ENOMEM;
+
+       ret = get_cur_path(sctx, ref->dir, ref->dir_gen, new_path);
+       if (ret < 0) {
+               fs_path_free(new_path);
+               return ret;
+       }
+       ret = fs_path_add(new_path, ref->name, ref->name_len);
+       if (ret < 0) {
+               fs_path_free(new_path);
+               return ret;
+       }
+
+       fs_path_free(ref->full_path);
+       set_ref_path(ref, new_path);
+
+       return 0;
+}
+
 /*
  * This does all the move/link/unlink/rmdir magic.
  */
@@ -3696,10 +3726,12 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
        struct fs_path *valid_path = NULL;
        u64 ow_inode = 0;
        u64 ow_gen;
+       u64 ow_mode;
        int did_overwrite = 0;
        int is_orphan = 0;
        u64 last_dir_ino_rm = 0;
        bool can_rename = true;
+       bool orphanized_dir = false;
        bool orphanized_ancestor = false;
 
        btrfs_debug(fs_info, "process_recorded_refs %llu", sctx->cur_ino);
@@ -3798,7 +3830,7 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
                 */
                ret = will_overwrite_ref(sctx, cur->dir, cur->dir_gen,
                                cur->name, cur->name_len,
-                               &ow_inode, &ow_gen);
+                               &ow_inode, &ow_gen, &ow_mode);
                if (ret < 0)
                        goto out;
                if (ret) {
@@ -3815,6 +3847,8 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
                                                cur->full_path);
                                if (ret < 0)
                                        goto out;
+                               if (S_ISDIR(ow_mode))
+                                       orphanized_dir = true;
 
                                /*
                                 * If ow_inode has its rename operation delayed
@@ -3920,6 +3954,18 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
                                if (ret < 0)
                                        goto out;
                        } else {
+                               /*
+                                * We might have previously orphanized an inode
+                                * which is an ancestor of our current inode,
+                                * so our reference's full path, which was
+                                * computed before any such orphanizations, must
+                                * be updated.
+                                */
+                               if (orphanized_dir) {
+                                       ret = update_ref_path(sctx, cur);
+                                       if (ret < 0)
+                                               goto out;
+                               }
                                ret = send_link(sctx, cur->full_path,
                                                valid_path);
                                if (ret < 0)
@@ -3990,34 +4036,9 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
                                 * ancestor inode.
                                 */
                                if (orphanized_ancestor) {
-                                       struct fs_path *new_path;
-
-                                       /*
-                                        * Our reference's name member points to
-                                        * its full_path member string, so we
-                                        * use here a new path.
-                                        */
-                                       new_path = fs_path_alloc();
-                                       if (!new_path) {
-                                               ret = -ENOMEM;
-                                               goto out;
-                                       }
-                                       ret = get_cur_path(sctx, cur->dir,
-                                                          cur->dir_gen,
-                                                          new_path);
-                                       if (ret < 0) {
-                                               fs_path_free(new_path);
-                                               goto out;
-                                       }
-                                       ret = fs_path_add(new_path,
-                                                         cur->name,
-                                                         cur->name_len);
-                                       if (ret < 0) {
-                                               fs_path_free(new_path);
+                                       ret = update_ref_path(sctx, cur);
+                                       if (ret < 0)
                                                goto out;
-                                       }
-                                       fs_path_free(cur->full_path);
-                                       set_ref_path(cur, new_path);
                                }
                                ret = send_unlink(sctx, cur->full_path);
                                if (ret < 0)
@@ -5249,15 +5270,12 @@ static int is_extent_unchanged(struct send_ctx *sctx,
                        goto out;
                }
 
-               right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
                if (right_type == BTRFS_FILE_EXTENT_INLINE) {
                        right_len = btrfs_file_extent_inline_len(eb, slot, ei);
                        right_len = PAGE_ALIGN(right_len);
                } else {
                        right_len = btrfs_file_extent_num_bytes(eb, ei);
                }
-               right_offset = btrfs_file_extent_offset(eb, ei);
-               right_gen = btrfs_file_extent_generation(eb, ei);
 
                /*
                 * Are we at extent 8? If yes, we know the extent is changed.
@@ -5282,6 +5300,10 @@ static int is_extent_unchanged(struct send_ctx *sctx,
                        goto out;
                }
 
+               right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
+               right_offset = btrfs_file_extent_offset(eb, ei);
+               right_gen = btrfs_file_extent_generation(eb, ei);
+
                left_offset_fixed = left_offset;
                if (key.offset < ekey->offset) {
                        /* Fix the right offset for 2a and 7. */
index 74e4779..12540b6 100644 (file)
@@ -1154,7 +1154,6 @@ static int btrfs_fill_super(struct super_block *sb,
                goto fail_close;
        }
 
-       save_mount_options(sb, data);
        cleancache_init_fs(sb);
        sb->s_flags |= MS_ACTIVE;
        return 0;
index f20ef21..3a11ae6 100644 (file)
@@ -2153,8 +2153,7 @@ process_leaf:
                        u32 this_len = sizeof(*di) + name_len + data_len;
                        char *name;
 
-                       ret = verify_dir_item(fs_info, path->nodes[0],
-                                             path->slots[0], di);
+                       ret = verify_dir_item(fs_info, path->nodes[0], i, di);
                        if (ret) {
                                ret = -EIO;
                                goto out;
index 5eb7217..e8b9a26 100644 (file)
@@ -2702,7 +2702,7 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
 
        mutex_lock(&fs_info->chunk_mutex);
        old_total = btrfs_super_total_bytes(super_copy);
-       diff = new_size - device->total_bytes;
+       diff = round_down(new_size - device->total_bytes, fs_info->sectorsize);
 
        if (new_size <= device->total_bytes ||
            device->is_tgtdev_for_dev_replace) {
@@ -4406,7 +4406,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
        u64 diff;
 
        new_size = round_down(new_size, fs_info->sectorsize);
-       diff = old_size - new_size;
+       diff = round_down(old_size - new_size, fs_info->sectorsize);
 
        if (device->is_tgtdev_for_dev_replace)
                return -EINVAL;
index e071d23..ef7240a 100644 (file)
@@ -271,6 +271,11 @@ out:
                if (ret < 0)
                        err = ret;
                dput(last);
+               /* last_name no longer match cache index */
+               if (fi->readdir_cache_idx >= 0) {
+                       fi->readdir_cache_idx = -1;
+                       fi->dir_release_count = 0;
+               }
        }
        return err;
 }
index 556f480..180b335 100644 (file)
@@ -1354,7 +1354,7 @@ init_cifs(void)
        spin_lock_init(&cifs_tcp_ses_lock);
        spin_lock_init(&GlobalMid_Lock);
 
-       get_random_bytes(&cifs_lock_secret, sizeof(cifs_lock_secret));
+       cifs_lock_secret = get_random_u32();
 
        if (cifs_max_pending < 2) {
                cifs_max_pending = 2;
index 6c30be6..f901413 100644 (file)
@@ -90,6 +90,11 @@ EXPORT_SYMBOL(rename_lock);
 
 static struct kmem_cache *dentry_cache __read_mostly;
 
+const struct qstr empty_name = QSTR_INIT("", 0);
+EXPORT_SYMBOL(empty_name);
+const struct qstr slash_name = QSTR_INIT("/", 1);
+EXPORT_SYMBOL(slash_name);
+
 /*
  * This is the single most critical data structure when it comes
  * to the dcache: the hashtable for lookups. Somebody should try
@@ -1606,8 +1611,7 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
         */
        dentry->d_iname[DNAME_INLINE_LEN-1] = 0;
        if (unlikely(!name)) {
-               static const struct qstr anon = QSTR_INIT("/", 1);
-               name = &anon;
+               name = &slash_name;
                dname = dentry->d_iname;
        } else if (name->len > DNAME_INLINE_LEN-1) {
                size_t size = offsetof(struct external_name, name[1]);
index a0e4e2f..c59f015 100644 (file)
@@ -203,8 +203,6 @@ static int debug_fill_super(struct super_block *sb, void *data, int silent)
        struct debugfs_fs_info *fsi;
        int err;
 
-       save_mount_options(sb, data);
-
        fsi = kzalloc(sizeof(struct debugfs_fs_info), GFP_KERNEL);
        sb->s_fs_info = fsi;
        if (!fsi) {
index d7a7c53..5b68e42 100644 (file)
@@ -29,7 +29,6 @@ static const struct super_operations efivarfs_ops = {
        .statfs = simple_statfs,
        .drop_inode = generic_delete_inode,
        .evict_inode = efivarfs_evict_inode,
-       .show_options = generic_show_options,
 };
 
 static struct super_block *efivarfs_sb;
index a6d1948..e767e43 100644 (file)
@@ -960,10 +960,14 @@ static void ep_show_fdinfo(struct seq_file *m, struct file *f)
        mutex_lock(&ep->mtx);
        for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
                struct epitem *epi = rb_entry(rbp, struct epitem, rbn);
+               struct inode *inode = file_inode(epi->ffd.file);
 
-               seq_printf(m, "tfd: %8d events: %8x data: %16llx\n",
+               seq_printf(m, "tfd: %8d events: %8x data: %16llx "
+                          " pos:%lli ino:%lx sdev:%x\n",
                           epi->ffd.fd, epi->event.events,
-                          (long long)epi->event.data);
+                          (long long)epi->event.data,
+                          (long long)epi->ffd.file->f_pos,
+                          inode->i_ino, inode->i_sb->s_dev);
                if (seq_has_overflowed(m))
                        break;
        }
@@ -1073,6 +1077,50 @@ static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd)
        return epir;
 }
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+static struct epitem *ep_find_tfd(struct eventpoll *ep, int tfd, unsigned long toff)
+{
+       struct rb_node *rbp;
+       struct epitem *epi;
+
+       for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
+               epi = rb_entry(rbp, struct epitem, rbn);
+               if (epi->ffd.fd == tfd) {
+                       if (toff == 0)
+                               return epi;
+                       else
+                               toff--;
+               }
+               cond_resched();
+       }
+
+       return NULL;
+}
+
+struct file *get_epoll_tfile_raw_ptr(struct file *file, int tfd,
+                                    unsigned long toff)
+{
+       struct file *file_raw;
+       struct eventpoll *ep;
+       struct epitem *epi;
+
+       if (!is_file_epoll(file))
+               return ERR_PTR(-EINVAL);
+
+       ep = file->private_data;
+
+       mutex_lock(&ep->mtx);
+       epi = ep_find_tfd(ep, tfd, toff);
+       if (epi)
+               file_raw = epi->ffd.file;
+       else
+               file_raw = ERR_PTR(-ENOENT);
+       mutex_unlock(&ep->mtx);
+
+       return file_raw;
+}
+#endif /* CONFIG_CHECKPOINT_RESTORE */
+
 /*
  * This is the callback that is passed to the wait queue wakeup
  * mechanism. It is called by the stored file descriptors when they
index 79dafa7..51f0aea 100644 (file)
@@ -175,11 +175,8 @@ ext2_get_acl(struct inode *inode, int type)
        return acl;
 }
 
-/*
- * inode->i_mutex: down
- */
-int
-ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+static int
+__ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
        int name_index;
        void *value = NULL;
@@ -189,13 +186,6 @@ ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        switch(type) {
                case ACL_TYPE_ACCESS:
                        name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
-                       if (acl) {
-                               error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
-                               if (error)
-                                       return error;
-                               inode->i_ctime = current_time(inode);
-                               mark_inode_dirty(inode);
-                       }
                        break;
 
                case ACL_TYPE_DEFAULT:
@@ -222,6 +212,31 @@ ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 }
 
 /*
+ * inode->i_mutex: down
+ */
+int
+ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+       int error;
+       int update_mode = 0;
+       umode_t mode = inode->i_mode;
+
+       if (type == ACL_TYPE_ACCESS && acl) {
+               error = posix_acl_update_mode(inode, &mode, &acl);
+               if (error)
+                       return error;
+               update_mode = 1;
+       }
+       error = __ext2_set_acl(inode, acl, type);
+       if (!error && update_mode) {
+               inode->i_mode = mode;
+               inode->i_ctime = current_time(inode);
+               mark_inode_dirty(inode);
+       }
+       return error;
+}
+
+/*
  * Initialize the ACLs of a new inode. Called from ext2_new_inode.
  *
  * dir->i_mutex: down
@@ -238,12 +253,12 @@ ext2_init_acl(struct inode *inode, struct inode *dir)
                return error;
 
        if (default_acl) {
-               error = ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+               error = __ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
                posix_acl_release(default_acl);
        }
        if (acl) {
                if (!error)
-                       error = ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
+                       error = __ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
                posix_acl_release(acl);
        }
        return error;
index 2dcbd56..30163d0 100644 (file)
@@ -659,6 +659,7 @@ static int ext2_get_blocks(struct inode *inode,
                                 */
                                err = -EAGAIN;
                                count = 0;
+                               partial = chain + depth - 1;
                                break;
                        }
                        blk = le32_to_cpu(*(chain[depth-1].p + count));
index a140c5e..b4b8438 100644 (file)
@@ -211,7 +211,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
        switch (type) {
        case ACL_TYPE_ACCESS:
                name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
-               if (acl) {
+               if (acl && !ipage) {
                        error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
                        if (error)
                                return error;
index 56bbf59..5b876f6 100644 (file)
@@ -879,6 +879,7 @@ int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
        struct inode *inode;
        struct f2fs_inode_info *fi;
        bool is_dir = (type == DIR_INODE);
+       unsigned long ino = 0;
 
        trace_f2fs_sync_dirty_inodes_enter(sbi->sb, is_dir,
                                get_pages(sbi, is_dir ?
@@ -901,8 +902,17 @@ retry:
        inode = igrab(&fi->vfs_inode);
        spin_unlock(&sbi->inode_lock[type]);
        if (inode) {
+               unsigned long cur_ino = inode->i_ino;
+
                filemap_fdatawrite(inode->i_mapping);
                iput(inode);
+               /* We need to give cpu to another writers. */
+               if (ino == cur_ino) {
+                       congestion_wait(BLK_RW_ASYNC, HZ/50);
+                       cond_resched();
+               } else {
+                       ino = cur_ino;
+               }
        } else {
                /*
                 * We should submit bio, since it exists several
index a0e6d2c..2706130 100644 (file)
@@ -1538,7 +1538,6 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)
 
        /* Is it quota file? Do not allow user to mess with it */
        if (IS_NOQUOTA(inode)) {
-               inode_unlock(inode);
                ret = -EPERM;
                goto unlock_out;
        }
@@ -1549,9 +1548,8 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)
 
        if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
                if (!capable(CAP_LINUX_IMMUTABLE)) {
-                       inode_unlock(inode);
                        ret = -EPERM;
-                       goto out;
+                       goto unlock_out;
                }
        }
 
@@ -1564,7 +1562,6 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)
        f2fs_mark_inode_dirty_sync(inode, false);
 unlock_out:
        inode_unlock(inode);
-out:
        mnt_drop_write_file(filp);
        return ret;
 }
index 9adc202..71191d8 100644 (file)
@@ -11,6 +11,7 @@
  */
 #include <linux/proc_fs.h>
 #include <linux/f2fs_fs.h>
+#include <linux/seq_file.h>
 
 #include "f2fs.h"
 #include "segment.h"
index 8b99955..a920ad2 100644 (file)
@@ -33,9 +33,10 @@ static struct file_system_type *file_systems;
 static DEFINE_RWLOCK(file_systems_lock);
 
 /* WARNING: This can be used only if we _already_ own a reference */
-void get_filesystem(struct file_system_type *fs)
+struct file_system_type *get_filesystem(struct file_system_type *fs)
 {
        __module_get(fs->owner);
+       return fs;
 }
 
 void put_filesystem(struct file_system_type *fs)
index 8b426f8..245c430 100644 (file)
@@ -380,8 +380,8 @@ static void inode_switch_wbs_work_fn(struct work_struct *work)
                struct page *page = radix_tree_deref_slot_protected(slot,
                                                        &mapping->tree_lock);
                if (likely(page) && PageDirty(page)) {
-                       __dec_wb_stat(old_wb, WB_RECLAIMABLE);
-                       __inc_wb_stat(new_wb, WB_RECLAIMABLE);
+                       dec_wb_stat(old_wb, WB_RECLAIMABLE);
+                       inc_wb_stat(new_wb, WB_RECLAIMABLE);
                }
        }
 
@@ -391,8 +391,8 @@ static void inode_switch_wbs_work_fn(struct work_struct *work)
                                                        &mapping->tree_lock);
                if (likely(page)) {
                        WARN_ON_ONCE(!PageWriteback(page));
-                       __dec_wb_stat(old_wb, WB_WRITEBACK);
-                       __inc_wb_stat(new_wb, WB_WRITEBACK);
+                       dec_wb_stat(old_wb, WB_WRITEBACK);
+                       inc_wb_stat(new_wb, WB_WRITEBACK);
                }
        }
 
index db42765..5ee2e2f 100644 (file)
@@ -872,7 +872,6 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
        struct buffer_head *bh;
        struct gfs2_leaf *leaf;
        struct gfs2_dirent *dent;
-       struct qstr name = { .name = "" };
        struct timespec tv = current_time(inode);
 
        error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL);
@@ -896,7 +895,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
        leaf->lf_sec = cpu_to_be64(tv.tv_sec);
        memset(leaf->lf_reserved2, 0, sizeof(leaf->lf_reserved2));
        dent = (struct gfs2_dirent *)(leaf+1);
-       gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent);
+       gfs2_qstr2dirent(&empty_name, bh->b_size - sizeof(struct gfs2_leaf), dent);
        *pbh = bh;
        return leaf;
 }
index 9b92058..6bb5d7c 100644 (file)
@@ -51,8 +51,8 @@ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
        return acl;
 }
 
-int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
-               int type)
+static int __hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
+                                  int type)
 {
        int err;
        char *xattr_name;
@@ -64,12 +64,6 @@ int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
        switch (type) {
        case ACL_TYPE_ACCESS:
                xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
-               if (acl) {
-                       err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
-                       if (err)
-                               return err;
-               }
-               err = 0;
                break;
 
        case ACL_TYPE_DEFAULT:
@@ -105,6 +99,18 @@ end_set_acl:
        return err;
 }
 
+int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+       int err;
+
+       if (type == ACL_TYPE_ACCESS && acl) {
+               err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+               if (err)
+                       return err;
+       }
+       return __hfsplus_set_posix_acl(inode, acl, type);
+}
+
 int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
 {
        int err = 0;
@@ -122,15 +128,15 @@ int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
                return err;
 
        if (default_acl) {
-               err = hfsplus_set_posix_acl(inode, default_acl,
-                                           ACL_TYPE_DEFAULT);
+               err = __hfsplus_set_posix_acl(inode, default_acl,
+                                             ACL_TYPE_DEFAULT);
                posix_acl_release(default_acl);
        }
 
        if (acl) {
                if (!err)
-                       err = hfsplus_set_posix_acl(inode, acl,
-                                                   ACL_TYPE_ACCESS);
+                       err = __hfsplus_set_posix_acl(inode, acl,
+                                                     ACL_TYPE_ACCESS);
                posix_acl_release(acl);
        }
        return err;
index 5238861..28d2753 100644 (file)
@@ -46,13 +46,13 @@ static const struct inode_operations hugetlbfs_dir_inode_operations;
 static const struct inode_operations hugetlbfs_inode_operations;
 
 struct hugetlbfs_config {
-       kuid_t   uid;
-       kgid_t   gid;
-       umode_t mode;
-       long    max_hpages;
-       long    nr_inodes;
-       struct hstate *hstate;
-       long    min_hpages;
+       struct hstate           *hstate;
+       long                    max_hpages;
+       long                    nr_inodes;
+       long                    min_hpages;
+       kuid_t                  uid;
+       kgid_t                  gid;
+       umode_t                 mode;
 };
 
 struct hugetlbfs_inode_info {
@@ -861,6 +861,46 @@ static int hugetlbfs_error_remove_page(struct address_space *mapping,
        return 0;
 }
 
+/*
+ * Display the mount options in /proc/mounts.
+ */
+static int hugetlbfs_show_options(struct seq_file *m, struct dentry *root)
+{
+       struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(root->d_sb);
+       struct hugepage_subpool *spool = sbinfo->spool;
+       unsigned long hpage_size = huge_page_size(sbinfo->hstate);
+       unsigned hpage_shift = huge_page_shift(sbinfo->hstate);
+       char mod;
+
+       if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID))
+               seq_printf(m, ",uid=%u",
+                          from_kuid_munged(&init_user_ns, sbinfo->uid));
+       if (!gid_eq(sbinfo->gid, GLOBAL_ROOT_GID))
+               seq_printf(m, ",gid=%u",
+                          from_kgid_munged(&init_user_ns, sbinfo->gid));
+       if (sbinfo->mode != 0755)
+               seq_printf(m, ",mode=%o", sbinfo->mode);
+       if (sbinfo->max_inodes != -1)
+               seq_printf(m, ",nr_inodes=%lu", sbinfo->max_inodes);
+
+       hpage_size /= 1024;
+       mod = 'K';
+       if (hpage_size >= 1024) {
+               hpage_size /= 1024;
+               mod = 'M';
+       }
+       seq_printf(m, ",pagesize=%lu%c", hpage_size, mod);
+       if (spool) {
+               if (spool->max_hpages != -1)
+                       seq_printf(m, ",size=%llu",
+                                  (unsigned long long)spool->max_hpages << hpage_shift);
+               if (spool->min_hpages != -1)
+                       seq_printf(m, ",min_size=%llu",
+                                  (unsigned long long)spool->min_hpages << hpage_shift);
+       }
+       return 0;
+}
+
 static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb);
@@ -1019,19 +1059,19 @@ static const struct super_operations hugetlbfs_ops = {
        .evict_inode    = hugetlbfs_evict_inode,
        .statfs         = hugetlbfs_statfs,
        .put_super      = hugetlbfs_put_super,
-       .show_options   = generic_show_options,
+       .show_options   = hugetlbfs_show_options,
 };
 
-enum { NO_SIZE, SIZE_STD, SIZE_PERCENT };
+enum hugetlbfs_size_type { NO_SIZE, SIZE_STD, SIZE_PERCENT };
 
 /*
  * Convert size option passed from command line to number of huge pages
  * in the pool specified by hstate.  Size option could be in bytes
  * (val_type == SIZE_STD) or percentage of the pool (val_type == SIZE_PERCENT).
  */
-static long long
+static long
 hugetlbfs_size_to_hpages(struct hstate *h, unsigned long long size_opt,
-                                                               int val_type)
+                        enum hugetlbfs_size_type val_type)
 {
        if (val_type == NO_SIZE)
                return -1;
@@ -1053,7 +1093,7 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig)
        substring_t args[MAX_OPT_ARGS];
        int option;
        unsigned long long max_size_opt = 0, min_size_opt = 0;
-       int max_val_type = NO_SIZE, min_val_type = NO_SIZE;
+       enum hugetlbfs_size_type max_val_type = NO_SIZE, min_val_type = NO_SIZE;
 
        if (!options)
                return 0;
@@ -1167,8 +1207,6 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)
        struct hugetlbfs_config config;
        struct hugetlbfs_sb_info *sbinfo;
 
-       save_mount_options(sb, data);
-
        config.max_hpages = -1; /* No limit on size by default */
        config.nr_inodes = -1; /* No limit on number of inodes by default */
        config.uid = current_fsuid();
@@ -1189,6 +1227,10 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)
        sbinfo->max_inodes = config.nr_inodes;
        sbinfo->free_inodes = config.nr_inodes;
        sbinfo->spool = NULL;
+       sbinfo->uid = config.uid;
+       sbinfo->gid = config.gid;
+       sbinfo->mode = config.mode;
+
        /*
         * Allocate and initialize subpool if maximum or minimum size is
         * specified.  Any needed reservations (for minimim size) are taken
index 1732228..0392661 100644 (file)
@@ -610,8 +610,8 @@ iomap_seek_hole(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
        loff_t length = size - offset;
        loff_t ret;
 
-       /* Nothing to be found beyond the end of the file. */
-       if (offset >= size)
+       /* Nothing to be found before or beyond the end of the file. */
+       if (offset < 0 || offset >= size)
                return -ENXIO;
 
        while (length > 0) {
@@ -656,8 +656,8 @@ iomap_seek_data(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
        loff_t length = size - offset;
        loff_t ret;
 
-       /* Nothing to be found beyond the end of the file. */
-       if (offset >= size)
+       /* Nothing to be found before or beyond the end of the file. */
+       if (offset < 0 || offset >= size)
                return -ENXIO;
 
        while (length > 0) {
index 020ba09..217a5e7 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/parser.h>
 #include <linux/mpage.h>
 #include <linux/user_namespace.h>
+#include <linux/seq_file.h>
 
 #include "isofs.h"
 #include "zisofs.h"
@@ -57,6 +58,7 @@ static void isofs_put_super(struct super_block *sb)
 
 static int isofs_read_inode(struct inode *, int relocated);
 static int isofs_statfs (struct dentry *, struct kstatfs *);
+static int isofs_show_options(struct seq_file *, struct dentry *);
 
 static struct kmem_cache *isofs_inode_cachep;
 
@@ -123,7 +125,7 @@ static const struct super_operations isofs_sops = {
        .put_super      = isofs_put_super,
        .statfs         = isofs_statfs,
        .remount_fs     = isofs_remount,
-       .show_options   = generic_show_options,
+       .show_options   = isofs_show_options,
 };
 
 
@@ -408,7 +410,11 @@ static int parse_options(char *options, struct iso9660_options *popt)
                        if (match_int(&args[0], &option))
                                return 0;
                        n = option;
-                       if (n > 99)
+                       /*
+                        * Track numbers are supposed to be in range 1-99, the
+                        * mount option starts indexing at 0.
+                        */
+                       if (n >= 99)
                                return 0;
                        popt->session = n + 1;
                        break;
@@ -473,6 +479,48 @@ static int parse_options(char *options, struct iso9660_options *popt)
 }
 
 /*
+ * Display the mount options in /proc/mounts.
+ */
+static int isofs_show_options(struct seq_file *m, struct dentry *root)
+{
+       struct isofs_sb_info *sbi = ISOFS_SB(root->d_sb);
+
+       if (!sbi->s_rock)               seq_puts(m, ",norock");
+       else if (!sbi->s_joliet_level)  seq_puts(m, ",nojoliet");
+       if (sbi->s_cruft)               seq_puts(m, ",cruft");
+       if (sbi->s_hide)                seq_puts(m, ",hide");
+       if (sbi->s_nocompress)          seq_puts(m, ",nocompress");
+       if (sbi->s_overriderockperm)    seq_puts(m, ",overriderockperm");
+       if (sbi->s_showassoc)           seq_puts(m, ",showassoc");
+       if (sbi->s_utf8)                seq_puts(m, ",utf8");
+
+       if (sbi->s_check)               seq_printf(m, ",check=%c", sbi->s_check);
+       if (sbi->s_mapping)             seq_printf(m, ",map=%c", sbi->s_mapping);
+       if (sbi->s_session != 255)      seq_printf(m, ",session=%u", sbi->s_session - 1);
+       if (sbi->s_sbsector != -1)      seq_printf(m, ",sbsector=%u", sbi->s_sbsector);
+
+       if (root->d_sb->s_blocksize != 1024)
+               seq_printf(m, ",blocksize=%lu", root->d_sb->s_blocksize);
+
+       if (sbi->s_uid_set)
+               seq_printf(m, ",uid=%u",
+                          from_kuid_munged(&init_user_ns, sbi->s_uid));
+       if (sbi->s_gid_set)
+               seq_printf(m, ",gid=%u",
+                          from_kgid_munged(&init_user_ns, sbi->s_gid));
+
+       if (sbi->s_dmode != ISOFS_INVALID_MODE)
+               seq_printf(m, ",dmode=%o", sbi->s_dmode);
+       if (sbi->s_fmode != ISOFS_INVALID_MODE)
+               seq_printf(m, ",fmode=%o", sbi->s_fmode);
+
+       if (sbi->s_nls_iocharset &&
+           strcmp(sbi->s_nls_iocharset->charset, CONFIG_NLS_DEFAULT) != 0)
+               seq_printf(m, ",iocharset=%s", sbi->s_nls_iocharset->charset);
+       return 0;
+}
+
+/*
  * look if the driver can tell the multi session redirection value
  *
  * don't change this if you don't know what you do, please!
@@ -499,7 +547,7 @@ static unsigned int isofs_get_last_session(struct super_block *sb, s32 session)
 
        vol_desc_start=0;
        ms_info.addr_format=CDROM_LBA;
-       if(session >= 0 && session <= 99) {
+       if (session > 0) {
                struct cdrom_tocentry Te;
                Te.cdte_track=session;
                Te.cdte_format=CDROM_LBA;
@@ -583,8 +631,6 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
        int table, error = -EINVAL;
        unsigned int vol_desc_start;
 
-       save_mount_options(s, data);
-
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
                return -ENOMEM;
@@ -605,6 +651,8 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
        opt.blocksize = sb_min_blocksize(s, opt.blocksize);
 
        sbi->s_high_sierra = 0; /* default is iso9660 */
+       sbi->s_session = opt.session;
+       sbi->s_sbsector = opt.sbsector;
 
        vol_desc_start = (opt.sbsector != -1) ?
                opt.sbsector : isofs_get_last_session(s,opt.session);
@@ -911,6 +959,7 @@ root_found:
                table += 2;
        if (opt.check == 'r')
                table++;
+       sbi->s_check = opt.check;
 
        if (table)
                s->s_d_op = &isofs_dentry_ops[table - 1];
index 0ac4c1f..133a456 100644 (file)
@@ -36,8 +36,11 @@ struct isofs_sb_info {
        unsigned long s_max_size;
        
        int           s_rock_offset; /* offset of SUSP fields within SU area */
+       s32           s_sbsector;
        unsigned char s_joliet_level;
        unsigned char s_mapping;
+       unsigned char s_check;
+       unsigned char s_session;
        unsigned int  s_high_sierra:1;
        unsigned int  s_rock:2;
        unsigned int  s_utf8:1;
index 7bc186f..2e71b6e 100644 (file)
@@ -77,13 +77,6 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
        switch (type) {
        case ACL_TYPE_ACCESS:
                ea_name = XATTR_NAME_POSIX_ACL_ACCESS;
-               if (acl) {
-                       rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
-                       if (rc)
-                               return rc;
-                       inode->i_ctime = current_time(inode);
-                       mark_inode_dirty(inode);
-               }
                break;
        case ACL_TYPE_DEFAULT:
                ea_name = XATTR_NAME_POSIX_ACL_DEFAULT;
@@ -115,12 +108,27 @@ int jfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
        int rc;
        tid_t tid;
+       int update_mode = 0;
+       umode_t mode = inode->i_mode;
 
        tid = txBegin(inode->i_sb, 0);
        mutex_lock(&JFS_IP(inode)->commit_mutex);
+       if (type == ACL_TYPE_ACCESS && acl) {
+               rc = posix_acl_update_mode(inode, &mode, &acl);
+               if (rc)
+                       goto end_tx;
+               update_mode = 1;
+       }
        rc = __jfs_set_acl(tid, inode, type, acl);
-       if (!rc)
+       if (!rc) {
+               if (update_mode) {
+                       inode->i_mode = mode;
+                       inode->i_ctime = current_time(inode);
+                       mark_inode_dirty(inode);
+               }
                rc = txCommit(tid, 1, &inode, 0);
+       }
+end_tx:
        txEnd(tid);
        mutex_unlock(&JFS_IP(inode)->commit_mutex);
        return rc;
index bd9b641..7ddcb44 100644 (file)
@@ -98,7 +98,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
                goto out;
        }
 
-       VolumeSize = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits;
+       VolumeSize = i_size_read(sb->s_bdev->bd_inode) >> sb->s_blocksize_bits;
 
        if (VolumeSize) {
                if (newLVSize > VolumeSize) {
@@ -211,7 +211,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
        txQuiesce(sb);
 
        /* Reset size of direct inode */
-       sbi->direct_inode->i_size =  sb->s_bdev->bd_inode->i_size;
+       sbi->direct_inode->i_size =  i_size_read(sb->s_bdev->bd_inode);
 
        if (sbi->mntflag & JFS_INLINELOG) {
                /*
index e8aad7d..78b41e1 100644 (file)
@@ -313,7 +313,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
                }
                case Opt_resize_nosize:
                {
-                       *newLVSize = sb->s_bdev->bd_inode->i_size >>
+                       *newLVSize = i_size_read(sb->s_bdev->bd_inode) >>
                                sb->s_blocksize_bits;
                        if (*newLVSize == 0)
                                pr_err("JFS: Cannot determine volume size\n");
@@ -579,7 +579,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
                goto out_unload;
        }
        inode->i_ino = 0;
-       inode->i_size = sb->s_bdev->bd_inode->i_size;
+       inode->i_size = i_size_read(sb->s_bdev->bd_inode);
        inode->i_mapping->a_ops = &jfs_metapage_aops;
        hlist_add_fake(&inode->i_hash);
        mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
index d3e40db..c349fc0 100644 (file)
@@ -381,8 +381,9 @@ static void encode_nlm4_lock(struct xdr_stream *xdr,
  */
 static void nlm4_xdr_enc_testargs(struct rpc_rqst *req,
                                  struct xdr_stream *xdr,
-                                 const struct nlm_args *args)
+                                 const void *data)
 {
+       const struct nlm_args *args = data;
        const struct nlm_lock *lock = &args->lock;
 
        encode_cookie(xdr, &args->cookie);
@@ -402,8 +403,9 @@ static void nlm4_xdr_enc_testargs(struct rpc_rqst *req,
  */
 static void nlm4_xdr_enc_lockargs(struct rpc_rqst *req,
                                  struct xdr_stream *xdr,
-                                 const struct nlm_args *args)
+                                 const void *data)
 {
+       const struct nlm_args *args = data;
        const struct nlm_lock *lock = &args->lock;
 
        encode_cookie(xdr, &args->cookie);
@@ -424,8 +426,9 @@ static void nlm4_xdr_enc_lockargs(struct rpc_rqst *req,
  */
 static void nlm4_xdr_enc_cancargs(struct rpc_rqst *req,
                                  struct xdr_stream *xdr,
-                                 const struct nlm_args *args)
+                                 const void *data)
 {
+       const struct nlm_args *args = data;
        const struct nlm_lock *lock = &args->lock;
 
        encode_cookie(xdr, &args->cookie);
@@ -442,8 +445,9 @@ static void nlm4_xdr_enc_cancargs(struct rpc_rqst *req,
  */
 static void nlm4_xdr_enc_unlockargs(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   const struct nlm_args *args)
+                                   const void *data)
 {
+       const struct nlm_args *args = data;
        const struct nlm_lock *lock = &args->lock;
 
        encode_cookie(xdr, &args->cookie);
@@ -458,8 +462,10 @@ static void nlm4_xdr_enc_unlockargs(struct rpc_rqst *req,
  */
 static void nlm4_xdr_enc_res(struct rpc_rqst *req,
                             struct xdr_stream *xdr,
-                            const struct nlm_res *result)
+                            const void *data)
 {
+       const struct nlm_res *result = data;
+
        encode_cookie(xdr, &result->cookie);
        encode_nlm4_stat(xdr, result->status);
 }
@@ -479,8 +485,10 @@ static void nlm4_xdr_enc_res(struct rpc_rqst *req,
  */
 static void nlm4_xdr_enc_testres(struct rpc_rqst *req,
                                 struct xdr_stream *xdr,
-                                const struct nlm_res *result)
+                                const void *data)
 {
+       const struct nlm_res *result = data;
+
        encode_cookie(xdr, &result->cookie);
        encode_nlm4_stat(xdr, result->status);
        if (result->status == nlm_lck_denied)
@@ -525,8 +533,9 @@ out:
 
 static int nlm4_xdr_dec_testres(struct rpc_rqst *req,
                                struct xdr_stream *xdr,
-                               struct nlm_res *result)
+                               void *data)
 {
+       struct nlm_res *result = data;
        int error;
 
        error = decode_cookie(xdr, &result->cookie);
@@ -545,8 +554,9 @@ out:
  */
 static int nlm4_xdr_dec_res(struct rpc_rqst *req,
                            struct xdr_stream *xdr,
-                           struct nlm_res *result)
+                           void *data)
 {
+       struct nlm_res *result = data;
        int error;
 
        error = decode_cookie(xdr, &result->cookie);
@@ -566,15 +576,15 @@ out:
 #define PROC(proc, argtype, restype)                                   \
 [NLMPROC_##proc] = {                                                   \
        .p_proc      = NLMPROC_##proc,                                  \
-       .p_encode    = (kxdreproc_t)nlm4_xdr_enc_##argtype,             \
-       .p_decode    = (kxdrdproc_t)nlm4_xdr_dec_##restype,             \
+       .p_encode    = nlm4_xdr_enc_##argtype,                          \
+       .p_decode    = nlm4_xdr_dec_##restype,                          \
        .p_arglen    = NLM4_##argtype##_sz,                             \
        .p_replen    = NLM4_##restype##_sz,                             \
        .p_statidx   = NLMPROC_##proc,                                  \
        .p_name      = #proc,                                           \
        }
 
-static struct rpc_procinfo     nlm4_procedures[] = {
+static const struct rpc_procinfo nlm4_procedures[] = {
        PROC(TEST,              testargs,       testres),
        PROC(LOCK,              lockargs,       res),
        PROC(CANCEL,            cancargs,       res),
@@ -592,8 +602,10 @@ static struct rpc_procinfo nlm4_procedures[] = {
        PROC(GRANTED_RES,       res,            norep),
 };
 
+static unsigned int nlm_version4_counts[ARRAY_SIZE(nlm4_procedures)];
 const struct rpc_version nlm_version4 = {
        .number         = 4,
        .nrprocs        = ARRAY_SIZE(nlm4_procedures),
        .procs          = nlm4_procedures,
+       .counts         = nlm_version4_counts,
 };
index 3e9f787..3b4724a 100644 (file)
@@ -374,8 +374,9 @@ static void encode_nlm_lock(struct xdr_stream *xdr,
  */
 static void nlm_xdr_enc_testargs(struct rpc_rqst *req,
                                 struct xdr_stream *xdr,
-                                const struct nlm_args *args)
+                                const void *data)
 {
+       const struct nlm_args *args = data;
        const struct nlm_lock *lock = &args->lock;
 
        encode_cookie(xdr, &args->cookie);
@@ -395,8 +396,9 @@ static void nlm_xdr_enc_testargs(struct rpc_rqst *req,
  */
 static void nlm_xdr_enc_lockargs(struct rpc_rqst *req,
                                 struct xdr_stream *xdr,
-                                const struct nlm_args *args)
+                                const void *data)
 {
+       const struct nlm_args *args = data;
        const struct nlm_lock *lock = &args->lock;
 
        encode_cookie(xdr, &args->cookie);
@@ -417,8 +419,9 @@ static void nlm_xdr_enc_lockargs(struct rpc_rqst *req,
  */
 static void nlm_xdr_enc_cancargs(struct rpc_rqst *req,
                                 struct xdr_stream *xdr,
-                                const struct nlm_args *args)
+                                const void *data)
 {
+       const struct nlm_args *args = data;
        const struct nlm_lock *lock = &args->lock;
 
        encode_cookie(xdr, &args->cookie);
@@ -435,8 +438,9 @@ static void nlm_xdr_enc_cancargs(struct rpc_rqst *req,
  */
 static void nlm_xdr_enc_unlockargs(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  const struct nlm_args *args)
+                                  const void *data)
 {
+       const struct nlm_args *args = data;
        const struct nlm_lock *lock = &args->lock;
 
        encode_cookie(xdr, &args->cookie);
@@ -451,8 +455,10 @@ static void nlm_xdr_enc_unlockargs(struct rpc_rqst *req,
  */
 static void nlm_xdr_enc_res(struct rpc_rqst *req,
                            struct xdr_stream *xdr,
-                           const struct nlm_res *result)
+                           const void *data)
 {
+       const struct nlm_res *result = data;
+
        encode_cookie(xdr, &result->cookie);
        encode_nlm_stat(xdr, result->status);
 }
@@ -479,8 +485,10 @@ static void encode_nlm_testrply(struct xdr_stream *xdr,
 
 static void nlm_xdr_enc_testres(struct rpc_rqst *req,
                                struct xdr_stream *xdr,
-                               const struct nlm_res *result)
+                               const void *data)
 {
+       const struct nlm_res *result = data;
+
        encode_cookie(xdr, &result->cookie);
        encode_nlm_stat(xdr, result->status);
        encode_nlm_testrply(xdr, result);
@@ -523,8 +531,9 @@ out:
 
 static int nlm_xdr_dec_testres(struct rpc_rqst *req,
                               struct xdr_stream *xdr,
-                              struct nlm_res *result)
+                              void *data)
 {
+       struct nlm_res *result = data;
        int error;
 
        error = decode_cookie(xdr, &result->cookie);
@@ -543,8 +552,9 @@ out:
  */
 static int nlm_xdr_dec_res(struct rpc_rqst *req,
                           struct xdr_stream *xdr,
-                          struct nlm_res *result)
+                          void *data)
 {
+       struct nlm_res *result = data;
        int error;
 
        error = decode_cookie(xdr, &result->cookie);
@@ -564,15 +574,15 @@ out:
 #define PROC(proc, argtype, restype)   \
 [NLMPROC_##proc] = {                                                   \
        .p_proc      = NLMPROC_##proc,                                  \
-       .p_encode    = (kxdreproc_t)nlm_xdr_enc_##argtype,              \
-       .p_decode    = (kxdrdproc_t)nlm_xdr_dec_##restype,              \
+       .p_encode    = nlm_xdr_enc_##argtype,           \
+       .p_decode    = nlm_xdr_dec_##restype,                           \
        .p_arglen    = NLM_##argtype##_sz,                              \
        .p_replen    = NLM_##restype##_sz,                              \
        .p_statidx   = NLMPROC_##proc,                                  \
        .p_name      = #proc,                                           \
        }
 
-static struct rpc_procinfo     nlm_procedures[] = {
+static const struct rpc_procinfo nlm_procedures[] = {
        PROC(TEST,              testargs,       testres),
        PROC(LOCK,              lockargs,       res),
        PROC(CANCEL,            cancargs,       res),
@@ -590,16 +600,20 @@ static struct rpc_procinfo        nlm_procedures[] = {
        PROC(GRANTED_RES,       res,            norep),
 };
 
+static unsigned int nlm_version1_counts[ARRAY_SIZE(nlm_procedures)];
 static const struct rpc_version        nlm_version1 = {
-               .number         = 1,
-               .nrprocs        = ARRAY_SIZE(nlm_procedures),
-               .procs          = nlm_procedures,
+       .number         = 1,
+       .nrprocs        = ARRAY_SIZE(nlm_procedures),
+       .procs          = nlm_procedures,
+       .counts         = nlm_version1_counts,
 };
 
+static unsigned int nlm_version3_counts[ARRAY_SIZE(nlm_procedures)];
 static const struct rpc_version        nlm_version3 = {
-               .number         = 3,
-               .nrprocs        = ARRAY_SIZE(nlm_procedures),
-               .procs          = nlm_procedures,
+       .number         = 3,
+       .nrprocs        = ARRAY_SIZE(nlm_procedures),
+       .procs          = nlm_procedures,
+       .counts         = nlm_version3_counts,
 };
 
 static const struct rpc_version        *nlm_versions[] = {
@@ -613,9 +627,9 @@ static const struct rpc_version     *nlm_versions[] = {
 static struct rpc_stat         nlm_rpc_stats;
 
 const struct rpc_program       nlm_program = {
-               .name           = "lockd",
-               .number         = NLM_PROGRAM,
-               .nrvers         = ARRAY_SIZE(nlm_versions),
-               .version        = nlm_versions,
-               .stats          = &nlm_rpc_stats,
+       .name           = "lockd",
+       .number         = NLM_PROGRAM,
+       .nrvers         = ARRAY_SIZE(nlm_versions),
+       .version        = nlm_versions,
+       .stats          = &nlm_rpc_stats,
 };
index 19166d4..9d8166c 100644 (file)
@@ -476,22 +476,23 @@ static void encode_priv(struct xdr_stream *xdr, const struct nsm_args *argp)
 }
 
 static void nsm_xdr_enc_mon(struct rpc_rqst *req, struct xdr_stream *xdr,
-                           const struct nsm_args *argp)
+                           const void *argp)
 {
        encode_mon_id(xdr, argp);
        encode_priv(xdr, argp);
 }
 
 static void nsm_xdr_enc_unmon(struct rpc_rqst *req, struct xdr_stream *xdr,
-                             const struct nsm_args *argp)
+                             const void *argp)
 {
        encode_mon_id(xdr, argp);
 }
 
 static int nsm_xdr_dec_stat_res(struct rpc_rqst *rqstp,
                                struct xdr_stream *xdr,
-                               struct nsm_res *resp)
+                               void *data)
 {
+       struct nsm_res *resp = data;
        __be32 *p;
 
        p = xdr_inline_decode(xdr, 4 + 4);
@@ -507,8 +508,9 @@ static int nsm_xdr_dec_stat_res(struct rpc_rqst *rqstp,
 
 static int nsm_xdr_dec_stat(struct rpc_rqst *rqstp,
                            struct xdr_stream *xdr,
-                           struct nsm_res *resp)
+                           void *data)
 {
+       struct nsm_res *resp = data;
        __be32 *p;
 
        p = xdr_inline_decode(xdr, 4);
@@ -529,11 +531,11 @@ static int nsm_xdr_dec_stat(struct rpc_rqst *rqstp,
 #define SM_monres_sz   2
 #define SM_unmonres_sz 1
 
-static struct rpc_procinfo     nsm_procedures[] = {
+static const struct rpc_procinfo nsm_procedures[] = {
 [NSMPROC_MON] = {
                .p_proc         = NSMPROC_MON,
-               .p_encode       = (kxdreproc_t)nsm_xdr_enc_mon,
-               .p_decode       = (kxdrdproc_t)nsm_xdr_dec_stat_res,
+               .p_encode       = nsm_xdr_enc_mon,
+               .p_decode       = nsm_xdr_dec_stat_res,
                .p_arglen       = SM_mon_sz,
                .p_replen       = SM_monres_sz,
                .p_statidx      = NSMPROC_MON,
@@ -541,8 +543,8 @@ static struct rpc_procinfo  nsm_procedures[] = {
        },
 [NSMPROC_UNMON] = {
                .p_proc         = NSMPROC_UNMON,
-               .p_encode       = (kxdreproc_t)nsm_xdr_enc_unmon,
-               .p_decode       = (kxdrdproc_t)nsm_xdr_dec_stat,
+               .p_encode       = nsm_xdr_enc_unmon,
+               .p_decode       = nsm_xdr_dec_stat,
                .p_arglen       = SM_mon_id_sz,
                .p_replen       = SM_unmonres_sz,
                .p_statidx      = NSMPROC_UNMON,
@@ -550,10 +552,12 @@ static struct rpc_procinfo        nsm_procedures[] = {
        },
 };
 
+static unsigned int nsm_version1_counts[ARRAY_SIZE(nsm_procedures)];
 static const struct rpc_version nsm_version1 = {
-               .number         = 1,
-               .nrprocs        = ARRAY_SIZE(nsm_procedures),
-               .procs          = nsm_procedures
+       .number         = 1,
+       .nrprocs        = ARRAY_SIZE(nsm_procedures),
+       .procs          = nsm_procedures,
+       .counts         = nsm_version1_counts,
 };
 
 static const struct rpc_version *nsm_version[] = {
@@ -563,9 +567,9 @@ static const struct rpc_version *nsm_version[] = {
 static struct rpc_stat         nsm_stats;
 
 static const struct rpc_program nsm_program = {
-               .name           = "statd",
-               .number         = NSM_PROGRAM,
-               .nrvers         = ARRAY_SIZE(nsm_version),
-               .version        = nsm_version,
-               .stats          = &nsm_stats
+       .name           = "statd",
+       .number         = NSM_PROGRAM,
+       .nrvers         = ARRAY_SIZE(nsm_version),
+       .version        = nsm_version,
+       .stats          = &nsm_stats
 };
index 5d481e8..726b6ce 100644 (file)
@@ -739,27 +739,33 @@ module_exit(exit_nlm);
 /*
  * Define NLM program and procedures
  */
-static struct svc_version      nlmsvc_version1 = {
-               .vs_vers        = 1,
-               .vs_nproc       = 17,
-               .vs_proc        = nlmsvc_procedures,
-               .vs_xdrsize     = NLMSVC_XDRSIZE,
+static unsigned int nlmsvc_version1_count[17];
+static const struct svc_version        nlmsvc_version1 = {
+       .vs_vers        = 1,
+       .vs_nproc       = 17,
+       .vs_proc        = nlmsvc_procedures,
+       .vs_count       = nlmsvc_version1_count,
+       .vs_xdrsize     = NLMSVC_XDRSIZE,
 };
-static struct svc_version      nlmsvc_version3 = {
-               .vs_vers        = 3,
-               .vs_nproc       = 24,
-               .vs_proc        = nlmsvc_procedures,
-               .vs_xdrsize     = NLMSVC_XDRSIZE,
+static unsigned int nlmsvc_version3_count[24];
+static const struct svc_version        nlmsvc_version3 = {
+       .vs_vers        = 3,
+       .vs_nproc       = 24,
+       .vs_proc        = nlmsvc_procedures,
+       .vs_count       = nlmsvc_version3_count,
+       .vs_xdrsize     = NLMSVC_XDRSIZE,
 };
 #ifdef CONFIG_LOCKD_V4
-static struct svc_version      nlmsvc_version4 = {
-               .vs_vers        = 4,
-               .vs_nproc       = 24,
-               .vs_proc        = nlmsvc_procedures4,
-               .vs_xdrsize     = NLMSVC_XDRSIZE,
+static unsigned int nlmsvc_version4_count[24];
+static const struct svc_version        nlmsvc_version4 = {
+       .vs_vers        = 4,
+       .vs_nproc       = 24,
+       .vs_proc        = nlmsvc_procedures4,
+       .vs_count       = nlmsvc_version4_count,
+       .vs_xdrsize     = NLMSVC_XDRSIZE,
 };
 #endif
-static struct svc_version *    nlmsvc_version[] = {
+static const struct svc_version *nlmsvc_version[] = {
        [1] = &nlmsvc_version1,
        [3] = &nlmsvc_version3,
 #ifdef CONFIG_LOCKD_V4
index 09c576f..82925f1 100644 (file)
@@ -62,7 +62,7 @@ no_locks:
  * NULL: Test for presence of service
  */
 static __be32
-nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+nlm4svc_proc_null(struct svc_rqst *rqstp)
 {
        dprintk("lockd: NULL          called\n");
        return rpc_success;
@@ -72,9 +72,9 @@ nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
  * TEST: Check for conflicting lock
  */
 static __be32
-nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                        struct nlm_res  *resp)
+__nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
        struct nlm_file *file;
        __be32 rc = rpc_success;
@@ -99,9 +99,15 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
 }
 
 static __be32
-nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                        struct nlm_res  *resp)
+nlm4svc_proc_test(struct svc_rqst *rqstp)
 {
+       return __nlm4svc_proc_test(rqstp, rqstp->rq_resp);
+}
+
+static __be32
+__nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_res *resp)
+{
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
        struct nlm_file *file;
        __be32 rc = rpc_success;
@@ -141,9 +147,15 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 }
 
 static __be32
-nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                          struct nlm_res  *resp)
+nlm4svc_proc_lock(struct svc_rqst *rqstp)
+{
+       return __nlm4svc_proc_lock(rqstp, rqstp->rq_resp);
+}
+
+static __be32
+__nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_res *resp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
        struct nlm_file *file;
 
@@ -170,13 +182,19 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
        return rpc_success;
 }
 
+static __be32
+nlm4svc_proc_cancel(struct svc_rqst *rqstp)
+{
+       return __nlm4svc_proc_cancel(rqstp, rqstp->rq_resp);
+}
+
 /*
  * UNLOCK: release a lock
  */
 static __be32
-nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                          struct nlm_res  *resp)
+__nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_res *resp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
        struct nlm_file *file;
 
@@ -203,14 +221,21 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
        return rpc_success;
 }
 
+static __be32
+nlm4svc_proc_unlock(struct svc_rqst *rqstp)
+{
+       return __nlm4svc_proc_unlock(rqstp, rqstp->rq_resp);
+}
+
 /*
  * GRANTED: A server calls us to tell that a process' lock request
  * was granted
  */
 static __be32
-nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                           struct nlm_res  *resp)
+__nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_res *resp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
+
        resp->cookie = argp->cookie;
 
        dprintk("lockd: GRANTED       called\n");
@@ -219,6 +244,12 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
        return rpc_success;
 }
 
+static __be32
+nlm4svc_proc_granted(struct svc_rqst *rqstp)
+{
+       return __nlm4svc_proc_granted(rqstp, rqstp->rq_resp);
+}
+
 /*
  * This is the generic lockd callback for async RPC calls
  */
@@ -243,9 +274,10 @@ static const struct rpc_call_ops nlm4svc_callback_ops = {
  * because we send the callback before the reply proper. I hope this
  * doesn't break any clients.
  */
-static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
-               __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res  *))
+static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc,
+               __be32 (*func)(struct svc_rqst *,  struct nlm_res *))
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
        struct nlm_rqst *call;
        __be32 stat;
@@ -261,7 +293,7 @@ static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args
        if (call == NULL)
                return rpc_system_err;
 
-       stat = func(rqstp, argp, &call->a_res);
+       stat = func(rqstp, &call->a_res);
        if (stat != 0) {
                nlmsvc_release_call(call);
                return stat;
@@ -273,48 +305,44 @@ static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args
        return rpc_success;
 }
 
-static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                            void            *resp)
+static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp)
 {
        dprintk("lockd: TEST_MSG      called\n");
-       return nlm4svc_callback(rqstp, NLMPROC_TEST_RES, argp, nlm4svc_proc_test);
+       return nlm4svc_callback(rqstp, NLMPROC_TEST_RES, __nlm4svc_proc_test);
 }
 
-static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                            void            *resp)
+static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp)
 {
        dprintk("lockd: LOCK_MSG      called\n");
-       return nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlm4svc_proc_lock);
+       return nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, __nlm4svc_proc_lock);
 }
 
-static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                              void            *resp)
+static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp)
 {
        dprintk("lockd: CANCEL_MSG    called\n");
-       return nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlm4svc_proc_cancel);
+       return nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, __nlm4svc_proc_cancel);
 }
 
-static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                               void            *resp)
+static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp)
 {
        dprintk("lockd: UNLOCK_MSG    called\n");
-       return nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlm4svc_proc_unlock);
+       return nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, __nlm4svc_proc_unlock);
 }
 
-static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                                void            *resp)
+static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp)
 {
        dprintk("lockd: GRANTED_MSG   called\n");
-       return nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, argp, nlm4svc_proc_granted);
+       return nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, __nlm4svc_proc_granted);
 }
 
 /*
  * SHARE: create a DOS share or alter existing share.
  */
 static __be32
-nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                         struct nlm_res  *resp)
+nlm4svc_proc_share(struct svc_rqst *rqstp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
+       struct nlm_res *resp = rqstp->rq_resp;
        struct nlm_host *host;
        struct nlm_file *file;
 
@@ -345,9 +373,10 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
  * UNSHARE: Release a DOS share.
  */
 static __be32
-nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                           struct nlm_res  *resp)
+nlm4svc_proc_unshare(struct svc_rqst *rqstp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
+       struct nlm_res *resp = rqstp->rq_resp;
        struct nlm_host *host;
        struct nlm_file *file;
 
@@ -378,22 +407,23 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
  * NM_LOCK: Create an unmonitored lock
  */
 static __be32
-nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                           struct nlm_res  *resp)
+nlm4svc_proc_nm_lock(struct svc_rqst *rqstp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
+
        dprintk("lockd: NM_LOCK       called\n");
 
        argp->monitor = 0;              /* just clean the monitor flag */
-       return nlm4svc_proc_lock(rqstp, argp, resp);
+       return nlm4svc_proc_lock(rqstp);
 }
 
 /*
  * FREE_ALL: Release all locks and shares held by client
  */
 static __be32
-nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                            void            *resp)
+nlm4svc_proc_free_all(struct svc_rqst *rqstp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
 
        /* Obtain client */
@@ -409,9 +439,10 @@ nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
  * SM_NOTIFY: private callback from statd (not part of official NLM proto)
  */
 static __be32
-nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
-                                             void              *resp)
+nlm4svc_proc_sm_notify(struct svc_rqst *rqstp)
 {
+       struct nlm_reboot *argp = rqstp->rq_argp;
+
        dprintk("lockd: SM_NOTIFY     called\n");
 
        if (!nlm_privileged_requester(rqstp)) {
@@ -429,9 +460,10 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
  * client sent a GRANTED_RES, let's remove the associated block
  */
 static __be32
-nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res  *argp,
-                                                void            *resp)
+nlm4svc_proc_granted_res(struct svc_rqst *rqstp)
 {
+       struct nlm_res *argp = rqstp->rq_argp;
+
         if (!nlmsvc_ops)
                 return rpc_success;
 
@@ -463,9 +495,9 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res  *argp,
 struct nlm_void                        { int dummy; };
 
 #define PROC(name, xargt, xrest, argt, rest, respsize) \
- { .pc_func    = (svc_procfunc) nlm4svc_proc_##name,   \
-   .pc_decode  = (kxdrproc_t) nlm4svc_decode_##xargt,  \
-   .pc_encode  = (kxdrproc_t) nlm4svc_encode_##xrest,  \
+ { .pc_func    = nlm4svc_proc_##name,  \
+   .pc_decode  = nlm4svc_decode_##xargt,       \
+   .pc_encode  = nlm4svc_encode_##xrest,       \
    .pc_release = NULL,                                 \
    .pc_argsize = sizeof(struct nlm_##argt),            \
    .pc_ressize = sizeof(struct nlm_##rest),            \
@@ -475,7 +507,7 @@ struct nlm_void                     { int dummy; };
 #define        No      (1+1024/4)                              /* netobj */
 #define        St      1                                       /* status */
 #define        Rg      4                                       /* range (offset + length) */
-struct svc_procedure           nlmsvc_procedures4[] = {
+const struct svc_procedure nlmsvc_procedures4[] = {
   PROC(null,           void,           void,           void,   void, 1),
   PROC(test,           testargs,       testres,        args,   res, Ck+St+2+No+Rg),
   PROC(lock,           lockargs,       res,            args,   res, Ck+St),
index fb26b9f..0791516 100644 (file)
@@ -92,7 +92,7 @@ no_locks:
  * NULL: Test for presence of service
  */
 static __be32
-nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+nlmsvc_proc_null(struct svc_rqst *rqstp)
 {
        dprintk("lockd: NULL          called\n");
        return rpc_success;
@@ -102,9 +102,9 @@ nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
  * TEST: Check for conflicting lock
  */
 static __be32
-nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                        struct nlm_res  *resp)
+__nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
        struct nlm_file *file;
        __be32 rc = rpc_success;
@@ -130,9 +130,15 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
 }
 
 static __be32
-nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                        struct nlm_res  *resp)
+nlmsvc_proc_test(struct svc_rqst *rqstp)
 {
+       return __nlmsvc_proc_test(rqstp, rqstp->rq_resp);
+}
+
+static __be32
+__nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_res *resp)
+{
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
        struct nlm_file *file;
        __be32 rc = rpc_success;
@@ -172,9 +178,15 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 }
 
 static __be32
-nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                          struct nlm_res  *resp)
+nlmsvc_proc_lock(struct svc_rqst *rqstp)
+{
+       return __nlmsvc_proc_lock(rqstp, rqstp->rq_resp);
+}
+
+static __be32
+__nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_res *resp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
        struct nlm_file *file;
        struct net *net = SVC_NET(rqstp);
@@ -202,13 +214,19 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
        return rpc_success;
 }
 
+static __be32
+nlmsvc_proc_cancel(struct svc_rqst *rqstp)
+{
+       return __nlmsvc_proc_cancel(rqstp, rqstp->rq_resp);
+}
+
 /*
  * UNLOCK: release a lock
  */
 static __be32
-nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                          struct nlm_res  *resp)
+__nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_res *resp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
        struct nlm_file *file;
        struct net *net = SVC_NET(rqstp);
@@ -236,14 +254,21 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
        return rpc_success;
 }
 
+static __be32
+nlmsvc_proc_unlock(struct svc_rqst *rqstp)
+{
+       return __nlmsvc_proc_unlock(rqstp, rqstp->rq_resp);
+}
+
 /*
  * GRANTED: A server calls us to tell that a process' lock request
  * was granted
  */
 static __be32
-nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                           struct nlm_res  *resp)
+__nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_res *resp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
+
        resp->cookie = argp->cookie;
 
        dprintk("lockd: GRANTED       called\n");
@@ -252,6 +277,12 @@ nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
        return rpc_success;
 }
 
+static __be32
+nlmsvc_proc_granted(struct svc_rqst *rqstp)
+{
+       return __nlmsvc_proc_granted(rqstp, rqstp->rq_resp);
+}
+
 /*
  * This is the generic lockd callback for async RPC calls
  */
@@ -284,9 +315,10 @@ static const struct rpc_call_ops nlmsvc_callback_ops = {
  * because we send the callback before the reply proper. I hope this
  * doesn't break any clients.
  */
-static __be32 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
-               __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res  *))
+static __be32 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc,
+               __be32 (*func)(struct svc_rqst *, struct nlm_res *))
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
        struct nlm_rqst *call;
        __be32 stat;
@@ -302,7 +334,7 @@ static __be32 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args
        if (call == NULL)
                return rpc_system_err;
 
-       stat = func(rqstp, argp, &call->a_res);
+       stat = func(rqstp, &call->a_res);
        if (stat != 0) {
                nlmsvc_release_call(call);
                return stat;
@@ -314,50 +346,46 @@ static __be32 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args
        return rpc_success;
 }
 
-static __be32 nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                            void            *resp)
+static __be32 nlmsvc_proc_test_msg(struct svc_rqst *rqstp)
 {
        dprintk("lockd: TEST_MSG      called\n");
-       return nlmsvc_callback(rqstp, NLMPROC_TEST_RES, argp, nlmsvc_proc_test);
+       return nlmsvc_callback(rqstp, NLMPROC_TEST_RES, __nlmsvc_proc_test);
 }
 
-static __be32 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                            void            *resp)
+static __be32 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp)
 {
        dprintk("lockd: LOCK_MSG      called\n");
-       return nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlmsvc_proc_lock);
+       return nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, __nlmsvc_proc_lock);
 }
 
-static __be32 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                              void            *resp)
+static __be32 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp)
 {
        dprintk("lockd: CANCEL_MSG    called\n");
-       return nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlmsvc_proc_cancel);
+       return nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, __nlmsvc_proc_cancel);
 }
 
 static __be32
-nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                               void            *resp)
+nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp)
 {
        dprintk("lockd: UNLOCK_MSG    called\n");
-       return nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlmsvc_proc_unlock);
+       return nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, __nlmsvc_proc_unlock);
 }
 
 static __be32
-nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                                void            *resp)
+nlmsvc_proc_granted_msg(struct svc_rqst *rqstp)
 {
        dprintk("lockd: GRANTED_MSG   called\n");
-       return nlmsvc_callback(rqstp, NLMPROC_GRANTED_RES, argp, nlmsvc_proc_granted);
+       return nlmsvc_callback(rqstp, NLMPROC_GRANTED_RES, __nlmsvc_proc_granted);
 }
 
 /*
  * SHARE: create a DOS share or alter existing share.
  */
 static __be32
-nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                         struct nlm_res  *resp)
+nlmsvc_proc_share(struct svc_rqst *rqstp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
+       struct nlm_res *resp = rqstp->rq_resp;
        struct nlm_host *host;
        struct nlm_file *file;
 
@@ -388,9 +416,10 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
  * UNSHARE: Release a DOS share.
  */
 static __be32
-nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                           struct nlm_res  *resp)
+nlmsvc_proc_unshare(struct svc_rqst *rqstp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
+       struct nlm_res *resp = rqstp->rq_resp;
        struct nlm_host *host;
        struct nlm_file *file;
 
@@ -421,22 +450,23 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
  * NM_LOCK: Create an unmonitored lock
  */
 static __be32
-nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                           struct nlm_res  *resp)
+nlmsvc_proc_nm_lock(struct svc_rqst *rqstp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
+
        dprintk("lockd: NM_LOCK       called\n");
 
        argp->monitor = 0;              /* just clean the monitor flag */
-       return nlmsvc_proc_lock(rqstp, argp, resp);
+       return nlmsvc_proc_lock(rqstp);
 }
 
 /*
  * FREE_ALL: Release all locks and shares held by client
  */
 static __be32
-nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                            void            *resp)
+nlmsvc_proc_free_all(struct svc_rqst *rqstp)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_host *host;
 
        /* Obtain client */
@@ -452,9 +482,10 @@ nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
  * SM_NOTIFY: private callback from statd (not part of official NLM proto)
  */
 static __be32
-nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
-                                             void              *resp)
+nlmsvc_proc_sm_notify(struct svc_rqst *rqstp)
 {
+       struct nlm_reboot *argp = rqstp->rq_argp;
+
        dprintk("lockd: SM_NOTIFY     called\n");
 
        if (!nlm_privileged_requester(rqstp)) {
@@ -472,9 +503,10 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
  * client sent a GRANTED_RES, let's remove the associated block
  */
 static __be32
-nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res  *argp,
-                                                void            *resp)
+nlmsvc_proc_granted_res(struct svc_rqst *rqstp)
 {
+       struct nlm_res *argp = rqstp->rq_argp;
+
        if (!nlmsvc_ops)
                return rpc_success;
 
@@ -505,9 +537,9 @@ nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res  *argp,
 struct nlm_void                        { int dummy; };
 
 #define PROC(name, xargt, xrest, argt, rest, respsize) \
- { .pc_func    = (svc_procfunc) nlmsvc_proc_##name,    \
-   .pc_decode  = (kxdrproc_t) nlmsvc_decode_##xargt,   \
-   .pc_encode  = (kxdrproc_t) nlmsvc_encode_##xrest,   \
+ { .pc_func    = nlmsvc_proc_##name,                   \
+   .pc_decode  = nlmsvc_decode_##xargt,                \
+   .pc_encode  = nlmsvc_encode_##xrest,                \
    .pc_release = NULL,                                 \
    .pc_argsize = sizeof(struct nlm_##argt),            \
    .pc_ressize = sizeof(struct nlm_##rest),            \
@@ -519,7 +551,7 @@ struct nlm_void                     { int dummy; };
 #define        No      (1+1024/4)                      /* Net Obj */
 #define        Rg      2                               /* range - offset + size */
 
-struct svc_procedure           nlmsvc_procedures[] = {
+const struct svc_procedure nlmsvc_procedures[] = {
   PROC(null,           void,           void,           void,   void, 1),
   PROC(test,           testargs,       testres,        args,   res, Ck+St+2+No+Rg),
   PROC(lock,           lockargs,       res,            args,   res, Ck+St),
index 5b651da..442bbd0 100644 (file)
@@ -182,8 +182,9 @@ nlm_encode_testres(__be32 *p, struct nlm_res *resp)
  * First, the server side XDR functions
  */
 int
-nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        u32     exclusive;
 
        if (!(p = nlm_decode_cookie(p, &argp->cookie)))
@@ -199,16 +200,19 @@ nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 }
 
 int
-nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_res *resp = rqstp->rq_resp;
+
        if (!(p = nlm_encode_testres(p, resp)))
                return 0;
        return xdr_ressize_check(rqstp, p);
 }
 
 int
-nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        u32     exclusive;
 
        if (!(p = nlm_decode_cookie(p, &argp->cookie)))
@@ -227,8 +231,9 @@ nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 }
 
 int
-nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        u32     exclusive;
 
        if (!(p = nlm_decode_cookie(p, &argp->cookie)))
@@ -243,8 +248,10 @@ nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 }
 
 int
-nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
+
        if (!(p = nlm_decode_cookie(p, &argp->cookie))
         || !(p = nlm_decode_lock(p, &argp->lock)))
                return 0;
@@ -253,8 +260,9 @@ nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 }
 
 int
-nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_lock *lock = &argp->lock;
 
        memset(lock, 0, sizeof(*lock));
@@ -274,8 +282,10 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 }
 
 int
-nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_res *resp = rqstp->rq_resp;
+
        if (!(p = nlm_encode_cookie(p, &resp->cookie)))
                return 0;
        *p++ = resp->status;
@@ -284,8 +294,10 @@ nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 }
 
 int
-nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_res *resp = rqstp->rq_resp;
+
        if (!(p = nlm_encode_cookie(p, &resp->cookie)))
                return 0;
        *p++ = resp->status;
@@ -293,8 +305,9 @@ nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 }
 
 int
-nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
+nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_lock *lock = &argp->lock;
 
        if (!(p = xdr_decode_string_inplace(p, &lock->caller,
@@ -305,8 +318,10 @@ nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
 }
 
 int
-nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
+nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_reboot *argp = rqstp->rq_argp;
+
        if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
                return 0;
        argp->state = ntohl(*p++);
@@ -316,8 +331,10 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
 }
 
 int
-nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_res *resp = rqstp->rq_argp;
+
        if (!(p = nlm_decode_cookie(p, &resp->cookie)))
                return 0;
        resp->status = *p++;
@@ -325,13 +342,13 @@ nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 }
 
 int
-nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p)
 {
        return xdr_argsize_check(rqstp, p);
 }
 
 int
-nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
 {
        return xdr_ressize_check(rqstp, p);
 }
index dfa4789..2a0cd56 100644 (file)
@@ -179,8 +179,9 @@ nlm4_encode_testres(__be32 *p, struct nlm_res *resp)
  * First, the server side XDR functions
  */
 int
-nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        u32     exclusive;
 
        if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
@@ -196,16 +197,19 @@ nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 }
 
 int
-nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_res *resp = rqstp->rq_resp;
+
        if (!(p = nlm4_encode_testres(p, resp)))
                return 0;
        return xdr_ressize_check(rqstp, p);
 }
 
 int
-nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        u32     exclusive;
 
        if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
@@ -224,8 +228,9 @@ nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 }
 
 int
-nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        u32     exclusive;
 
        if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
@@ -240,8 +245,10 @@ nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 }
 
 int
-nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
+
        if (!(p = nlm4_decode_cookie(p, &argp->cookie))
         || !(p = nlm4_decode_lock(p, &argp->lock)))
                return 0;
@@ -250,8 +257,9 @@ nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 }
 
 int
-nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
+nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_lock *lock = &argp->lock;
 
        memset(lock, 0, sizeof(*lock));
@@ -271,8 +279,10 @@ nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 }
 
 int
-nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_res *resp = rqstp->rq_resp;
+
        if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
                return 0;
        *p++ = resp->status;
@@ -281,8 +291,10 @@ nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 }
 
 int
-nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_res *resp = rqstp->rq_resp;
+
        if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
                return 0;
        *p++ = resp->status;
@@ -290,8 +302,9 @@ nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 }
 
 int
-nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
+nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_args *argp = rqstp->rq_argp;
        struct nlm_lock *lock = &argp->lock;
 
        if (!(p = xdr_decode_string_inplace(p, &lock->caller,
@@ -302,8 +315,10 @@ nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
 }
 
 int
-nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
+nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_reboot *argp = rqstp->rq_argp;
+
        if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
                return 0;
        argp->state = ntohl(*p++);
@@ -313,8 +328,10 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp
 }
 
 int
-nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
+nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nlm_res *resp = rqstp->rq_argp;
+
        if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
                return 0;
        resp->status = *p++;
@@ -322,13 +339,13 @@ nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 }
 
 int
-nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p)
 {
        return xdr_argsize_check(rqstp, p);
 }
 
 int
-nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p)
 {
        return xdr_ressize_check(rqstp, p);
 }
index de45d9e..6790767 100644 (file)
@@ -16,7 +16,7 @@ struct mnt_namespace {
        u64 event;
        unsigned int            mounts; /* # of mounts in the namespace */
        unsigned int            pending_mounts;
-};
+} __randomize_layout;
 
 struct mnt_pcp {
        int mnt_count;
@@ -69,7 +69,7 @@ struct mount {
        struct hlist_head mnt_pins;
        struct fs_pin mnt_umount;
        struct dentry *mnt_ex_mountpoint;
-};
+} __randomize_layout;
 
 #define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */
 
index e0b46eb..ddb6a7c 100644 (file)
@@ -524,7 +524,7 @@ struct nameidata {
        struct inode    *link_inode;
        unsigned        root_seq;
        int             dfd;
-};
+} __randomize_layout;
 
 static void set_nameidata(struct nameidata *p, int dfd, struct filename *name)
 {
@@ -3400,7 +3400,6 @@ out:
 
 struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode, int open_flag)
 {
-       static const struct qstr name = QSTR_INIT("/", 1);
        struct dentry *child = NULL;
        struct inode *dir = dentry->d_inode;
        struct inode *inode;
@@ -3414,7 +3413,7 @@ struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode, int open_flag)
        if (!dir->i_op->tmpfile)
                goto out_err;
        error = -ENOMEM;
-       child = d_alloc(dentry, &name);
+       child = d_alloc(dentry, &slash_name);
        if (unlikely(!child))
                goto out_err;
        error = dir->i_op->tmpfile(dir, child, mode);
index 81f934b..f8893dc 100644 (file)
@@ -1238,65 +1238,6 @@ struct vfsmount *mnt_clone_internal(const struct path *path)
        return &p->mnt;
 }
 
-static inline void mangle(struct seq_file *m, const char *s)
-{
-       seq_escape(m, s, " \t\n\\");
-}
-
-/*
- * Simple .show_options callback for filesystems which don't want to
- * implement more complex mount option showing.
- *
- * See also save_mount_options().
- */
-int generic_show_options(struct seq_file *m, struct dentry *root)
-{
-       const char *options;
-
-       rcu_read_lock();
-       options = rcu_dereference(root->d_sb->s_options);
-
-       if (options != NULL && options[0]) {
-               seq_putc(m, ',');
-               mangle(m, options);
-       }
-       rcu_read_unlock();
-
-       return 0;
-}
-EXPORT_SYMBOL(generic_show_options);
-
-/*
- * If filesystem uses generic_show_options(), this function should be
- * called from the fill_super() callback.
- *
- * The .remount_fs callback usually needs to be handled in a special
- * way, to make sure, that previous options are not overwritten if the
- * remount fails.
- *
- * Also note, that if the filesystem's .remount_fs function doesn't
- * reset all options to their default value, but changes only newly
- * given options, then the displayed options will not reflect reality
- * any more.
- */
-void save_mount_options(struct super_block *sb, char *options)
-{
-       BUG_ON(sb->s_options);
-       rcu_assign_pointer(sb->s_options, kstrdup(options, GFP_KERNEL));
-}
-EXPORT_SYMBOL(save_mount_options);
-
-void replace_mount_options(struct super_block *sb, char *options)
-{
-       char *old = sb->s_options;
-       rcu_assign_pointer(sb->s_options, options);
-       if (old) {
-               synchronize_rcu();
-               kfree(old);
-       }
-}
-EXPORT_SYMBOL(replace_mount_options);
-
 #ifdef CONFIG_PROC_FS
 /* iterator; we want it to have access to namespace_sem, thus here... */
 static void *m_start(struct seq_file *m, loff_t *pos)
@@ -1657,7 +1598,7 @@ out_unlock:
        namespace_unlock();
 }
 
-/* 
+/*
  * Is the caller allowed to modify his namespace?
  */
 static inline bool may_mount(void)
@@ -2211,7 +2152,7 @@ static int do_loopback(struct path *path, const char *old_name,
 
        err = -EINVAL;
        if (mnt_ns_loop(old_path.dentry))
-               goto out; 
+               goto out;
 
        mp = lock_mount(path);
        err = PTR_ERR(mp);
index 98f4e57..1fb1189 100644 (file)
@@ -7,7 +7,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o
 CFLAGS_nfstrace.o += -I$(src)
 nfs-y                  := client.o dir.o file.o getroot.o inode.o super.o \
                           io.o direct.o pagelist.o read.o symlink.o unlink.o \
-                          write.o namespace.o mount_clnt.o nfstrace.o
+                          write.o namespace.o mount_clnt.o nfstrace.o export.o
 nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
 nfs-$(CONFIG_SYSCTL)   += sysctl.o
 nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
index 73a1f92..3432387 100644 (file)
@@ -439,7 +439,7 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
 /*
  * Define NFS4 callback program
  */
-static struct svc_version *nfs4_callback_version[] = {
+static const struct svc_version *nfs4_callback_version[] = {
        [1] = &nfs4_callback_version1,
        [4] = &nfs4_callback_version4,
 };
index c701c30..3dc54d7 100644 (file)
@@ -114,8 +114,7 @@ struct cb_sequenceres {
        uint32_t                        csr_target_highestslotid;
 };
 
-extern __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
-                                      struct cb_sequenceres *res,
+extern __be32 nfs4_callback_sequence(void *argp, void *resp,
                                       struct cb_process_state *cps);
 
 #define RCA4_TYPE_MASK_RDATA_DLG       0
@@ -134,15 +133,13 @@ struct cb_recallanyargs {
        uint32_t        craa_type_mask;
 };
 
-extern __be32 nfs4_callback_recallany(struct cb_recallanyargs *args,
-                                       void *dummy,
+extern __be32 nfs4_callback_recallany(void *argp, void *resp,
                                        struct cb_process_state *cps);
 
 struct cb_recallslotargs {
        uint32_t        crsa_target_highest_slotid;
 };
-extern __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args,
-                                        void *dummy,
+extern __be32 nfs4_callback_recallslot(void *argp, void *resp,
                                         struct cb_process_state *cps);
 
 struct cb_layoutrecallargs {
@@ -159,9 +156,8 @@ struct cb_layoutrecallargs {
        };
 };
 
-extern __be32 nfs4_callback_layoutrecall(
-       struct cb_layoutrecallargs *args,
-       void *dummy, struct cb_process_state *cps);
+extern __be32 nfs4_callback_layoutrecall(void *argp, void *resp,
+               struct cb_process_state *cps);
 
 struct cb_devicenotifyitem {
        uint32_t                cbd_notify_type;
@@ -175,9 +171,8 @@ struct cb_devicenotifyargs {
        struct cb_devicenotifyitem       *devs;
 };
 
-extern __be32 nfs4_callback_devicenotify(
-       struct cb_devicenotifyargs *args,
-       void *dummy, struct cb_process_state *cps);
+extern __be32 nfs4_callback_devicenotify(void *argp, void *resp,
+               struct cb_process_state *cps);
 
 struct cb_notify_lock_args {
        struct nfs_fh                   cbnl_fh;
@@ -185,15 +180,13 @@ struct cb_notify_lock_args {
        bool                            cbnl_valid;
 };
 
-extern __be32 nfs4_callback_notify_lock(struct cb_notify_lock_args *args,
-                                        void *dummy,
+extern __be32 nfs4_callback_notify_lock(void *argp, void *resp,
                                         struct cb_process_state *cps);
 #endif /* CONFIG_NFS_V4_1 */
 extern int check_gss_callback_principal(struct nfs_client *, struct svc_rqst *);
-extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
-                                   struct cb_getattrres *res,
+extern __be32 nfs4_callback_getattr(void *argp, void *resp,
                                    struct cb_process_state *cps);
-extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
+extern __be32 nfs4_callback_recall(void *argp, void *resp,
                                   struct cb_process_state *cps);
 #if IS_ENABLED(CONFIG_NFS_V4)
 extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt);
index 52479f1..5427cdf 100644 (file)
 
 #define NFSDBG_FACILITY NFSDBG_CALLBACK
 
-__be32 nfs4_callback_getattr(struct cb_getattrargs *args,
-                            struct cb_getattrres *res,
+__be32 nfs4_callback_getattr(void *argp, void *resp,
                             struct cb_process_state *cps)
 {
+       struct cb_getattrargs *args = argp;
+       struct cb_getattrres *res = resp;
        struct nfs_delegation *delegation;
        struct nfs_inode *nfsi;
        struct inode *inode;
@@ -68,9 +69,10 @@ out:
        return res->status;
 }
 
-__be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
+__be32 nfs4_callback_recall(void *argp, void *resp,
                            struct cb_process_state *cps)
 {
+       struct cb_recallargs *args = argp;
        struct inode *inode;
        __be32 res;
        
@@ -324,9 +326,10 @@ static u32 do_callback_layoutrecall(struct nfs_client *clp,
        return initiate_bulk_draining(clp, args);
 }
 
-__be32 nfs4_callback_layoutrecall(struct cb_layoutrecallargs *args,
-                                 void *dummy, struct cb_process_state *cps)
+__be32 nfs4_callback_layoutrecall(void *argp, void *resp,
+                                 struct cb_process_state *cps)
 {
+       struct cb_layoutrecallargs *args = argp;
        u32 res = NFS4ERR_OP_NOT_IN_SESSION;
 
        if (cps->clp)
@@ -345,9 +348,10 @@ static void pnfs_recall_all_layouts(struct nfs_client *clp)
        do_callback_layoutrecall(clp, &args);
 }
 
-__be32 nfs4_callback_devicenotify(struct cb_devicenotifyargs *args,
-                                 void *dummy, struct cb_process_state *cps)
+__be32 nfs4_callback_devicenotify(void *argp, void *resp,
+                                 struct cb_process_state *cps)
 {
+       struct cb_devicenotifyargs *args = argp;
        int i;
        __be32 res = 0;
        struct nfs_client *clp = cps->clp;
@@ -469,10 +473,11 @@ out:
        return status;
 }
 
-__be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
-                             struct cb_sequenceres *res,
+__be32 nfs4_callback_sequence(void *argp, void *resp,
                              struct cb_process_state *cps)
 {
+       struct cb_sequenceargs *args = argp;
+       struct cb_sequenceres *res = resp;
        struct nfs4_slot_table *tbl;
        struct nfs4_slot *slot;
        struct nfs_client *clp;
@@ -571,9 +576,10 @@ validate_bitmap_values(unsigned long mask)
        return (mask & ~RCA4_TYPE_MASK_ALL) == 0;
 }
 
-__be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy,
+__be32 nfs4_callback_recallany(void *argp, void *resp,
                               struct cb_process_state *cps)
 {
+       struct cb_recallanyargs *args = argp;
        __be32 status;
        fmode_t flags = 0;
 
@@ -606,9 +612,10 @@ out:
 }
 
 /* Reduce the fore channel's max_slots to the target value */
-__be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,
+__be32 nfs4_callback_recallslot(void *argp, void *resp,
                                struct cb_process_state *cps)
 {
+       struct cb_recallslotargs *args = argp;
        struct nfs4_slot_table *fc_tbl;
        __be32 status;
 
@@ -631,9 +638,11 @@ out:
        return status;
 }
 
-__be32 nfs4_callback_notify_lock(struct cb_notify_lock_args *args, void *dummy,
+__be32 nfs4_callback_notify_lock(void *argp, void *resp,
                                 struct cb_process_state *cps)
 {
+       struct cb_notify_lock_args *args = argp;
+
        if (!cps->clp) /* set in cb_sequence */
                return htonl(NFS4ERR_OP_NOT_IN_SESSION);
 
index 390ac9c..681dd64 100644 (file)
 /* Internal error code */
 #define NFS4ERR_RESOURCE_HDR   11050
 
-typedef __be32 (*callback_process_op_t)(void *, void *,
-                                       struct cb_process_state *);
-typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
-typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
-
-
 struct callback_op {
-       callback_process_op_t process_op;
-       callback_decode_arg_t decode_args;
-       callback_encode_res_t encode_res;
+       __be32 (*process_op)(void *, void *, struct cb_process_state *);
+       __be32 (*decode_args)(struct svc_rqst *, struct xdr_stream *, void *);
+       __be32 (*encode_res)(struct svc_rqst *, struct xdr_stream *,
+                       const void *);
        long res_maxsize;
 };
 
 static struct callback_op callback_ops[];
 
-static __be32 nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp)
+static __be32 nfs4_callback_null(struct svc_rqst *rqstp)
 {
        return htonl(NFS4_OK);
 }
 
-static int nfs4_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+static int nfs4_decode_void(struct svc_rqst *rqstp, __be32 *p)
 {
        return xdr_argsize_check(rqstp, p);
 }
 
-static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p)
 {
        return xdr_ressize_check(rqstp, p);
 }
@@ -184,8 +179,10 @@ static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
        return 0;
 }
 
-static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args)
+static __be32 decode_getattr_args(struct svc_rqst *rqstp,
+               struct xdr_stream *xdr, void *argp)
 {
+       struct cb_getattrargs *args = argp;
        __be32 status;
 
        status = decode_fh(xdr, &args->fh);
@@ -194,8 +191,10 @@ static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr
        return decode_bitmap(xdr, args->bitmap);
 }
 
-static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args)
+static __be32 decode_recall_args(struct svc_rqst *rqstp,
+               struct xdr_stream *xdr, void *argp)
 {
+       struct cb_recallargs *args = argp;
        __be32 *p;
        __be32 status;
 
@@ -217,9 +216,9 @@ static __be32 decode_layout_stateid(struct xdr_stream *xdr, nfs4_stateid *statei
 }
 
 static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp,
-                                      struct xdr_stream *xdr,
-                                      struct cb_layoutrecallargs *args)
+                                      struct xdr_stream *xdr, void *argp)
 {
+       struct cb_layoutrecallargs *args = argp;
        __be32 *p;
        __be32 status = 0;
        uint32_t iomode;
@@ -262,8 +261,9 @@ static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp,
 static
 __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
                                struct xdr_stream *xdr,
-                               struct cb_devicenotifyargs *args)
+                               void *argp)
 {
+       struct cb_devicenotifyargs *args = argp;
        __be32 *p;
        __be32 status = 0;
        u32 tmp;
@@ -403,8 +403,9 @@ out:
 
 static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp,
                                        struct xdr_stream *xdr,
-                                       struct cb_sequenceargs *args)
+                                       void *argp)
 {
+       struct cb_sequenceargs *args = argp;
        __be32 *p;
        int i;
        __be32 status;
@@ -450,8 +451,9 @@ out_free:
 
 static __be32 decode_recallany_args(struct svc_rqst *rqstp,
                                      struct xdr_stream *xdr,
-                                     struct cb_recallanyargs *args)
+                                     void *argp)
 {
+       struct cb_recallanyargs *args = argp;
        uint32_t bitmap[2];
        __be32 *p, status;
 
@@ -469,8 +471,9 @@ static __be32 decode_recallany_args(struct svc_rqst *rqstp,
 
 static __be32 decode_recallslot_args(struct svc_rqst *rqstp,
                                        struct xdr_stream *xdr,
-                                       struct cb_recallslotargs *args)
+                                       void *argp)
 {
+       struct cb_recallslotargs *args = argp;
        __be32 *p;
 
        p = read_buf(xdr, 4);
@@ -510,8 +513,10 @@ static __be32 decode_lockowner(struct xdr_stream *xdr, struct cb_notify_lock_arg
        return 0;
 }
 
-static __be32 decode_notify_lock_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_notify_lock_args *args)
+static __be32 decode_notify_lock_args(struct svc_rqst *rqstp,
+               struct xdr_stream *xdr, void *argp)
 {
+       struct cb_notify_lock_args *args = argp;
        __be32 status;
 
        status = decode_fh(xdr, &args->cbnl_fh);
@@ -641,8 +646,10 @@ static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res)
        return 0;
 }
 
-static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res)
+static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr,
+               const void *resp)
 {
+       const struct cb_getattrres *res = resp;
        __be32 *savep = NULL;
        __be32 status = res->status;
        
@@ -683,8 +690,9 @@ static __be32 encode_sessionid(struct xdr_stream *xdr,
 
 static __be32 encode_cb_sequence_res(struct svc_rqst *rqstp,
                                       struct xdr_stream *xdr,
-                                      const struct cb_sequenceres *res)
+                                      const void *resp)
 {
+       const struct cb_sequenceres *res = resp;
        __be32 *p;
        __be32 status = res->csr_status;
 
@@ -871,7 +879,7 @@ encode_hdr:
 /*
  * Decode, process and encode a COMPOUND
  */
-static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
+static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)
 {
        struct cb_compound_hdr_arg hdr_arg = { 0 };
        struct cb_compound_hdr_res hdr_res = { NULL };
@@ -907,7 +915,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
 
        while (status == 0 && nops != hdr_arg.nops) {
                status = process_op(nops, rqstp, &xdr_in,
-                                   argp, &xdr_out, resp, &cps);
+                                   rqstp->rq_argp, &xdr_out, rqstp->rq_resp,
+                                   &cps);
                nops++;
        }
 
@@ -937,48 +946,46 @@ static struct callback_op callback_ops[] = {
                .res_maxsize = CB_OP_HDR_RES_MAXSZ,
        },
        [OP_CB_GETATTR] = {
-               .process_op = (callback_process_op_t)nfs4_callback_getattr,
-               .decode_args = (callback_decode_arg_t)decode_getattr_args,
-               .encode_res = (callback_encode_res_t)encode_getattr_res,
+               .process_op = nfs4_callback_getattr,
+               .decode_args = decode_getattr_args,
+               .encode_res = encode_getattr_res,
                .res_maxsize = CB_OP_GETATTR_RES_MAXSZ,
        },
        [OP_CB_RECALL] = {
-               .process_op = (callback_process_op_t)nfs4_callback_recall,
-               .decode_args = (callback_decode_arg_t)decode_recall_args,
+               .process_op = nfs4_callback_recall,
+               .decode_args = decode_recall_args,
                .res_maxsize = CB_OP_RECALL_RES_MAXSZ,
        },
 #if defined(CONFIG_NFS_V4_1)
        [OP_CB_LAYOUTRECALL] = {
-               .process_op = (callback_process_op_t)nfs4_callback_layoutrecall,
-               .decode_args =
-                       (callback_decode_arg_t)decode_layoutrecall_args,
+               .process_op = nfs4_callback_layoutrecall,
+               .decode_args = decode_layoutrecall_args,
                .res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ,
        },
        [OP_CB_NOTIFY_DEVICEID] = {
-               .process_op = (callback_process_op_t)nfs4_callback_devicenotify,
-               .decode_args =
-                       (callback_decode_arg_t)decode_devicenotify_args,
+               .process_op = nfs4_callback_devicenotify,
+               .decode_args = decode_devicenotify_args,
                .res_maxsize = CB_OP_DEVICENOTIFY_RES_MAXSZ,
        },
        [OP_CB_SEQUENCE] = {
-               .process_op = (callback_process_op_t)nfs4_callback_sequence,
-               .decode_args = (callback_decode_arg_t)decode_cb_sequence_args,
-               .encode_res = (callback_encode_res_t)encode_cb_sequence_res,
+               .process_op = nfs4_callback_sequence,
+               .decode_args = decode_cb_sequence_args,
+               .encode_res = encode_cb_sequence_res,
                .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ,
        },
        [OP_CB_RECALL_ANY] = {
-               .process_op = (callback_process_op_t)nfs4_callback_recallany,
-               .decode_args = (callback_decode_arg_t)decode_recallany_args,
+               .process_op = nfs4_callback_recallany,
+               .decode_args = decode_recallany_args,
                .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ,
        },
        [OP_CB_RECALL_SLOT] = {
-               .process_op = (callback_process_op_t)nfs4_callback_recallslot,
-               .decode_args = (callback_decode_arg_t)decode_recallslot_args,
+               .process_op = nfs4_callback_recallslot,
+               .decode_args = decode_recallslot_args,
                .res_maxsize = CB_OP_RECALLSLOT_RES_MAXSZ,
        },
        [OP_CB_NOTIFY_LOCK] = {
-               .process_op = (callback_process_op_t)nfs4_callback_notify_lock,
-               .decode_args = (callback_decode_arg_t)decode_notify_lock_args,
+               .process_op = nfs4_callback_notify_lock,
+               .decode_args = decode_notify_lock_args,
                .res_maxsize = CB_OP_NOTIFY_LOCK_RES_MAXSZ,
        },
 #endif /* CONFIG_NFS_V4_1 */
@@ -987,36 +994,40 @@ static struct callback_op callback_ops[] = {
 /*
  * Define NFS4 callback procedures
  */
-static struct svc_procedure nfs4_callback_procedures1[] = {
+static const struct svc_procedure nfs4_callback_procedures1[] = {
        [CB_NULL] = {
                .pc_func = nfs4_callback_null,
-               .pc_decode = (kxdrproc_t)nfs4_decode_void,
-               .pc_encode = (kxdrproc_t)nfs4_encode_void,
+               .pc_decode = nfs4_decode_void,
+               .pc_encode = nfs4_encode_void,
                .pc_xdrressize = 1,
        },
        [CB_COMPOUND] = {
                .pc_func = nfs4_callback_compound,
-               .pc_encode = (kxdrproc_t)nfs4_encode_void,
+               .pc_encode = nfs4_encode_void,
                .pc_argsize = 256,
                .pc_ressize = 256,
                .pc_xdrressize = NFS4_CALLBACK_BUFSIZE,
        }
 };
 
-struct svc_version nfs4_callback_version1 = {
+static unsigned int nfs4_callback_count1[ARRAY_SIZE(nfs4_callback_procedures1)];
+const struct svc_version nfs4_callback_version1 = {
        .vs_vers = 1,
        .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
        .vs_proc = nfs4_callback_procedures1,
+       .vs_count = nfs4_callback_count1,
        .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
        .vs_dispatch = NULL,
        .vs_hidden = true,
        .vs_need_cong_ctrl = true,
 };
 
-struct svc_version nfs4_callback_version4 = {
+static unsigned int nfs4_callback_count4[ARRAY_SIZE(nfs4_callback_procedures1)];
+const struct svc_version nfs4_callback_version4 = {
        .vs_vers = 4,
        .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
        .vs_proc = nfs4_callback_procedures1,
+       .vs_count = nfs4_callback_count4,
        .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
        .vs_dispatch = NULL,
        .vs_hidden = true,
index ee5ddbd..efebe6c 100644 (file)
@@ -820,6 +820,7 @@ void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *sour
        target->caps = source->caps;
        target->options = source->options;
        target->auth_info = source->auth_info;
+       target->port = source->port;
 }
 EXPORT_SYMBOL_GPL(nfs_server_copy_userdata);
 
index 2ac00bf..3522b12 100644 (file)
@@ -151,7 +151,7 @@ struct nfs_cache_array {
        struct nfs_cache_array_entry array[0];
 };
 
-typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, int);
+typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, bool);
 typedef struct {
        struct file     *file;
        struct page     *page;
@@ -165,8 +165,8 @@ typedef struct {
        unsigned long   timestamp;
        unsigned long   gencount;
        unsigned int    cache_entry_index;
-       unsigned int    plus:1;
-       unsigned int    eof:1;
+       bool plus;
+       bool eof;
 } nfs_readdir_descriptor_t;
 
 /*
@@ -355,7 +355,7 @@ int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc,
                if (error == -ENOTSUPP && desc->plus) {
                        NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS;
                        clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
-                       desc->plus = 0;
+                       desc->plus = false;
                        goto again;
                }
                goto error;
@@ -557,7 +557,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
 
                count++;
 
-               if (desc->plus != 0)
+               if (desc->plus)
                        nfs_prime_dcache(file_dentry(desc->file), entry);
 
                status = nfs_readdir_add_to_array(entry, page);
@@ -860,7 +860,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        desc->ctx = ctx;
        desc->dir_cookie = &dir_ctx->dir_cookie;
        desc->decode = NFS_PROTO(inode)->decode_dirent;
-       desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0;
+       desc->plus = nfs_use_readdirplus(inode, ctx);
 
        if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
                res = nfs_revalidate_mapping(inode, file->f_mapping);
@@ -885,8 +885,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
                        clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
                        nfs_zap_caches(inode);
                        desc->page_index = 0;
-                       desc->plus = 0;
-                       desc->eof = 0;
+                       desc->plus = false;
+                       desc->eof = false;
                        continue;
                }
                if (res < 0)
@@ -1115,11 +1115,13 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
        /* Force a full look up iff the parent directory has changed */
        if (!nfs_is_exclusive_create(dir, flags) &&
            nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) {
-
-               if (nfs_lookup_verify_inode(inode, flags)) {
+               error = nfs_lookup_verify_inode(inode, flags);
+               if (error) {
                        if (flags & LOOKUP_RCU)
                                return -ECHILD;
-                       goto out_zap_parent;
+                       if (error == -ESTALE)
+                               goto out_zap_parent;
+                       goto out_error;
                }
                nfs_advise_use_readdirplus(dir);
                goto out_valid;
@@ -1144,8 +1146,10 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
        trace_nfs_lookup_revalidate_enter(dir, dentry, flags);
        error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
        trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error);
-       if (error)
+       if (error == -ESTALE || error == -ENOENT)
                goto out_bad;
+       if (error)
+               goto out_error;
        if (nfs_compare_fh(NFS_FH(inode), fhandle))
                goto out_bad;
        if ((error = nfs_refresh_inode(inode, fattr)) != 0)
@@ -1427,8 +1431,10 @@ static int nfs_finish_open(struct nfs_open_context *ctx,
        err = finish_open(file, dentry, do_open, opened);
        if (err)
                goto out;
-       nfs_file_set_open_context(file, ctx);
-
+       if (S_ISREG(file->f_path.dentry->d_inode->i_mode))
+               nfs_file_set_open_context(file, ctx);
+       else
+               err = -ESTALE;
 out:
        return err;
 }
@@ -1512,7 +1518,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
                d_drop(dentry);
                switch (err) {
                case -ENOENT:
-                       d_add(dentry, NULL);
+                       d_splice_alias(NULL, dentry);
                        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
                        break;
                case -EISDIR:
@@ -2035,7 +2041,11 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        }
 
        error = rpc_wait_for_completion_task(task);
-       if (error == 0)
+       if (error != 0) {
+               ((struct nfs_renamedata *)task->tk_calldata)->cancelled = 1;
+               /* Paired with the atomic_dec_and_test() barrier in rpc_do_put_task() */
+               smp_wmb();
+       } else
                error = task->tk_status;
        rpc_put_task(task);
        nfs_mark_for_revalidate(old_inode);
@@ -2362,16 +2372,40 @@ void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
 }
 EXPORT_SYMBOL_GPL(nfs_access_add_cache);
 
+#define NFS_MAY_READ (NFS4_ACCESS_READ)
+#define NFS_MAY_WRITE (NFS4_ACCESS_MODIFY | \
+               NFS4_ACCESS_EXTEND | \
+               NFS4_ACCESS_DELETE)
+#define NFS_FILE_MAY_WRITE (NFS4_ACCESS_MODIFY | \
+               NFS4_ACCESS_EXTEND)
+#define NFS_DIR_MAY_WRITE NFS_MAY_WRITE
+#define NFS_MAY_LOOKUP (NFS4_ACCESS_LOOKUP)
+#define NFS_MAY_EXECUTE (NFS4_ACCESS_EXECUTE)
+static int
+nfs_access_calc_mask(u32 access_result, umode_t umode)
+{
+       int mask = 0;
+
+       if (access_result & NFS_MAY_READ)
+               mask |= MAY_READ;
+       if (S_ISDIR(umode)) {
+               if ((access_result & NFS_DIR_MAY_WRITE) == NFS_DIR_MAY_WRITE)
+                       mask |= MAY_WRITE;
+               if ((access_result & NFS_MAY_LOOKUP) == NFS_MAY_LOOKUP)
+                       mask |= MAY_EXEC;
+       } else if (S_ISREG(umode)) {
+               if ((access_result & NFS_FILE_MAY_WRITE) == NFS_FILE_MAY_WRITE)
+                       mask |= MAY_WRITE;
+               if ((access_result & NFS_MAY_EXECUTE) == NFS_MAY_EXECUTE)
+                       mask |= MAY_EXEC;
+       } else if (access_result & NFS_MAY_WRITE)
+                       mask |= MAY_WRITE;
+       return mask;
+}
+
 void nfs_access_set_mask(struct nfs_access_entry *entry, u32 access_result)
 {
-       entry->mask = 0;
-       if (access_result & NFS4_ACCESS_READ)
-               entry->mask |= MAY_READ;
-       if (access_result &
-           (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE))
-               entry->mask |= MAY_WRITE;
-       if (access_result & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
-               entry->mask |= MAY_EXEC;
+       entry->mask = access_result;
 }
 EXPORT_SYMBOL_GPL(nfs_access_set_mask);
 
@@ -2379,6 +2413,7 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
 {
        struct nfs_access_entry cache;
        bool may_block = (mask & MAY_NOT_BLOCK) == 0;
+       int cache_mask;
        int status;
 
        trace_nfs_access_enter(inode);
@@ -2394,7 +2429,8 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
                goto out;
 
        /* Be clever: ask server to check for all possible rights */
-       cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ;
+       cache.mask = NFS_MAY_LOOKUP | NFS_MAY_EXECUTE
+                    | NFS_MAY_WRITE | NFS_MAY_READ;
        cache.cred = cred;
        cache.jiffies = jiffies;
        status = NFS_PROTO(inode)->access(inode, &cache);
@@ -2408,7 +2444,8 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
        }
        nfs_access_add_cache(inode, &cache);
 out_cached:
-       if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) != 0)
+       cache_mask = nfs_access_calc_mask(cache.mask, inode->i_mode);
+       if ((mask & ~cache_mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) != 0)
                status = -EACCES;
 out:
        trace_nfs_access_exit(inode, status);
diff --git a/fs/nfs/export.c b/fs/nfs/export.c
new file mode 100644 (file)
index 0000000..249cb96
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2015, Primary Data, Inc. All rights reserved.
+ *
+ * Tao Peng <bergwolf@primarydata.com>
+ */
+#include <linux/dcache.h>
+#include <linux/exportfs.h>
+#include <linux/nfs.h>
+#include <linux/nfs_fs.h>
+
+#include "internal.h"
+#include "nfstrace.h"
+
+#define NFSDBG_FACILITY                NFSDBG_VFS
+
+enum {
+       FILEID_HIGH_OFF = 0,    /* inode fileid high */
+       FILEID_LOW_OFF,         /* inode fileid low */
+       FILE_I_TYPE_OFF,        /* inode type */
+       EMBED_FH_OFF            /* embeded server fh */
+};
+
+
+static struct nfs_fh *nfs_exp_embedfh(__u32 *p)
+{
+       return (struct nfs_fh *)(p + EMBED_FH_OFF);
+}
+
+/*
+ * Let's break subtree checking for now... otherwise we'll have to embed parent fh
+ * but there might not be enough space.
+ */
+static int
+nfs_encode_fh(struct inode *inode, __u32 *p, int *max_len, struct inode *parent)
+{
+       struct nfs_fh *server_fh = NFS_FH(inode);
+       struct nfs_fh *clnt_fh = nfs_exp_embedfh(p);
+       size_t fh_size = offsetof(struct nfs_fh, data) + server_fh->size;
+       int len = EMBED_FH_OFF + XDR_QUADLEN(fh_size);
+
+       dprintk("%s: max fh len %d inode %p parent %p",
+               __func__, *max_len, inode, parent);
+
+       if (*max_len < len || IS_AUTOMOUNT(inode)) {
+               dprintk("%s: fh len %d too small, required %d\n",
+                       __func__, *max_len, len);
+               *max_len = len;
+               return FILEID_INVALID;
+       }
+       if (IS_AUTOMOUNT(inode)) {
+               *max_len = FILEID_INVALID;
+               goto out;
+       }
+
+       p[FILEID_HIGH_OFF] = NFS_FILEID(inode) >> 32;
+       p[FILEID_LOW_OFF] = NFS_FILEID(inode);
+       p[FILE_I_TYPE_OFF] = inode->i_mode & S_IFMT;
+       p[len - 1] = 0; /* Padding */
+       nfs_copy_fh(clnt_fh, server_fh);
+       *max_len = len;
+out:
+       dprintk("%s: result fh fileid %llu mode %u size %d\n",
+               __func__, NFS_FILEID(inode), inode->i_mode, *max_len);
+       return *max_len;
+}
+
+static struct dentry *
+nfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+                int fh_len, int fh_type)
+{
+       struct nfs4_label *label = NULL;
+       struct nfs_fattr *fattr = NULL;
+       struct nfs_fh *server_fh = nfs_exp_embedfh(fid->raw);
+       size_t fh_size = offsetof(struct nfs_fh, data) + server_fh->size;
+       const struct nfs_rpc_ops *rpc_ops;
+       struct dentry *dentry;
+       struct inode *inode;
+       int len = EMBED_FH_OFF + XDR_QUADLEN(fh_size);
+       u32 *p = fid->raw;
+       int ret;
+
+       /* NULL translates to ESTALE */
+       if (fh_len < len || fh_type != len)
+               return NULL;
+
+       fattr = nfs_alloc_fattr();
+       if (fattr == NULL) {
+               dentry = ERR_PTR(-ENOMEM);
+               goto out;
+       }
+
+       fattr->fileid = ((u64)p[FILEID_HIGH_OFF] << 32) + p[FILEID_LOW_OFF];
+       fattr->mode = p[FILE_I_TYPE_OFF];
+       fattr->valid |= NFS_ATTR_FATTR_FILEID | NFS_ATTR_FATTR_TYPE;
+
+       dprintk("%s: fileid %llu mode %d\n", __func__, fattr->fileid, fattr->mode);
+
+       inode = nfs_ilookup(sb, fattr, server_fh);
+       if (inode)
+               goto out_found;
+
+       label = nfs4_label_alloc(NFS_SB(sb), GFP_KERNEL);
+       if (IS_ERR(label)) {
+               dentry = ERR_CAST(label);
+               goto out_free_fattr;
+       }
+
+       rpc_ops = NFS_SB(sb)->nfs_client->rpc_ops;
+       ret = rpc_ops->getattr(NFS_SB(sb), server_fh, fattr, label);
+       if (ret) {
+               dprintk("%s: getattr failed %d\n", __func__, ret);
+               dentry = ERR_PTR(ret);
+               goto out_free_label;
+       }
+
+       inode = nfs_fhget(sb, server_fh, fattr, label);
+
+out_found:
+       dentry = d_obtain_alias(inode);
+
+out_free_label:
+       nfs4_label_free(label);
+out_free_fattr:
+       nfs_free_fattr(fattr);
+out:
+       return dentry;
+}
+
+static struct dentry *
+nfs_get_parent(struct dentry *dentry)
+{
+       int ret;
+       struct inode *inode = d_inode(dentry), *pinode;
+       struct super_block *sb = inode->i_sb;
+       struct nfs_server *server = NFS_SB(sb);
+       struct nfs_fattr *fattr = NULL;
+       struct nfs4_label *label = NULL;
+       struct dentry *parent;
+       struct nfs_rpc_ops const *ops = server->nfs_client->rpc_ops;
+       struct nfs_fh fh;
+
+       if (!ops->lookupp)
+               return ERR_PTR(-EACCES);
+
+       fattr = nfs_alloc_fattr();
+       if (fattr == NULL) {
+               parent = ERR_PTR(-ENOMEM);
+               goto out;
+       }
+
+       label = nfs4_label_alloc(server, GFP_KERNEL);
+       if (IS_ERR(label)) {
+               parent = ERR_CAST(label);
+               goto out_free_fattr;
+       }
+
+       ret = ops->lookupp(inode, &fh, fattr, label);
+       if (ret) {
+               parent = ERR_PTR(ret);
+               goto out_free_label;
+       }
+
+       pinode = nfs_fhget(sb, &fh, fattr, label);
+       parent = d_obtain_alias(pinode);
+out_free_label:
+       nfs4_label_free(label);
+out_free_fattr:
+       nfs_free_fattr(fattr);
+out:
+       return parent;
+}
+
+const struct export_operations nfs_export_ops = {
+       .encode_fh = nfs_encode_fh,
+       .fh_to_dentry = nfs_fh_to_dentry,
+       .get_parent = nfs_get_parent,
+};
index 5713eb3..af330c3 100644 (file)
@@ -617,6 +617,8 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
                if (result)
                        goto out;
        }
+       if (iocb->ki_pos > i_size_read(inode))
+               nfs_revalidate_mapping(inode, file->f_mapping);
 
        nfs_start_io_write(inode);
        result = generic_write_checks(iocb, from);
@@ -750,7 +752,7 @@ do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
         */
        nfs_sync_mapping(filp->f_mapping);
        if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
-               nfs_zap_mapping(inode, filp->f_mapping);
+               nfs_zap_caches(inode);
 out:
        return status;
 }
index 1cf85d6..44c638b 100644 (file)
@@ -126,32 +126,13 @@ static int filelayout_async_handle_error(struct rpc_task *task,
 {
        struct pnfs_layout_hdr *lo = lseg->pls_layout;
        struct inode *inode = lo->plh_inode;
-       struct nfs_server *mds_server = NFS_SERVER(inode);
        struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
-       struct nfs_client *mds_client = mds_server->nfs_client;
        struct nfs4_slot_table *tbl = &clp->cl_session->fc_slot_table;
 
        if (task->tk_status >= 0)
                return 0;
 
        switch (task->tk_status) {
-       /* MDS state errors */
-       case -NFS4ERR_DELEG_REVOKED:
-       case -NFS4ERR_ADMIN_REVOKED:
-       case -NFS4ERR_BAD_STATEID:
-       case -NFS4ERR_OPENMODE:
-               if (state == NULL)
-                       break;
-               if (nfs4_schedule_stateid_recovery(mds_server, state) < 0)
-                       goto out_bad_stateid;
-               goto wait_on_recovery;
-       case -NFS4ERR_EXPIRED:
-               if (state != NULL) {
-                       if (nfs4_schedule_stateid_recovery(mds_server, state) < 0)
-                               goto out_bad_stateid;
-               }
-               nfs4_schedule_lease_recovery(mds_client);
-               goto wait_on_recovery;
        /* DS session errors */
        case -NFS4ERR_BADSESSION:
        case -NFS4ERR_BADSLOT:
@@ -172,6 +153,7 @@ static int filelayout_async_handle_error(struct rpc_task *task,
        case -NFS4ERR_RETRY_UNCACHED_REP:
                break;
        /* Invalidate Layout errors */
+       case -NFS4ERR_ACCESS:
        case -NFS4ERR_PNFS_NO_LAYOUT:
        case -ESTALE:           /* mapped NFS4ERR_STALE */
        case -EBADHANDLE:       /* mapped NFS4ERR_BADHANDLE */
@@ -202,26 +184,17 @@ static int filelayout_async_handle_error(struct rpc_task *task,
                        task->tk_status);
                nfs4_mark_deviceid_unavailable(devid);
                pnfs_error_mark_layout_for_return(inode, lseg);
+               pnfs_set_lo_fail(lseg);
                rpc_wake_up(&tbl->slot_tbl_waitq);
                /* fall through */
        default:
-               pnfs_set_lo_fail(lseg);
 reset:
                dprintk("%s Retry through MDS. Error %d\n", __func__,
                        task->tk_status);
                return -NFS4ERR_RESET_TO_MDS;
        }
-out:
        task->tk_status = 0;
        return -EAGAIN;
-out_bad_stateid:
-       task->tk_status = -EIO;
-       return 0;
-wait_on_recovery:
-       rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL);
-       if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0)
-               rpc_wake_up_queued_task(&mds_client->cl_rpcwaitq, task);
-       goto out;
 }
 
 /* NFS_PROTO call done callback routines */
@@ -569,6 +542,10 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
        struct nfs4_file_layout_dsaddr *dsaddr;
        int status = -EINVAL;
 
+       /* Is the deviceid already set? If so, we're good. */
+       if (fl->dsaddr != NULL)
+               return 0;
+
        /* find and reference the deviceid */
        d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &fl->deviceid,
                        lo->plh_lc_cred, gfp_flags);
@@ -580,8 +557,6 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
        if (filelayout_test_devid_unavailable(&dsaddr->id_node))
                goto out_put;
 
-       fl->dsaddr = dsaddr;
-
        if (fl->first_stripe_index >= dsaddr->stripe_count) {
                dprintk("%s Bad first_stripe_index %u\n",
                                __func__, fl->first_stripe_index);
@@ -597,6 +572,13 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
                goto out_put;
        }
        status = 0;
+
+       /*
+        * Atomic compare and xchange to ensure we don't scribble
+        * over a non-NULL pointer.
+        */
+       if (cmpxchg(&fl->dsaddr, NULL, dsaddr) != NULL)
+               goto out_put;
 out:
        return status;
 out_put:
index 23542dc..b0fa83a 100644 (file)
@@ -1050,34 +1050,10 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
 {
        struct pnfs_layout_hdr *lo = lseg->pls_layout;
        struct inode *inode = lo->plh_inode;
-       struct nfs_server *mds_server = NFS_SERVER(inode);
-
        struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx);
-       struct nfs_client *mds_client = mds_server->nfs_client;
        struct nfs4_slot_table *tbl = &clp->cl_session->fc_slot_table;
 
        switch (task->tk_status) {
-       /* MDS state errors */
-       case -NFS4ERR_DELEG_REVOKED:
-       case -NFS4ERR_ADMIN_REVOKED:
-       case -NFS4ERR_BAD_STATEID:
-               if (state == NULL)
-                       break;
-               nfs_remove_bad_delegation(state->inode, NULL);
-       case -NFS4ERR_OPENMODE:
-               if (state == NULL)
-                       break;
-               if (nfs4_schedule_stateid_recovery(mds_server, state) < 0)
-                       goto out_bad_stateid;
-               goto wait_on_recovery;
-       case -NFS4ERR_EXPIRED:
-               if (state != NULL) {
-                       if (nfs4_schedule_stateid_recovery(mds_server, state) < 0)
-                               goto out_bad_stateid;
-               }
-               nfs4_schedule_lease_recovery(mds_client);
-               goto wait_on_recovery;
-       /* DS session errors */
        case -NFS4ERR_BADSESSION:
        case -NFS4ERR_BADSLOT:
        case -NFS4ERR_BAD_HIGH_SLOT:
@@ -1137,17 +1113,8 @@ reset:
                        task->tk_status);
                return -NFS4ERR_RESET_TO_MDS;
        }
-out:
        task->tk_status = 0;
        return -EAGAIN;
-out_bad_stateid:
-       task->tk_status = -EIO;
-       return 0;
-wait_on_recovery:
-       rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL);
-       if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0)
-               rpc_wake_up_queued_task(&mds_client->cl_rpcwaitq, task);
-       goto out;
 }
 
 /* Retry all errors through either pNFS or MDS except for -EJUKEBOX */
@@ -1875,6 +1842,10 @@ static int ff_layout_initiate_commit(struct nfs_commit_data *data, int how)
        int vers, ret;
        struct nfs_fh *fh;
 
+       if (!lseg || !(pnfs_is_valid_lseg(lseg) ||
+           test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags)))
+               goto out_err;
+
        idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
        ds = nfs4_ff_layout_prepare_ds(lseg, idx, true);
        if (!ds)
index 1de93ba..109279d 100644 (file)
@@ -386,6 +386,28 @@ void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
 #endif
 EXPORT_SYMBOL_GPL(nfs_setsecurity);
 
+/* Search for inode identified by fh, fileid and i_mode in inode cache. */
+struct inode *
+nfs_ilookup(struct super_block *sb, struct nfs_fattr *fattr, struct nfs_fh *fh)
+{
+       struct nfs_find_desc desc = {
+               .fh     = fh,
+               .fattr  = fattr,
+       };
+       struct inode *inode;
+       unsigned long hash;
+
+       if (!(fattr->valid & NFS_ATTR_FATTR_FILEID) ||
+           !(fattr->valid & NFS_ATTR_FATTR_TYPE))
+               return NULL;
+
+       hash = nfs_fattr_to_ino_t(fattr);
+       inode = ilookup5(sb, hash, nfs_find_actor, &desc);
+
+       dprintk("%s: returning %p\n", __func__, inode);
+       return inode;
+}
+
 /*
  * This is our front-end to iget that looks up inodes by file handle
  * instead of inode number.
@@ -525,8 +547,14 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
                nfs_fscache_init_inode(inode);
 
                unlock_new_inode(inode);
-       } else
-               nfs_refresh_inode(inode, fattr);
+       } else {
+               int err = nfs_refresh_inode(inode, fattr);
+               if (err < 0) {
+                       iput(inode);
+                       inode = ERR_PTR(err);
+                       goto out_no_inode;
+               }
+       }
        dprintk("NFS: nfs_fhget(%s/%Lu fh_crc=0x%08x ct=%d)\n",
                inode->i_sb->s_id,
                (unsigned long long)NFS_FILEID(inode),
@@ -1315,9 +1343,9 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
                return 0;
        /* Has the inode gone and changed behind our back? */
        if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
-               return -EIO;
+               return -ESTALE;
        if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
-               return -EIO;
+               return -ESTALE;
 
        if (!nfs_file_has_buffered_writers(nfsi)) {
                /* Verify a few of the more important attributes */
index 8701d76..dc45641 100644 (file)
@@ -11,6 +11,8 @@
 
 #define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
 
+extern const struct export_operations nfs_export_ops;
+
 struct nfs_string;
 
 /* Maximum number of readahead requests
@@ -226,8 +228,8 @@ static inline void nfs_fs_proc_exit(void)
 #endif
 
 /* callback_xdr.c */
-extern struct svc_version nfs4_callback_version1;
-extern struct svc_version nfs4_callback_version4;
+extern const struct svc_version nfs4_callback_version1;
+extern const struct svc_version nfs4_callback_version4;
 
 struct nfs_pageio_descriptor;
 /* pagelist.c */
@@ -271,19 +273,19 @@ static inline bool nfs_match_open_context(const struct nfs_open_context *ctx1,
 }
 
 /* nfs2xdr.c */
-extern struct rpc_procinfo nfs_procedures[];
+extern const struct rpc_procinfo nfs_procedures[];
 extern int nfs2_decode_dirent(struct xdr_stream *,
-                               struct nfs_entry *, int);
+                               struct nfs_entry *, bool);
 
 /* nfs3xdr.c */
-extern struct rpc_procinfo nfs3_procedures[];
+extern const struct rpc_procinfo nfs3_procedures[];
 extern int nfs3_decode_dirent(struct xdr_stream *,
-                               struct nfs_entry *, int);
+                               struct nfs_entry *, bool);
 
 /* nfs4xdr.c */
 #if IS_ENABLED(CONFIG_NFS_V4)
 extern int nfs4_decode_dirent(struct xdr_stream *,
-                               struct nfs_entry *, int);
+                               struct nfs_entry *, bool);
 #endif
 #ifdef CONFIG_NFS_V4_1
 extern const u32 nfs41_maxread_overhead;
@@ -293,7 +295,7 @@ extern const u32 nfs41_maxgetdevinfo_overhead;
 
 /* nfs4proc.c */
 #if IS_ENABLED(CONFIG_NFS_V4)
-extern struct rpc_procinfo nfs4_procedures[];
+extern const struct rpc_procinfo nfs4_procedures[];
 #endif
 
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
index 09b1900..60bad88 100644 (file)
@@ -304,7 +304,7 @@ static void encode_mntdirpath(struct xdr_stream *xdr, const char *pathname)
 }
 
 static void mnt_xdr_enc_dirpath(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               const char *dirpath)
+                               const void *dirpath)
 {
        encode_mntdirpath(xdr, dirpath);
 }
@@ -357,8 +357,9 @@ static int decode_fhandle(struct xdr_stream *xdr, struct mountres *res)
 
 static int mnt_xdr_dec_mountres(struct rpc_rqst *req,
                                struct xdr_stream *xdr,
-                               struct mountres *res)
+                               void *data)
 {
+       struct mountres *res = data;
        int status;
 
        status = decode_status(xdr, res);
@@ -449,8 +450,9 @@ static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res)
 
 static int mnt_xdr_dec_mountres3(struct rpc_rqst *req,
                                 struct xdr_stream *xdr,
-                                struct mountres *res)
+                                void *data)
 {
+       struct mountres *res = data;
        int status;
 
        status = decode_fhs_status(xdr, res);
@@ -464,11 +466,11 @@ static int mnt_xdr_dec_mountres3(struct rpc_rqst *req,
        return decode_auth_flavors(xdr, res);
 }
 
-static struct rpc_procinfo mnt_procedures[] = {
+static const struct rpc_procinfo mnt_procedures[] = {
        [MOUNTPROC_MNT] = {
                .p_proc         = MOUNTPROC_MNT,
-               .p_encode       = (kxdreproc_t)mnt_xdr_enc_dirpath,
-               .p_decode       = (kxdrdproc_t)mnt_xdr_dec_mountres,
+               .p_encode       = mnt_xdr_enc_dirpath,
+               .p_decode       = mnt_xdr_dec_mountres,
                .p_arglen       = MNT_enc_dirpath_sz,
                .p_replen       = MNT_dec_mountres_sz,
                .p_statidx      = MOUNTPROC_MNT,
@@ -476,18 +478,18 @@ static struct rpc_procinfo mnt_procedures[] = {
        },
        [MOUNTPROC_UMNT] = {
                .p_proc         = MOUNTPROC_UMNT,
-               .p_encode       = (kxdreproc_t)mnt_xdr_enc_dirpath,
+               .p_encode       = mnt_xdr_enc_dirpath,
                .p_arglen       = MNT_enc_dirpath_sz,
                .p_statidx      = MOUNTPROC_UMNT,
                .p_name         = "UMOUNT",
        },
 };
 
-static struct rpc_procinfo mnt3_procedures[] = {
+static const struct rpc_procinfo mnt3_procedures[] = {
        [MOUNTPROC3_MNT] = {
                .p_proc         = MOUNTPROC3_MNT,
-               .p_encode       = (kxdreproc_t)mnt_xdr_enc_dirpath,
-               .p_decode       = (kxdrdproc_t)mnt_xdr_dec_mountres3,
+               .p_encode       = mnt_xdr_enc_dirpath,
+               .p_decode       = mnt_xdr_dec_mountres3,
                .p_arglen       = MNT_enc_dirpath_sz,
                .p_replen       = MNT_dec_mountres3_sz,
                .p_statidx      = MOUNTPROC3_MNT,
@@ -495,24 +497,27 @@ static struct rpc_procinfo mnt3_procedures[] = {
        },
        [MOUNTPROC3_UMNT] = {
                .p_proc         = MOUNTPROC3_UMNT,
-               .p_encode       = (kxdreproc_t)mnt_xdr_enc_dirpath,
+               .p_encode       = mnt_xdr_enc_dirpath,
                .p_arglen       = MNT_enc_dirpath_sz,
                .p_statidx      = MOUNTPROC3_UMNT,
                .p_name         = "UMOUNT",
        },
 };
 
-
+static unsigned int mnt_counts[ARRAY_SIZE(mnt_procedures)];
 static const struct rpc_version mnt_version1 = {
        .number         = 1,
        .nrprocs        = ARRAY_SIZE(mnt_procedures),
        .procs          = mnt_procedures,
+       .counts         = mnt_counts,
 };
 
+static unsigned int mnt3_counts[ARRAY_SIZE(mnt3_procedures)];
 static const struct rpc_version mnt_version3 = {
        .number         = 3,
        .nrprocs        = ARRAY_SIZE(mnt3_procedures),
        .procs          = mnt3_procedures,
+       .counts         = mnt3_counts,
 };
 
 static const struct rpc_version *mnt_version[] = {
index b4e03ed..fe68dab 100644 (file)
@@ -568,8 +568,10 @@ out_default:
 
 static void nfs2_xdr_enc_fhandle(struct rpc_rqst *req,
                                 struct xdr_stream *xdr,
-                                const struct nfs_fh *fh)
+                                const void *data)
 {
+       const struct nfs_fh *fh = data;
+
        encode_fhandle(xdr, fh);
 }
 
@@ -583,23 +585,29 @@ static void nfs2_xdr_enc_fhandle(struct rpc_rqst *req,
  */
 static void nfs2_xdr_enc_sattrargs(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  const struct nfs_sattrargs *args)
+                                  const void *data)
 {
+       const struct nfs_sattrargs *args = data;
+
        encode_fhandle(xdr, args->fh);
        encode_sattr(xdr, args->sattr);
 }
 
 static void nfs2_xdr_enc_diropargs(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  const struct nfs_diropargs *args)
+                                  const void *data)
 {
+       const struct nfs_diropargs *args = data;
+
        encode_diropargs(xdr, args->fh, args->name, args->len);
 }
 
 static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req,
                                      struct xdr_stream *xdr,
-                                     const struct nfs_readlinkargs *args)
+                                     const void *data)
 {
+       const struct nfs_readlinkargs *args = data;
+
        encode_fhandle(xdr, args->fh);
        prepare_reply_buffer(req, args->pages, args->pgbase,
                                        args->pglen, NFS_readlinkres_sz);
@@ -632,8 +640,10 @@ static void encode_readargs(struct xdr_stream *xdr,
 
 static void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
                                  struct xdr_stream *xdr,
-                                 const struct nfs_pgio_args *args)
+                                 const void *data)
 {
+       const struct nfs_pgio_args *args = data;
+
        encode_readargs(xdr, args);
        prepare_reply_buffer(req, args->pages, args->pgbase,
                                        args->count, NFS_readres_sz);
@@ -672,8 +682,10 @@ static void encode_writeargs(struct xdr_stream *xdr,
 
 static void nfs2_xdr_enc_writeargs(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  const struct nfs_pgio_args *args)
+                                  const void *data)
 {
+       const struct nfs_pgio_args *args = data;
+
        encode_writeargs(xdr, args);
        xdr->buf->flags |= XDRBUF_WRITE;
 }
@@ -688,16 +700,20 @@ static void nfs2_xdr_enc_writeargs(struct rpc_rqst *req,
  */
 static void nfs2_xdr_enc_createargs(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   const struct nfs_createargs *args)
+                                   const void *data)
 {
+       const struct nfs_createargs *args = data;
+
        encode_diropargs(xdr, args->fh, args->name, args->len);
        encode_sattr(xdr, args->sattr);
 }
 
 static void nfs2_xdr_enc_removeargs(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   const struct nfs_removeargs *args)
+                                   const void *data)
 {
+       const struct nfs_removeargs *args = data;
+
        encode_diropargs(xdr, args->fh, args->name.name, args->name.len);
 }
 
@@ -711,8 +727,9 @@ static void nfs2_xdr_enc_removeargs(struct rpc_rqst *req,
  */
 static void nfs2_xdr_enc_renameargs(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   const struct nfs_renameargs *args)
+                                   const void *data)
 {
+       const struct nfs_renameargs *args = data;
        const struct qstr *old = args->old_name;
        const struct qstr *new = args->new_name;
 
@@ -730,8 +747,10 @@ static void nfs2_xdr_enc_renameargs(struct rpc_rqst *req,
  */
 static void nfs2_xdr_enc_linkargs(struct rpc_rqst *req,
                                  struct xdr_stream *xdr,
-                                 const struct nfs_linkargs *args)
+                                 const void *data)
 {
+       const struct nfs_linkargs *args = data;
+
        encode_fhandle(xdr, args->fromfh);
        encode_diropargs(xdr, args->tofh, args->toname, args->tolen);
 }
@@ -747,8 +766,10 @@ static void nfs2_xdr_enc_linkargs(struct rpc_rqst *req,
  */
 static void nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    const struct nfs_symlinkargs *args)
+                                    const void *data)
 {
+       const struct nfs_symlinkargs *args = data;
+
        encode_diropargs(xdr, args->fromfh, args->fromname, args->fromlen);
        encode_path(xdr, args->pages, args->pathlen);
        encode_sattr(xdr, args->sattr);
@@ -777,8 +798,10 @@ static void encode_readdirargs(struct xdr_stream *xdr,
 
 static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    const struct nfs_readdirargs *args)
+                                    const void *data)
 {
+       const struct nfs_readdirargs *args = data;
+
        encode_readdirargs(xdr, args);
        prepare_reply_buffer(req, args->pages, 0,
                                        args->count, NFS_readdirres_sz);
@@ -809,13 +832,13 @@ out_default:
 }
 
 static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                struct nfs_fattr *result)
+                                void *result)
 {
        return decode_attrstat(xdr, result, NULL);
 }
 
 static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                struct nfs_diropok *result)
+                                void *result)
 {
        return decode_diropres(xdr, result);
 }
@@ -860,8 +883,9 @@ out_default:
  *     };
  */
 static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               struct nfs_pgio_res *result)
+                               void *data)
 {
+       struct nfs_pgio_res *result = data;
        enum nfs_stat status;
        int error;
 
@@ -882,8 +906,10 @@ out_default:
 }
 
 static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                struct nfs_pgio_res *result)
+                                void *data)
 {
+       struct nfs_pgio_res *result = data;
+
        /* All NFSv2 writes are "file sync" writes */
        result->verf->committed = NFS_FILE_SYNC;
        return decode_attrstat(xdr, result->fattr, &result->op_status);
@@ -913,7 +939,7 @@ static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr,
  *     };
  */
 int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
-                      int plus)
+                      bool plus)
 {
        __be32 *p;
        int error;
@@ -1034,7 +1060,7 @@ out_overflow:
 }
 
 static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                 struct nfs2_fsstat *result)
+                                 void *result)
 {
        enum nfs_stat status;
        int error;
@@ -1118,15 +1144,15 @@ static int nfs_stat_to_errno(enum nfs_stat status)
 #define PROC(proc, argtype, restype, timer)                            \
 [NFSPROC_##proc] = {                                                   \
        .p_proc     =  NFSPROC_##proc,                                  \
-       .p_encode   =  (kxdreproc_t)nfs2_xdr_enc_##argtype,             \
-       .p_decode   =  (kxdrdproc_t)nfs2_xdr_dec_##restype,             \
+       .p_encode   =  nfs2_xdr_enc_##argtype,                          \
+       .p_decode   =  nfs2_xdr_dec_##restype,                          \
        .p_arglen   =  NFS_##argtype##_sz,                              \
        .p_replen   =  NFS_##restype##_sz,                              \
        .p_timer    =  timer,                                           \
        .p_statidx  =  NFSPROC_##proc,                                  \
        .p_name     =  #proc,                                           \
        }
-struct rpc_procinfo    nfs_procedures[] = {
+const struct rpc_procinfo nfs_procedures[] = {
        PROC(GETATTR,   fhandle,        attrstat,       1),
        PROC(SETATTR,   sattrargs,      attrstat,       0),
        PROC(LOOKUP,    diropargs,      diropres,       2),
@@ -1144,8 +1170,10 @@ struct rpc_procinfo      nfs_procedures[] = {
        PROC(STATFS,    fhandle,        statfsres,      0),
 };
 
+static unsigned int nfs_version2_counts[ARRAY_SIZE(nfs_procedures)];
 const struct rpc_version nfs_version2 = {
        .number                 = 2,
        .nrprocs                = ARRAY_SIZE(nfs_procedures),
-       .procs                  = nfs_procedures
+       .procs                  = nfs_procedures,
+       .counts                 = nfs_version2_counts,
 };
index 0c07b56..d1e87ec 100644 (file)
@@ -220,15 +220,8 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
 
        status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
        nfs_refresh_inode(inode, res.fattr);
-       if (status == 0) {
-               entry->mask = 0;
-               if (res.access & NFS3_ACCESS_READ)
-                       entry->mask |= MAY_READ;
-               if (res.access & (NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE))
-                       entry->mask |= MAY_WRITE;
-               if (res.access & (NFS3_ACCESS_LOOKUP|NFS3_ACCESS_EXECUTE))
-                       entry->mask |= MAY_EXEC;
-       }
+       if (status == 0)
+               nfs_access_set_mask(entry, res.access);
        nfs_free_fattr(res.fattr);
 out:
        dprintk("NFS reply access: %d\n", status);
@@ -621,7 +614,7 @@ out:
  */
 static int
 nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
-                 u64 cookie, struct page **pages, unsigned int count, int plus)
+                 u64 cookie, struct page **pages, unsigned int count, bool plus)
 {
        struct inode            *dir = d_inode(dentry);
        __be32                  *verf = NFS_I(dir)->cookieverf;
index 267126d..e82c9e5 100644 (file)
@@ -846,8 +846,10 @@ static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
  */
 static void nfs3_xdr_enc_getattr3args(struct rpc_rqst *req,
                                      struct xdr_stream *xdr,
-                                     const struct nfs_fh *fh)
+                                     const void *data)
 {
+       const struct nfs_fh *fh = data;
+
        encode_nfs_fh3(xdr, fh);
 }
 
@@ -884,8 +886,9 @@ static void encode_sattrguard3(struct xdr_stream *xdr,
 
 static void nfs3_xdr_enc_setattr3args(struct rpc_rqst *req,
                                      struct xdr_stream *xdr,
-                                     const struct nfs3_sattrargs *args)
+                                     const void *data)
 {
+       const struct nfs3_sattrargs *args = data;
        encode_nfs_fh3(xdr, args->fh);
        encode_sattr3(xdr, args->sattr);
        encode_sattrguard3(xdr, args);
@@ -900,8 +903,10 @@ static void nfs3_xdr_enc_setattr3args(struct rpc_rqst *req,
  */
 static void nfs3_xdr_enc_lookup3args(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    const struct nfs3_diropargs *args)
+                                    const void *data)
 {
+       const struct nfs3_diropargs *args = data;
+
        encode_diropargs3(xdr, args->fh, args->name, args->len);
 }
 
@@ -922,8 +927,10 @@ static void encode_access3args(struct xdr_stream *xdr,
 
 static void nfs3_xdr_enc_access3args(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    const struct nfs3_accessargs *args)
+                                    const void *data)
 {
+       const struct nfs3_accessargs *args = data;
+
        encode_access3args(xdr, args);
 }
 
@@ -936,8 +943,10 @@ static void nfs3_xdr_enc_access3args(struct rpc_rqst *req,
  */
 static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req,
                                       struct xdr_stream *xdr,
-                                      const struct nfs3_readlinkargs *args)
+                                      const void *data)
 {
+       const struct nfs3_readlinkargs *args = data;
+
        encode_nfs_fh3(xdr, args->fh);
        prepare_reply_buffer(req, args->pages, args->pgbase,
                                        args->pglen, NFS3_readlinkres_sz);
@@ -966,8 +975,10 @@ static void encode_read3args(struct xdr_stream *xdr,
 
 static void nfs3_xdr_enc_read3args(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  const struct nfs_pgio_args *args)
+                                  const void *data)
 {
+       const struct nfs_pgio_args *args = data;
+
        encode_read3args(xdr, args);
        prepare_reply_buffer(req, args->pages, args->pgbase,
                                        args->count, NFS3_readres_sz);
@@ -1008,8 +1019,10 @@ static void encode_write3args(struct xdr_stream *xdr,
 
 static void nfs3_xdr_enc_write3args(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   const struct nfs_pgio_args *args)
+                                   const void *data)
 {
+       const struct nfs_pgio_args *args = data;
+
        encode_write3args(xdr, args);
        xdr->buf->flags |= XDRBUF_WRITE;
 }
@@ -1055,8 +1068,10 @@ static void encode_createhow3(struct xdr_stream *xdr,
 
 static void nfs3_xdr_enc_create3args(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    const struct nfs3_createargs *args)
+                                    const void *data)
 {
+       const struct nfs3_createargs *args = data;
+
        encode_diropargs3(xdr, args->fh, args->name, args->len);
        encode_createhow3(xdr, args);
 }
@@ -1071,8 +1086,10 @@ static void nfs3_xdr_enc_create3args(struct rpc_rqst *req,
  */
 static void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   const struct nfs3_mkdirargs *args)
+                                   const void *data)
 {
+       const struct nfs3_mkdirargs *args = data;
+
        encode_diropargs3(xdr, args->fh, args->name, args->len);
        encode_sattr3(xdr, args->sattr);
 }
@@ -1091,16 +1108,20 @@ static void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req,
  *     };
  */
 static void encode_symlinkdata3(struct xdr_stream *xdr,
-                               const struct nfs3_symlinkargs *args)
+                               const void *data)
 {
+       const struct nfs3_symlinkargs *args = data;
+
        encode_sattr3(xdr, args->sattr);
        encode_nfspath3(xdr, args->pages, args->pathlen);
 }
 
 static void nfs3_xdr_enc_symlink3args(struct rpc_rqst *req,
                                      struct xdr_stream *xdr,
-                                     const struct nfs3_symlinkargs *args)
+                                     const void *data)
 {
+       const struct nfs3_symlinkargs *args = data;
+
        encode_diropargs3(xdr, args->fromfh, args->fromname, args->fromlen);
        encode_symlinkdata3(xdr, args);
        xdr->buf->flags |= XDRBUF_WRITE;
@@ -1160,8 +1181,10 @@ static void encode_mknoddata3(struct xdr_stream *xdr,
 
 static void nfs3_xdr_enc_mknod3args(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   const struct nfs3_mknodargs *args)
+                                   const void *data)
 {
+       const struct nfs3_mknodargs *args = data;
+
        encode_diropargs3(xdr, args->fh, args->name, args->len);
        encode_mknoddata3(xdr, args);
 }
@@ -1175,8 +1198,10 @@ static void nfs3_xdr_enc_mknod3args(struct rpc_rqst *req,
  */
 static void nfs3_xdr_enc_remove3args(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    const struct nfs_removeargs *args)
+                                    const void *data)
 {
+       const struct nfs_removeargs *args = data;
+
        encode_diropargs3(xdr, args->fh, args->name.name, args->name.len);
 }
 
@@ -1190,8 +1215,9 @@ static void nfs3_xdr_enc_remove3args(struct rpc_rqst *req,
  */
 static void nfs3_xdr_enc_rename3args(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    const struct nfs_renameargs *args)
+                                    const void *data)
 {
+       const struct nfs_renameargs *args = data;
        const struct qstr *old = args->old_name;
        const struct qstr *new = args->new_name;
 
@@ -1209,8 +1235,10 @@ static void nfs3_xdr_enc_rename3args(struct rpc_rqst *req,
  */
 static void nfs3_xdr_enc_link3args(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  const struct nfs3_linkargs *args)
+                                  const void *data)
 {
+       const struct nfs3_linkargs *args = data;
+
        encode_nfs_fh3(xdr, args->fromfh);
        encode_diropargs3(xdr, args->tofh, args->toname, args->tolen);
 }
@@ -1240,8 +1268,10 @@ static void encode_readdir3args(struct xdr_stream *xdr,
 
 static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req,
                                      struct xdr_stream *xdr,
-                                     const struct nfs3_readdirargs *args)
+                                     const void *data)
 {
+       const struct nfs3_readdirargs *args = data;
+
        encode_readdir3args(xdr, args);
        prepare_reply_buffer(req, args->pages, 0,
                                args->count, NFS3_readdirres_sz);
@@ -1280,8 +1310,10 @@ static void encode_readdirplus3args(struct xdr_stream *xdr,
 
 static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req,
                                          struct xdr_stream *xdr,
-                                         const struct nfs3_readdirargs *args)
+                                         const void *data)
 {
+       const struct nfs3_readdirargs *args = data;
+
        encode_readdirplus3args(xdr, args);
        prepare_reply_buffer(req, args->pages, 0,
                                args->count, NFS3_readdirres_sz);
@@ -1310,8 +1342,10 @@ static void encode_commit3args(struct xdr_stream *xdr,
 
 static void nfs3_xdr_enc_commit3args(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    const struct nfs_commitargs *args)
+                                    const void *data)
 {
+       const struct nfs_commitargs *args = data;
+
        encode_commit3args(xdr, args);
 }
 
@@ -1319,8 +1353,10 @@ static void nfs3_xdr_enc_commit3args(struct rpc_rqst *req,
 
 static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    const struct nfs3_getaclargs *args)
+                                    const void *data)
 {
+       const struct nfs3_getaclargs *args = data;
+
        encode_nfs_fh3(xdr, args->fh);
        encode_uint32(xdr, args->mask);
        if (args->mask & (NFS_ACL | NFS_DFACL))
@@ -1331,8 +1367,9 @@ static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req,
 
 static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    const struct nfs3_setaclargs *args)
+                                    const void *data)
 {
+       const struct nfs3_setaclargs *args = data;
        unsigned int base;
        int error;
 
@@ -1382,7 +1419,7 @@ static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
  */
 static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   struct nfs_fattr *result)
+                                   void *result)
 {
        enum nfs_stat status;
        int error;
@@ -1419,7 +1456,7 @@ out_default:
  */
 static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   struct nfs_fattr *result)
+                                   void *result)
 {
        enum nfs_stat status;
        int error;
@@ -1460,8 +1497,9 @@ out_status:
  */
 static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  struct nfs3_diropres *result)
+                                  void *data)
 {
+       struct nfs3_diropres *result = data;
        enum nfs_stat status;
        int error;
 
@@ -1507,8 +1545,9 @@ out_default:
  */
 static int nfs3_xdr_dec_access3res(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  struct nfs3_accessres *result)
+                                  void *data)
 {
+       struct nfs3_accessres *result = data;
        enum nfs_stat status;
        int error;
 
@@ -1548,7 +1587,7 @@ out_default:
  */
 static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    struct nfs_fattr *result)
+                                    void *result)
 {
        enum nfs_stat status;
        int error;
@@ -1626,8 +1665,9 @@ out_overflow:
 }
 
 static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                struct nfs_pgio_res *result)
+                                void *data)
 {
+       struct nfs_pgio_res *result = data;
        enum nfs_stat status;
        int error;
 
@@ -1699,8 +1739,9 @@ out_eio:
 }
 
 static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                 struct nfs_pgio_res *result)
+                                 void *data)
 {
+       struct nfs_pgio_res *result = data;
        enum nfs_stat status;
        int error;
 
@@ -1764,8 +1805,9 @@ out:
 
 static int nfs3_xdr_dec_create3res(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  struct nfs3_diropres *result)
+                                  void *data)
 {
+       struct nfs3_diropres *result = data;
        enum nfs_stat status;
        int error;
 
@@ -1804,8 +1846,9 @@ out_default:
  */
 static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  struct nfs_removeres *result)
+                                  void *data)
 {
+       struct nfs_removeres *result = data;
        enum nfs_stat status;
        int error;
 
@@ -1845,8 +1888,9 @@ out_status:
  */
 static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  struct nfs_renameres *result)
+                                  void *data)
 {
+       struct nfs_renameres *result = data;
        enum nfs_stat status;
        int error;
 
@@ -1888,8 +1932,9 @@ out_status:
  *     };
  */
 static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                struct nfs3_linkres *result)
+                                void *data)
 {
+       struct nfs3_linkres *result = data;
        enum nfs_stat status;
        int error;
 
@@ -1946,7 +1991,7 @@ out_status:
  *     };
  */
 int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
-                      int plus)
+                      bool plus)
 {
        struct nfs_entry old = *entry;
        __be32 *p;
@@ -2072,8 +2117,9 @@ out:
 
 static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   struct nfs3_readdirres *result)
+                                   void *data)
 {
+       struct nfs3_readdirres *result = data;
        enum nfs_stat status;
        int error;
 
@@ -2140,8 +2186,9 @@ out_overflow:
 
 static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  struct nfs_fsstat *result)
+                                  void *data)
 {
+       struct nfs_fsstat *result = data;
        enum nfs_stat status;
        int error;
 
@@ -2216,8 +2263,9 @@ out_overflow:
 
 static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  struct nfs_fsinfo *result)
+                                  void *data)
 {
+       struct nfs_fsinfo *result = data;
        enum nfs_stat status;
        int error;
 
@@ -2279,8 +2327,9 @@ out_overflow:
 
 static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    struct nfs_pathconf *result)
+                                    void *data)
 {
+       struct nfs_pathconf *result = data;
        enum nfs_stat status;
        int error;
 
@@ -2320,8 +2369,9 @@ out_status:
  */
 static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  struct nfs_commitres *result)
+                                  void *data)
 {
+       struct nfs_commitres *result = data;
        enum nfs_stat status;
        int error;
 
@@ -2389,7 +2439,7 @@ out:
 
 static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  struct nfs3_getaclres *result)
+                                  void *result)
 {
        enum nfs_stat status;
        int error;
@@ -2408,7 +2458,7 @@ out_default:
 
 static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  struct nfs_fattr *result)
+                                  void *result)
 {
        enum nfs_stat status;
        int error;
@@ -2495,8 +2545,8 @@ static int nfs3_stat_to_errno(enum nfs_stat status)
 #define PROC(proc, argtype, restype, timer)                            \
 [NFS3PROC_##proc] = {                                                  \
        .p_proc      = NFS3PROC_##proc,                                 \
-       .p_encode    = (kxdreproc_t)nfs3_xdr_enc_##argtype##3args,      \
-       .p_decode    = (kxdrdproc_t)nfs3_xdr_dec_##restype##3res,       \
+       .p_encode    = nfs3_xdr_enc_##argtype##3args,                   \
+       .p_decode    = nfs3_xdr_dec_##restype##3res,                    \
        .p_arglen    = NFS3_##argtype##args_sz,                         \
        .p_replen    = NFS3_##restype##res_sz,                          \
        .p_timer     = timer,                                           \
@@ -2504,7 +2554,7 @@ static int nfs3_stat_to_errno(enum nfs_stat status)
        .p_name      = #proc,                                           \
        }
 
-struct rpc_procinfo    nfs3_procedures[] = {
+const struct rpc_procinfo nfs3_procedures[] = {
        PROC(GETATTR,           getattr,        getattr,        1),
        PROC(SETATTR,           setattr,        setattr,        0),
        PROC(LOOKUP,            lookup,         lookup,         2),
@@ -2528,18 +2578,20 @@ struct rpc_procinfo     nfs3_procedures[] = {
        PROC(COMMIT,            commit,         commit,         5),
 };
 
+static unsigned int nfs_version3_counts[ARRAY_SIZE(nfs3_procedures)];
 const struct rpc_version nfs_version3 = {
        .number                 = 3,
        .nrprocs                = ARRAY_SIZE(nfs3_procedures),
-       .procs                  = nfs3_procedures
+       .procs                  = nfs3_procedures,
+       .counts                 = nfs_version3_counts,
 };
 
 #ifdef CONFIG_NFS_V3_ACL
-static struct rpc_procinfo     nfs3_acl_procedures[] = {
+static const struct rpc_procinfo nfs3_acl_procedures[] = {
        [ACLPROC3_GETACL] = {
                .p_proc = ACLPROC3_GETACL,
-               .p_encode = (kxdreproc_t)nfs3_xdr_enc_getacl3args,
-               .p_decode = (kxdrdproc_t)nfs3_xdr_dec_getacl3res,
+               .p_encode = nfs3_xdr_enc_getacl3args,
+               .p_decode = nfs3_xdr_dec_getacl3res,
                .p_arglen = ACL3_getaclargs_sz,
                .p_replen = ACL3_getaclres_sz,
                .p_timer = 1,
@@ -2547,8 +2599,8 @@ static struct rpc_procinfo        nfs3_acl_procedures[] = {
        },
        [ACLPROC3_SETACL] = {
                .p_proc = ACLPROC3_SETACL,
-               .p_encode = (kxdreproc_t)nfs3_xdr_enc_setacl3args,
-               .p_decode = (kxdrdproc_t)nfs3_xdr_dec_setacl3res,
+               .p_encode = nfs3_xdr_enc_setacl3args,
+               .p_decode = nfs3_xdr_dec_setacl3res,
                .p_arglen = ACL3_setaclargs_sz,
                .p_replen = ACL3_setaclres_sz,
                .p_timer = 0,
@@ -2556,10 +2608,11 @@ static struct rpc_procinfo      nfs3_acl_procedures[] = {
        },
 };
 
+static unsigned int nfs3_acl_counts[ARRAY_SIZE(nfs3_acl_procedures)];
 const struct rpc_version nfsacl_version3 = {
        .number                 = 3,
-       .nrprocs                = sizeof(nfs3_acl_procedures)/
-                                 sizeof(nfs3_acl_procedures[0]),
+       .nrprocs                = ARRAY_SIZE(nfs3_acl_procedures),
        .procs                  = nfs3_acl_procedures,
+       .counts                 = nfs3_acl_counts,
 };
 #endif  /* CONFIG_NFS_V3_ACL */
index 319a47d..6c2db51 100644 (file)
@@ -146,7 +146,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
        loff_t pos_src = args->src_pos;
        loff_t pos_dst = args->dst_pos;
        size_t count = args->count;
-       int status;
+       ssize_t status;
 
        status = nfs4_set_rw_stateid(&args->src_stateid, src_lock->open_context,
                                     src_lock, FMODE_READ);
index 528362f..5ee1b0f 100644 (file)
                                         decode_getattr_maxsz)
 
 static void encode_fallocate(struct xdr_stream *xdr,
-                            struct nfs42_falloc_args *args)
+                            const struct nfs42_falloc_args *args)
 {
        encode_nfs4_stateid(xdr, &args->falloc_stateid);
        encode_uint64(xdr, args->falloc_offset);
@@ -120,7 +120,7 @@ static void encode_fallocate(struct xdr_stream *xdr,
 }
 
 static void encode_allocate(struct xdr_stream *xdr,
-                           struct nfs42_falloc_args *args,
+                           const struct nfs42_falloc_args *args,
                            struct compound_hdr *hdr)
 {
        encode_op_hdr(xdr, OP_ALLOCATE, decode_allocate_maxsz, hdr);
@@ -128,7 +128,7 @@ static void encode_allocate(struct xdr_stream *xdr,
 }
 
 static void encode_copy(struct xdr_stream *xdr,
-                       struct nfs42_copy_args *args,
+                       const struct nfs42_copy_args *args,
                        struct compound_hdr *hdr)
 {
        encode_op_hdr(xdr, OP_COPY, decode_copy_maxsz, hdr);
@@ -145,7 +145,7 @@ static void encode_copy(struct xdr_stream *xdr,
 }
 
 static void encode_deallocate(struct xdr_stream *xdr,
-                             struct nfs42_falloc_args *args,
+                             const struct nfs42_falloc_args *args,
                              struct compound_hdr *hdr)
 {
        encode_op_hdr(xdr, OP_DEALLOCATE, decode_deallocate_maxsz, hdr);
@@ -153,7 +153,7 @@ static void encode_deallocate(struct xdr_stream *xdr,
 }
 
 static void encode_seek(struct xdr_stream *xdr,
-                       struct nfs42_seek_args *args,
+                       const struct nfs42_seek_args *args,
                        struct compound_hdr *hdr)
 {
        encode_op_hdr(xdr, OP_SEEK, decode_seek_maxsz, hdr);
@@ -163,7 +163,7 @@ static void encode_seek(struct xdr_stream *xdr,
 }
 
 static void encode_layoutstats(struct xdr_stream *xdr,
-                              struct nfs42_layoutstat_args *args,
+                              const struct nfs42_layoutstat_args *args,
                               struct nfs42_layoutstat_devinfo *devinfo,
                               struct compound_hdr *hdr)
 {
@@ -191,7 +191,7 @@ static void encode_layoutstats(struct xdr_stream *xdr,
 }
 
 static void encode_clone(struct xdr_stream *xdr,
-                        struct nfs42_clone_args *args,
+                        const struct nfs42_clone_args *args,
                         struct compound_hdr *hdr)
 {
        __be32 *p;
@@ -210,8 +210,9 @@ static void encode_clone(struct xdr_stream *xdr,
  */
 static void nfs4_xdr_enc_allocate(struct rpc_rqst *req,
                                  struct xdr_stream *xdr,
-                                 struct nfs42_falloc_args *args)
+                                 const void *data)
 {
+       const struct nfs42_falloc_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -225,7 +226,7 @@ static void nfs4_xdr_enc_allocate(struct rpc_rqst *req,
 }
 
 static void encode_copy_commit(struct xdr_stream *xdr,
-                         struct nfs42_copy_args *args,
+                         const struct nfs42_copy_args *args,
                          struct compound_hdr *hdr)
 {
        __be32 *p;
@@ -241,8 +242,9 @@ static void encode_copy_commit(struct xdr_stream *xdr,
  */
 static void nfs4_xdr_enc_copy(struct rpc_rqst *req,
                              struct xdr_stream *xdr,
-                             struct nfs42_copy_args *args)
+                             const void *data)
 {
+       const struct nfs42_copy_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -262,8 +264,9 @@ static void nfs4_xdr_enc_copy(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   struct nfs42_falloc_args *args)
+                                   const void *data)
 {
+       const struct nfs42_falloc_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -281,8 +284,9 @@ static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_seek(struct rpc_rqst *req,
                              struct xdr_stream *xdr,
-                             struct nfs42_seek_args *args)
+                             const void *data)
 {
+       const struct nfs42_seek_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -299,8 +303,9 @@ static void nfs4_xdr_enc_seek(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_layoutstats(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    struct nfs42_layoutstat_args *args)
+                                    const void *data)
 {
+       const struct nfs42_layoutstat_args *args = data;
        int i;
 
        struct compound_hdr hdr = {
@@ -321,8 +326,9 @@ static void nfs4_xdr_enc_layoutstats(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_clone(struct rpc_rqst *req,
                               struct xdr_stream *xdr,
-                              struct nfs42_clone_args *args)
+                              const void *data)
 {
+       const struct nfs42_clone_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -448,8 +454,9 @@ static int decode_clone(struct xdr_stream *xdr)
  */
 static int nfs4_xdr_dec_allocate(struct rpc_rqst *rqstp,
                                 struct xdr_stream *xdr,
-                                struct nfs42_falloc_res *res)
+                                void *data)
 {
+       struct nfs42_falloc_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -475,8 +482,9 @@ out:
  */
 static int nfs4_xdr_dec_copy(struct rpc_rqst *rqstp,
                             struct xdr_stream *xdr,
-                            struct nfs42_copy_res *res)
+                            void *data)
 {
+       struct nfs42_copy_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -508,8 +516,9 @@ out:
  */
 static int nfs4_xdr_dec_deallocate(struct rpc_rqst *rqstp,
                                   struct xdr_stream *xdr,
-                                  struct nfs42_falloc_res *res)
+                                  void *data)
 {
+       struct nfs42_falloc_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -535,8 +544,9 @@ out:
  */
 static int nfs4_xdr_dec_seek(struct rpc_rqst *rqstp,
                             struct xdr_stream *xdr,
-                            struct nfs42_seek_res *res)
+                            void *data)
 {
+       struct nfs42_seek_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -559,8 +569,9 @@ out:
  */
 static int nfs4_xdr_dec_layoutstats(struct rpc_rqst *rqstp,
                                    struct xdr_stream *xdr,
-                                   struct nfs42_layoutstat_res *res)
+                                   void *data)
 {
+       struct nfs42_layoutstat_res *res = data;
        struct compound_hdr hdr;
        int status, i;
 
@@ -589,8 +600,9 @@ out:
  */
 static int nfs4_xdr_dec_clone(struct rpc_rqst *rqstp,
                              struct xdr_stream *xdr,
-                             struct nfs42_clone_res *res)
+                             void *data)
 {
+       struct nfs42_clone_res *res = data;
        struct compound_hdr hdr;
        int status;
 
index af285cc..40bd05f 100644 (file)
@@ -493,13 +493,13 @@ static inline void nfs4_unregister_sysctl(void)
 #endif
 
 /* nfs4xdr.c */
-extern struct rpc_procinfo nfs4_procedures[];
+extern const struct rpc_procinfo nfs4_procedures[];
 
 struct nfs4_mount_data;
 
 /* callback_xdr.c */
-extern struct svc_version nfs4_callback_version1;
-extern struct svc_version nfs4_callback_version4;
+extern const struct svc_version nfs4_callback_version1;
+extern const struct svc_version nfs4_callback_version4;
 
 static inline void nfs4_stateid_copy(nfs4_stateid *dst, const nfs4_stateid *src)
 {
index 66776f0..50566ac 100644 (file)
@@ -414,6 +414,7 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
        if (clp != old)
                clp->cl_preserve_clid = true;
        nfs_put_client(clp);
+       clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags);
        return old;
 
 error:
@@ -852,6 +853,8 @@ static int nfs4_set_client(struct nfs_server *server,
                set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
        if (server->options & NFS_OPTION_MIGRATION)
                set_bit(NFS_CS_MIGRATION, &cl_init.init_flags);
+       if (test_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status))
+               set_bit(NFS_CS_TSM_POSSIBLE, &cl_init.init_flags);
 
        /* Allocate or find a client reference we can use */
        clp = nfs_get_client(&cl_init);
@@ -1212,9 +1215,11 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
                return -EAFNOSUPPORT;
 
        nfs_server_remove_lists(server);
+       set_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
        error = nfs4_set_client(server, hostname, sap, salen, buf,
                                clp->cl_proto, clnt->cl_timeout,
                                clp->cl_minorversion, net);
+       clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
        nfs_put_client(clp);
        if (error != 0) {
                nfs_server_insert_lists(server);
index 835c163..dd5d27d 100644 (file)
@@ -364,7 +364,8 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *typ
                ret = -EINVAL;
        } else {
                ret = kstrtol(id_str, 10, &id_long);
-               *id = (__u32)id_long;
+               if (!ret)
+                       *id = (__u32)id_long;
        }
        return ret;
 }
index 98b0b66..18ca687 100644 (file)
@@ -275,6 +275,7 @@ const u32 nfs4_fs_locations_bitmap[3] = {
 static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
                struct nfs4_readdir_arg *readdir)
 {
+       unsigned int attrs = FATTR4_WORD0_FILEID | FATTR4_WORD0_TYPE;
        __be32 *start, *p;
 
        if (cookie > 2) {
@@ -305,8 +306,9 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
                memcpy(p, ".\0\0\0", 4);                        /* entry */
                p++;
                *p++ = xdr_one;                         /* bitmap length */
-               *p++ = htonl(FATTR4_WORD0_FILEID);             /* bitmap */
-               *p++ = htonl(8);              /* attribute buffer length */
+               *p++ = htonl(attrs);                           /* bitmap */
+               *p++ = htonl(12);             /* attribute buffer length */
+               *p++ = htonl(NF4DIR);
                p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry)));
        }
        
@@ -317,8 +319,9 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
        memcpy(p, "..\0\0", 4);                         /* entry */
        p++;
        *p++ = xdr_one;                         /* bitmap length */
-       *p++ = htonl(FATTR4_WORD0_FILEID);             /* bitmap */
-       *p++ = htonl(8);              /* attribute buffer length */
+       *p++ = htonl(attrs);                           /* bitmap */
+       *p++ = htonl(12);             /* attribute buffer length */
+       *p++ = htonl(NF4DIR);
        p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry->d_parent)));
 
        readdir->pgbase = (char *)p - (char *)start;
@@ -1034,11 +1037,11 @@ struct nfs4_opendata {
        struct nfs4_state *state;
        struct iattr attrs;
        unsigned long timestamp;
-       unsigned int rpc_done : 1;
-       unsigned int file_created : 1;
-       unsigned int is_recover : 1;
+       bool rpc_done;
+       bool file_created;
+       bool is_recover;
+       bool cancelled;
        int rpc_status;
-       int cancelled;
 };
 
 static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
@@ -1962,7 +1965,7 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
                nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid);
                nfs_confirm_seqid(&data->owner->so_seqid, 0);
                renew_lease(data->o_res.server, data->timestamp);
-               data->rpc_done = 1;
+               data->rpc_done = true;
        }
 }
 
@@ -1972,7 +1975,7 @@ static void nfs4_open_confirm_release(void *calldata)
        struct nfs4_state *state = NULL;
 
        /* If this request hasn't been cancelled, do nothing */
-       if (data->cancelled == 0)
+       if (!data->cancelled)
                goto out_free;
        /* In case of error, no cleanup! */
        if (!data->rpc_done)
@@ -2015,7 +2018,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
 
        nfs4_init_sequence(&data->c_arg.seq_args, &data->c_res.seq_res, 1);
        kref_get(&data->kref);
-       data->rpc_done = 0;
+       data->rpc_done = false;
        data->rpc_status = 0;
        data->timestamp = jiffies;
        if (data->is_recover)
@@ -2025,7 +2028,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
                return PTR_ERR(task);
        status = rpc_wait_for_completion_task(task);
        if (status != 0) {
-               data->cancelled = 1;
+               data->cancelled = true;
                smp_wmb();
        } else
                status = data->rpc_status;
@@ -2124,7 +2127,7 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
                if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM))
                        nfs_confirm_seqid(&data->owner->so_seqid, 0);
        }
-       data->rpc_done = 1;
+       data->rpc_done = true;
 }
 
 static void nfs4_open_release(void *calldata)
@@ -2133,7 +2136,7 @@ static void nfs4_open_release(void *calldata)
        struct nfs4_state *state = NULL;
 
        /* If this request hasn't been cancelled, do nothing */
-       if (data->cancelled == 0)
+       if (!data->cancelled)
                goto out_free;
        /* In case of error, no cleanup! */
        if (data->rpc_status != 0 || !data->rpc_done)
@@ -2179,20 +2182,20 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
 
        nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
        kref_get(&data->kref);
-       data->rpc_done = 0;
+       data->rpc_done = false;
        data->rpc_status = 0;
-       data->cancelled = 0;
-       data->is_recover = 0;
+       data->cancelled = false;
+       data->is_recover = false;
        if (isrecover) {
                nfs4_set_sequence_privileged(&o_arg->seq_args);
-               data->is_recover = 1;
+               data->is_recover = true;
        }
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
        status = rpc_wait_for_completion_task(task);
        if (status != 0) {
-               data->cancelled = 1;
+               data->cancelled = true;
                smp_wmb();
        } else
                status = data->rpc_status;
@@ -2233,7 +2236,7 @@ static int nfs4_opendata_access(struct rpc_cred *cred,
                                int openflags)
 {
        struct nfs_access_entry cache;
-       u32 mask;
+       u32 mask, flags;
 
        /* access call failed or for some reason the server doesn't
         * support any access modes -- defer access call until later */
@@ -2247,16 +2250,20 @@ static int nfs4_opendata_access(struct rpc_cred *cred,
         */
        if (openflags & __FMODE_EXEC) {
                /* ONLY check for exec rights */
-               mask = MAY_EXEC;
+               if (S_ISDIR(state->inode->i_mode))
+                       mask = NFS4_ACCESS_LOOKUP;
+               else
+                       mask = NFS4_ACCESS_EXECUTE;
        } else if ((fmode & FMODE_READ) && !opendata->file_created)
-               mask = MAY_READ;
+               mask = NFS4_ACCESS_READ;
 
        cache.cred = cred;
        cache.jiffies = jiffies;
        nfs_access_set_mask(&cache, opendata->o_res.access_result);
        nfs_access_add_cache(state->inode, &cache);
 
-       if ((mask & ~cache.mask & (MAY_READ | MAY_EXEC)) == 0)
+       flags = NFS4_ACCESS_READ | NFS4_ACCESS_EXECUTE | NFS4_ACCESS_LOOKUP;
+       if ((mask & ~cache.mask & flags) == 0)
                return 0;
 
        return -EACCES;
@@ -2287,9 +2294,9 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
 
        if (o_arg->open_flags & O_CREAT) {
                if (o_arg->open_flags & O_EXCL)
-                       data->file_created = 1;
+                       data->file_created = true;
                else if (o_res->cinfo.before != o_res->cinfo.after)
-                       data->file_created = 1;
+                       data->file_created = true;
                if (data->file_created || dir->i_version != o_res->cinfo.after)
                        update_changeattr(dir, &o_res->cinfo,
                                        o_res->f_attr->time_start);
@@ -3803,6 +3810,54 @@ nfs4_proc_lookup_mountpoint(struct inode *dir, const struct qstr *name,
        return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client;
 }
 
+static int _nfs4_proc_lookupp(struct inode *inode,
+               struct nfs_fh *fhandle, struct nfs_fattr *fattr,
+               struct nfs4_label *label)
+{
+       struct rpc_clnt *clnt = NFS_CLIENT(inode);
+       struct nfs_server *server = NFS_SERVER(inode);
+       int                    status;
+       struct nfs4_lookupp_arg args = {
+               .bitmask = server->attr_bitmask,
+               .fh = NFS_FH(inode),
+       };
+       struct nfs4_lookupp_res res = {
+               .server = server,
+               .fattr = fattr,
+               .label = label,
+               .fh = fhandle,
+       };
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUPP],
+               .rpc_argp = &args,
+               .rpc_resp = &res,
+       };
+
+       args.bitmask = nfs4_bitmask(server, label);
+
+       nfs_fattr_init(fattr);
+
+       dprintk("NFS call  lookupp ino=0x%lx\n", inode->i_ino);
+       status = nfs4_call_sync(clnt, server, &msg, &args.seq_args,
+                               &res.seq_res, 0);
+       dprintk("NFS reply lookupp: %d\n", status);
+       return status;
+}
+
+static int nfs4_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle,
+                            struct nfs_fattr *fattr, struct nfs4_label *label)
+{
+       struct nfs4_exception exception = { };
+       int err;
+       do {
+               err = _nfs4_proc_lookupp(inode, fhandle, fattr, label);
+               trace_nfs4_lookupp(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
+                               &exception);
+       } while (exception.retry);
+       return err;
+}
+
 static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
 {
        struct nfs_server *server = NFS_SERVER(inode);
@@ -4273,7 +4328,7 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 }
 
 static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
-               u64 cookie, struct page **pages, unsigned int count, int plus)
+               u64 cookie, struct page **pages, unsigned int count, bool plus)
 {
        struct inode            *dir = d_inode(dentry);
        struct nfs4_readdir_arg args = {
@@ -4311,7 +4366,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 }
 
 static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
-               u64 cookie, struct page **pages, unsigned int count, int plus)
+               u64 cookie, struct page **pages, unsigned int count, bool plus)
 {
        struct nfs4_exception exception = { };
        int err;
@@ -6135,7 +6190,7 @@ static void nfs4_lock_release(void *calldata)
 
        dprintk("%s: begin!\n", __func__);
        nfs_free_seqid(data->arg.open_seqid);
-       if (data->cancelled != 0) {
+       if (data->cancelled) {
                struct rpc_task *task;
                task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
                                data->arg.lock_seqid);
@@ -6218,7 +6273,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
                        nfs4_handle_setlk_error(data->server, data->lsp,
                                        data->arg.new_lock_owner, ret);
        } else
-               data->cancelled = 1;
+               data->cancelled = true;
        rpc_put_task(task);
        dprintk("%s: done, ret = %d!\n", __func__, ret);
        trace_nfs4_set_lock(fl, state, &data->res.stateid, cmd, ret);
@@ -6441,7 +6496,7 @@ nfs4_retry_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
                set_current_state(TASK_INTERRUPTIBLE);
                spin_unlock_irqrestore(&q->lock, flags);
 
-               freezable_schedule_timeout_interruptible(NFS4_LOCK_MAXTIMEOUT);
+               freezable_schedule_timeout(NFS4_LOCK_MAXTIMEOUT);
        }
 
        finish_wait(q, &wait);
@@ -7376,12 +7431,11 @@ static void nfs4_exchange_id_done(struct rpc_task *task, void *data)
        if (status == 0) {
                clp->cl_clientid = cdata->res.clientid;
                clp->cl_exchange_flags = cdata->res.flags;
+               clp->cl_seqid = cdata->res.seqid;
                /* Client ID is not confirmed */
-               if (!(cdata->res.flags & EXCHGID4_FLAG_CONFIRMED_R)) {
+               if (!(cdata->res.flags & EXCHGID4_FLAG_CONFIRMED_R))
                        clear_bit(NFS4_SESSION_ESTABLISHED,
-                       &clp->cl_session->session_state);
-                       clp->cl_seqid = cdata->res.seqid;
-               }
+                                 &clp->cl_session->session_state);
 
                kfree(clp->cl_serverowner);
                clp->cl_serverowner = cdata->res.server_owner;
@@ -9313,6 +9367,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .getattr        = nfs4_proc_getattr,
        .setattr        = nfs4_proc_setattr,
        .lookup         = nfs4_proc_lookup,
+       .lookupp        = nfs4_proc_lookupp,
        .access         = nfs4_proc_access,
        .readlink       = nfs4_proc_readlink,
        .create         = nfs4_proc_create,
index cbf82b0..0378e22 100644 (file)
@@ -352,11 +352,17 @@ int nfs41_discover_server_trunking(struct nfs_client *clp,
        if (clp != *result)
                return 0;
 
-       /* Purge state if the client id was established in a prior instance */
-       if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R)
-               set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
-       else
-               set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+       /*
+        * Purge state if the client id was established in a prior
+        * instance and the client id could not have arrived on the
+        * server via Transparent State Migration.
+        */
+       if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R) {
+               if (!test_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags))
+                       set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
+               else
+                       set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+       }
        nfs4_schedule_state_manager(clp);
        status = nfs_wait_client_init_complete(clp);
        if (status < 0)
index 845d0ea..be1da19 100644 (file)
@@ -891,6 +891,35 @@ DEFINE_NFS4_LOOKUP_EVENT(nfs4_remove);
 DEFINE_NFS4_LOOKUP_EVENT(nfs4_get_fs_locations);
 DEFINE_NFS4_LOOKUP_EVENT(nfs4_secinfo);
 
+TRACE_EVENT(nfs4_lookupp,
+               TP_PROTO(
+                       const struct inode *inode,
+                       int error
+               ),
+
+               TP_ARGS(inode, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u64, ino)
+                       __field(int, error)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->ino = NFS_FILEID(inode);
+                       __entry->error = error;
+               ),
+
+               TP_printk(
+                       "error=%d (%s) inode=%02x:%02x:%llu",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->ino
+               )
+);
+
 TRACE_EVENT(nfs4_rename,
                TP_PROTO(
                        const struct inode *olddir,
index 3aebfdc..fa3eb36 100644 (file)
@@ -159,6 +159,8 @@ static int nfs4_stat_to_errno(int);
                                (op_decode_hdr_maxsz)
 #define encode_lookup_maxsz    (op_encode_hdr_maxsz + nfs4_name_maxsz)
 #define decode_lookup_maxsz    (op_decode_hdr_maxsz)
+#define encode_lookupp_maxsz   (op_encode_hdr_maxsz)
+#define decode_lookupp_maxsz   (op_decode_hdr_maxsz)
 #define encode_share_access_maxsz \
                                (2)
 #define encode_createmode_maxsz        (1 + encode_attrs_maxsz + encode_verifier_maxsz)
@@ -618,6 +620,18 @@ static int nfs4_stat_to_errno(int);
                                decode_lookup_maxsz + \
                                decode_getattr_maxsz + \
                                decode_getfh_maxsz)
+#define NFS4_enc_lookupp_sz    (compound_encode_hdr_maxsz + \
+                               encode_sequence_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_lookupp_maxsz + \
+                               encode_getattr_maxsz + \
+                               encode_getfh_maxsz)
+#define NFS4_dec_lookupp_sz    (compound_decode_hdr_maxsz + \
+                               decode_sequence_maxsz + \
+                               decode_putfh_maxsz + \
+                               decode_lookupp_maxsz + \
+                               decode_getattr_maxsz + \
+                               decode_getfh_maxsz)
 #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
                                encode_sequence_maxsz + \
                                encode_putrootfh_maxsz + \
@@ -1368,6 +1382,11 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc
        encode_string(xdr, name->len, name->name);
 }
 
+static void encode_lookupp(struct xdr_stream *xdr, struct compound_hdr *hdr)
+{
+       encode_op_hdr(xdr, OP_LOOKUPP, decode_lookupp_maxsz, hdr);
+}
+
 static void encode_share_access(struct xdr_stream *xdr, u32 share_access)
 {
        __be32 *p;
@@ -1651,7 +1670,8 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 }
 
 static void
-encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compound_hdr *hdr)
+encode_setacl(struct xdr_stream *xdr, const struct nfs_setaclargs *arg,
+               struct compound_hdr *hdr)
 {
        __be32 *p;
 
@@ -1735,7 +1755,7 @@ static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, stru
 #if defined(CONFIG_NFS_V4_1)
 /* NFSv4.1 operations */
 static void encode_bind_conn_to_session(struct xdr_stream *xdr,
-                                  struct nfs41_bind_conn_to_session_args *args,
+                                  const struct nfs41_bind_conn_to_session_args *args,
                                   struct compound_hdr *hdr)
 {
        __be32 *p;
@@ -1748,7 +1768,7 @@ static void encode_bind_conn_to_session(struct xdr_stream *xdr,
        *p = (args->use_conn_in_rdma_mode) ? cpu_to_be32(1) : cpu_to_be32(0);
 }
 
-static void encode_op_map(struct xdr_stream *xdr, struct nfs4_op_map *op_map)
+static void encode_op_map(struct xdr_stream *xdr, const struct nfs4_op_map *op_map)
 {
        unsigned int i;
        encode_uint32(xdr, NFS4_OP_MAP_NUM_WORDS);
@@ -1757,7 +1777,7 @@ static void encode_op_map(struct xdr_stream *xdr, struct nfs4_op_map *op_map)
 }
 
 static void encode_exchange_id(struct xdr_stream *xdr,
-                              struct nfs41_exchange_id_args *args,
+                              const struct nfs41_exchange_id_args *args,
                               struct compound_hdr *hdr)
 {
        __be32 *p;
@@ -1809,7 +1829,7 @@ static void encode_exchange_id(struct xdr_stream *xdr,
 }
 
 static void encode_create_session(struct xdr_stream *xdr,
-                                 struct nfs41_create_session_args *args,
+                                 const struct nfs41_create_session_args *args,
                                  struct compound_hdr *hdr)
 {
        __be32 *p;
@@ -1862,7 +1882,7 @@ static void encode_create_session(struct xdr_stream *xdr,
 }
 
 static void encode_destroy_session(struct xdr_stream *xdr,
-                                  struct nfs4_session *session,
+                                  const struct nfs4_session *session,
                                   struct compound_hdr *hdr)
 {
        encode_op_hdr(xdr, OP_DESTROY_SESSION, decode_destroy_session_maxsz, hdr);
@@ -1878,7 +1898,7 @@ static void encode_destroy_clientid(struct xdr_stream *xdr,
 }
 
 static void encode_reclaim_complete(struct xdr_stream *xdr,
-                                   struct nfs41_reclaim_complete_args *args,
+                                   const struct nfs41_reclaim_complete_args *args,
                                    struct compound_hdr *hdr)
 {
        encode_op_hdr(xdr, OP_RECLAIM_COMPLETE, decode_reclaim_complete_maxsz, hdr);
@@ -1974,7 +1994,7 @@ encode_layoutget(struct xdr_stream *xdr,
 static int
 encode_layoutcommit(struct xdr_stream *xdr,
                    struct inode *inode,
-                   struct nfs4_layoutcommit_args *args,
+                   const struct nfs4_layoutcommit_args *args,
                    struct compound_hdr *hdr)
 {
        __be32 *p;
@@ -2044,7 +2064,7 @@ encode_secinfo_no_name(struct xdr_stream *xdr,
 }
 
 static void encode_test_stateid(struct xdr_stream *xdr,
-                               struct nfs41_test_stateid_args *args,
+                               const struct nfs41_test_stateid_args *args,
                                struct compound_hdr *hdr)
 {
        encode_op_hdr(xdr, OP_TEST_STATEID, decode_test_stateid_maxsz, hdr);
@@ -2053,7 +2073,7 @@ static void encode_test_stateid(struct xdr_stream *xdr,
 }
 
 static void encode_free_stateid(struct xdr_stream *xdr,
-                               struct nfs41_free_stateid_args *args,
+                               const struct nfs41_free_stateid_args *args,
                                struct compound_hdr *hdr)
 {
        encode_op_hdr(xdr, OP_FREE_STATEID, decode_free_stateid_maxsz, hdr);
@@ -2086,8 +2106,9 @@ static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args)
  * Encode an ACCESS request
  */
 static void nfs4_xdr_enc_access(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               const struct nfs4_accessargs *args)
+                               const void *data)
 {
+       const struct nfs4_accessargs *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2104,8 +2125,9 @@ static void nfs4_xdr_enc_access(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode LOOKUP request
  */
 static void nfs4_xdr_enc_lookup(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               const struct nfs4_lookup_arg *args)
+                               const void *data)
 {
+       const struct nfs4_lookup_arg *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2120,12 +2142,33 @@ static void nfs4_xdr_enc_lookup(struct rpc_rqst *req, struct xdr_stream *xdr,
 }
 
 /*
+ * Encode LOOKUPP request
+ */
+static void nfs4_xdr_enc_lookupp(struct rpc_rqst *req, struct xdr_stream *xdr,
+               const void *data)
+{
+       const struct nfs4_lookupp_arg *args = data;
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_sequence(xdr, &args->seq_args, &hdr);
+       encode_putfh(xdr, args->fh, &hdr);
+       encode_lookupp(xdr, &hdr);
+       encode_getfh(xdr, &hdr);
+       encode_getfattr(xdr, args->bitmask, &hdr);
+       encode_nops(&hdr);
+}
+
+/*
  * Encode LOOKUP_ROOT request
  */
 static void nfs4_xdr_enc_lookup_root(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    const struct nfs4_lookup_root_arg *args)
+                                    const void *data)
 {
+       const struct nfs4_lookup_root_arg *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2142,8 +2185,9 @@ static void nfs4_xdr_enc_lookup_root(struct rpc_rqst *req,
  * Encode REMOVE request
  */
 static void nfs4_xdr_enc_remove(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               const struct nfs_removeargs *args)
+                               const void *data)
 {
+       const struct nfs_removeargs *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2159,8 +2203,9 @@ static void nfs4_xdr_enc_remove(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode RENAME request
  */
 static void nfs4_xdr_enc_rename(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               const struct nfs_renameargs *args)
+                               const void *data)
 {
+       const struct nfs_renameargs *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2178,8 +2223,9 @@ static void nfs4_xdr_enc_rename(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode LINK request
  */
 static void nfs4_xdr_enc_link(struct rpc_rqst *req, struct xdr_stream *xdr,
-                            const struct nfs4_link_arg *args)
+                             const void *data)
 {
+       const struct nfs4_link_arg *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2199,8 +2245,9 @@ static void nfs4_xdr_enc_link(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode CREATE request
  */
 static void nfs4_xdr_enc_create(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               const struct nfs4_create_arg *args)
+                               const void *data)
 {
+       const struct nfs4_create_arg *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2218,8 +2265,10 @@ static void nfs4_xdr_enc_create(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode SYMLINK request
  */
 static void nfs4_xdr_enc_symlink(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                const struct nfs4_create_arg *args)
+                                const void *data)
 {
+       const struct nfs4_create_arg *args = data;
+
        nfs4_xdr_enc_create(req, xdr, args);
 }
 
@@ -2227,8 +2276,9 @@ static void nfs4_xdr_enc_symlink(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode GETATTR request
  */
 static void nfs4_xdr_enc_getattr(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                const struct nfs4_getattr_arg *args)
+                                const void *data)
 {
+       const struct nfs4_getattr_arg *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2244,8 +2294,9 @@ static void nfs4_xdr_enc_getattr(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode a CLOSE request
  */
 static void nfs4_xdr_enc_close(struct rpc_rqst *req, struct xdr_stream *xdr,
-                              struct nfs_closeargs *args)
+                              const void *data)
 {
+       const struct nfs_closeargs *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2265,8 +2316,9 @@ static void nfs4_xdr_enc_close(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode an OPEN request
  */
 static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr,
-                             struct nfs_openargs *args)
+                             const void *data)
 {
+       const struct nfs_openargs *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2287,8 +2339,9 @@ static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr,
  */
 static void nfs4_xdr_enc_open_confirm(struct rpc_rqst *req,
                                      struct xdr_stream *xdr,
-                                     struct nfs_open_confirmargs *args)
+                                     const void *data)
 {
+       const struct nfs_open_confirmargs *args = data;
        struct compound_hdr hdr = {
                .nops   = 0,
        };
@@ -2304,8 +2357,9 @@ static void nfs4_xdr_enc_open_confirm(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    struct nfs_openargs *args)
+                                    const void *data)
 {
+       const struct nfs_openargs *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2325,8 +2379,9 @@ static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req,
                                        struct xdr_stream *xdr,
-                                       struct nfs_closeargs *args)
+                                       const void *data)
 {
+       const struct nfs_closeargs *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2344,8 +2399,9 @@ static void nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req,
  * Encode a LOCK request
  */
 static void nfs4_xdr_enc_lock(struct rpc_rqst *req, struct xdr_stream *xdr,
-                             struct nfs_lock_args *args)
+                             const void *data)
 {
+       const struct nfs_lock_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2361,8 +2417,9 @@ static void nfs4_xdr_enc_lock(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode a LOCKT request
  */
 static void nfs4_xdr_enc_lockt(struct rpc_rqst *req, struct xdr_stream *xdr,
-                              struct nfs_lockt_args *args)
+                              const void *data)
 {
+       const struct nfs_lockt_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2378,8 +2435,9 @@ static void nfs4_xdr_enc_lockt(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode a LOCKU request
  */
 static void nfs4_xdr_enc_locku(struct rpc_rqst *req, struct xdr_stream *xdr,
-                              struct nfs_locku_args *args)
+                              const void *data)
 {
+       const struct nfs_locku_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2393,8 +2451,9 @@ static void nfs4_xdr_enc_locku(struct rpc_rqst *req, struct xdr_stream *xdr,
 
 static void nfs4_xdr_enc_release_lockowner(struct rpc_rqst *req,
                                           struct xdr_stream *xdr,
-                                       struct nfs_release_lockowner_args *args)
+                                          const void *data)
 {
+       const struct nfs_release_lockowner_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = 0,
        };
@@ -2408,8 +2467,9 @@ static void nfs4_xdr_enc_release_lockowner(struct rpc_rqst *req,
  * Encode a READLINK request
  */
 static void nfs4_xdr_enc_readlink(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                 const struct nfs4_readlink *args)
+                                 const void *data)
 {
+       const struct nfs4_readlink *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2428,8 +2488,9 @@ static void nfs4_xdr_enc_readlink(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode a READDIR request
  */
 static void nfs4_xdr_enc_readdir(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                const struct nfs4_readdir_arg *args)
+                                const void *data)
 {
+       const struct nfs4_readdir_arg *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2451,8 +2512,9 @@ static void nfs4_xdr_enc_readdir(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode a READ request
  */
 static void nfs4_xdr_enc_read(struct rpc_rqst *req, struct xdr_stream *xdr,
-                             struct nfs_pgio_args *args)
+                             const void *data)
 {
+       const struct nfs_pgio_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2472,8 +2534,9 @@ static void nfs4_xdr_enc_read(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode an SETATTR request
  */
 static void nfs4_xdr_enc_setattr(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                struct nfs_setattrargs *args)
+                                const void *data)
 {
+       const struct nfs_setattrargs *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2490,8 +2553,9 @@ static void nfs4_xdr_enc_setattr(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode a GETACL request
  */
 static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               struct nfs_getaclargs *args)
+                               const void *data)
 {
+       const struct nfs_getaclargs *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2513,8 +2577,9 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Encode a WRITE request
  */
 static void nfs4_xdr_enc_write(struct rpc_rqst *req, struct xdr_stream *xdr,
-                              struct nfs_pgio_args *args)
+                              const void *data)
 {
+       const struct nfs_pgio_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2533,8 +2598,9 @@ static void nfs4_xdr_enc_write(struct rpc_rqst *req, struct xdr_stream *xdr,
  *  a COMMIT request
  */
 static void nfs4_xdr_enc_commit(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               struct nfs_commitargs *args)
+                               const void *data)
 {
+       const struct nfs_commitargs *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2550,8 +2616,9 @@ static void nfs4_xdr_enc_commit(struct rpc_rqst *req, struct xdr_stream *xdr,
  * FSINFO request
  */
 static void nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               struct nfs4_fsinfo_arg *args)
+                               const void *data)
 {
+       const struct nfs4_fsinfo_arg *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2567,8 +2634,9 @@ static void nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, struct xdr_stream *xdr,
  * a PATHCONF request
  */
 static void nfs4_xdr_enc_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                 const struct nfs4_pathconf_arg *args)
+                                 const void *data)
 {
+       const struct nfs4_pathconf_arg *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2585,8 +2653,9 @@ static void nfs4_xdr_enc_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr,
  * a STATFS request
  */
 static void nfs4_xdr_enc_statfs(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               const struct nfs4_statfs_arg *args)
+                               const void *data)
 {
+       const struct nfs4_statfs_arg *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2604,8 +2673,9 @@ static void nfs4_xdr_enc_statfs(struct rpc_rqst *req, struct xdr_stream *xdr,
  */
 static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    struct nfs4_server_caps_arg *args)
+                                    const void *data)
 {
+       const struct nfs4_server_caps_arg *args = data;
        const u32 *bitmask = args->bitmask;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
@@ -2622,8 +2692,10 @@ static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req,
  * a RENEW request
  */
 static void nfs4_xdr_enc_renew(struct rpc_rqst *req, struct xdr_stream *xdr,
-                              struct nfs_client *clp)
+                              const void *data)
+
 {
+       const struct nfs_client *clp = data;
        struct compound_hdr hdr = {
                .nops   = 0,
        };
@@ -2638,8 +2710,9 @@ static void nfs4_xdr_enc_renew(struct rpc_rqst *req, struct xdr_stream *xdr,
  */
 static void nfs4_xdr_enc_setclientid(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    struct nfs4_setclientid *sc)
+                                    const void *data)
 {
+       const struct nfs4_setclientid *sc = data;
        struct compound_hdr hdr = {
                .nops   = 0,
        };
@@ -2654,8 +2727,9 @@ static void nfs4_xdr_enc_setclientid(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
                                             struct xdr_stream *xdr,
-                                            struct nfs4_setclientid_res *arg)
+                                            const void *data)
 {
+       const struct nfs4_setclientid_res *arg = data;
        struct compound_hdr hdr = {
                .nops   = 0,
        };
@@ -2670,8 +2744,9 @@ static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_delegreturn(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    const struct nfs4_delegreturnargs *args)
+                                    const void *data)
 {
+       const struct nfs4_delegreturnargs *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2692,8 +2767,9 @@ static void nfs4_xdr_enc_delegreturn(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,
                                      struct xdr_stream *xdr,
-                                     struct nfs4_fs_locations_arg *args)
+                                     const void *data)
 {
+       const struct nfs4_fs_locations_arg *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2715,8 +2791,8 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,
        }
 
        /* Set up reply kvec to capture returned fs_locations array. */
-       xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page,
-                       0, PAGE_SIZE);
+       xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
+                        (struct page **)&args->page, 0, PAGE_SIZE);
        encode_nops(&hdr);
 }
 
@@ -2725,8 +2801,9 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req,
                                struct xdr_stream *xdr,
-                               struct nfs4_secinfo_arg *args)
+                               const void *data)
 {
+       const struct nfs4_secinfo_arg *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2743,8 +2820,9 @@ static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_fsid_present(struct rpc_rqst *req,
                                      struct xdr_stream *xdr,
-                                     struct nfs4_fsid_present_arg *args)
+                                     const void *data)
 {
+       const struct nfs4_fsid_present_arg *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2764,8 +2842,9 @@ static void nfs4_xdr_enc_fsid_present(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_bind_conn_to_session(struct rpc_rqst *req,
                                struct xdr_stream *xdr,
-                               struct nfs41_bind_conn_to_session_args *args)
+                               const void *data)
 {
+       const struct nfs41_bind_conn_to_session_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = args->client->cl_mvops->minor_version,
        };
@@ -2780,8 +2859,9 @@ static void nfs4_xdr_enc_bind_conn_to_session(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_exchange_id(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    struct nfs41_exchange_id_args *args)
+                                    const void *data)
 {
+       const struct nfs41_exchange_id_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = args->client->cl_mvops->minor_version,
        };
@@ -2796,8 +2876,9 @@ static void nfs4_xdr_enc_exchange_id(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_create_session(struct rpc_rqst *req,
                                        struct xdr_stream *xdr,
-                                       struct nfs41_create_session_args *args)
+                                       const void *data)
 {
+       const struct nfs41_create_session_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = args->client->cl_mvops->minor_version,
        };
@@ -2812,8 +2893,9 @@ static void nfs4_xdr_enc_create_session(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_destroy_session(struct rpc_rqst *req,
                                         struct xdr_stream *xdr,
-                                        struct nfs4_session *session)
+                                        const void *data)
 {
+       const struct nfs4_session *session = data;
        struct compound_hdr hdr = {
                .minorversion = session->clp->cl_mvops->minor_version,
        };
@@ -2828,8 +2910,9 @@ static void nfs4_xdr_enc_destroy_session(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_destroy_clientid(struct rpc_rqst *req,
                                         struct xdr_stream *xdr,
-                                        struct nfs_client *clp)
+                                        const void *data)
 {
+       const struct nfs_client *clp = data;
        struct compound_hdr hdr = {
                .minorversion = clp->cl_mvops->minor_version,
        };
@@ -2843,8 +2926,9 @@ static void nfs4_xdr_enc_destroy_clientid(struct rpc_rqst *req,
  * a SEQUENCE request
  */
 static void nfs4_xdr_enc_sequence(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                 struct nfs4_sequence_args *args)
+                                 const void *data)
 {
+       const struct nfs4_sequence_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(args),
        };
@@ -2859,8 +2943,9 @@ static void nfs4_xdr_enc_sequence(struct rpc_rqst *req, struct xdr_stream *xdr,
  */
 static void nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req,
                                        struct xdr_stream *xdr,
-                                       struct nfs4_get_lease_time_args *args)
+                                       const void *data)
 {
+       const struct nfs4_get_lease_time_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->la_seq_args),
        };
@@ -2878,8 +2963,9 @@ static void nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req,
                                          struct xdr_stream *xdr,
-                               struct nfs41_reclaim_complete_args *args)
+                                         const void *data)
 {
+       const struct nfs41_reclaim_complete_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args)
        };
@@ -2895,8 +2981,9 @@ static void nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_getdeviceinfo(struct rpc_rqst *req,
                                       struct xdr_stream *xdr,
-                                      struct nfs4_getdeviceinfo_args *args)
+                                      const void *data)
 {
+       const struct nfs4_getdeviceinfo_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2919,8 +3006,9 @@ static void nfs4_xdr_enc_getdeviceinfo(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  struct nfs4_layoutget_args *args)
+                                  const void *data)
 {
+       const struct nfs4_layoutget_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2941,8 +3029,9 @@ static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req,
                                      struct xdr_stream *xdr,
-                                     struct nfs4_layoutcommit_args *args)
+                                     const void *priv)
 {
+       const struct nfs4_layoutcommit_args *args = priv;
        struct nfs4_layoutcommit_data *data =
                container_of(args, struct nfs4_layoutcommit_data, args);
        struct compound_hdr hdr = {
@@ -2962,8 +3051,9 @@ static void nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_layoutreturn(struct rpc_rqst *req,
                                      struct xdr_stream *xdr,
-                                     struct nfs4_layoutreturn_args *args)
+                                     const void *data)
 {
+       const struct nfs4_layoutreturn_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2978,10 +3068,11 @@ static void nfs4_xdr_enc_layoutreturn(struct rpc_rqst *req,
 /*
  * Encode SECINFO_NO_NAME request
  */
-static int nfs4_xdr_enc_secinfo_no_name(struct rpc_rqst *req,
+static void nfs4_xdr_enc_secinfo_no_name(struct rpc_rqst *req,
                                        struct xdr_stream *xdr,
-                                       struct nfs41_secinfo_no_name_args *args)
+                                       const void *data)
 {
+       const struct nfs41_secinfo_no_name_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2991,7 +3082,6 @@ static int nfs4_xdr_enc_secinfo_no_name(struct rpc_rqst *req,
        encode_putrootfh(xdr, &hdr);
        encode_secinfo_no_name(xdr, args, &hdr);
        encode_nops(&hdr);
-       return 0;
 }
 
 /*
@@ -2999,8 +3089,9 @@ static int nfs4_xdr_enc_secinfo_no_name(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_test_stateid(struct rpc_rqst *req,
                                      struct xdr_stream *xdr,
-                                     struct nfs41_test_stateid_args *args)
+                                     const void *data)
 {
+       const struct nfs41_test_stateid_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -3016,8 +3107,9 @@ static void nfs4_xdr_enc_test_stateid(struct rpc_rqst *req,
  */
 static void nfs4_xdr_enc_free_stateid(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    struct nfs41_free_stateid_args *args)
+                                    const void *data)
 {
+       const struct nfs41_free_stateid_args *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -5005,6 +5097,11 @@ static int decode_lookup(struct xdr_stream *xdr)
        return decode_op_hdr(xdr, OP_LOOKUP);
 }
 
+static int decode_lookupp(struct xdr_stream *xdr)
+{
+       return decode_op_hdr(xdr, OP_LOOKUPP);
+}
+
 /* This is too sick! */
 static int decode_space_limit(struct xdr_stream *xdr,
                unsigned long *pagemod_limit)
@@ -6101,8 +6198,9 @@ int decode_layoutreturn(struct xdr_stream *xdr,
  */
 static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
                                       struct xdr_stream *xdr,
-                                      struct nfs_closeres *res)
+                                      void *data)
 {
+       struct nfs_closeres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6130,8 +6228,9 @@ out:
  * Decode ACCESS response
  */
 static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                              struct nfs4_accessres *res)
+                              void *data)
 {
+       struct nfs4_accessres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6156,8 +6255,9 @@ out:
  * Decode LOOKUP response
  */
 static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                              struct nfs4_lookup_res *res)
+                              void *data)
 {
+       struct nfs4_lookup_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6182,12 +6282,43 @@ out:
 }
 
 /*
+ * Decode LOOKUPP response
+ */
+static int nfs4_xdr_dec_lookupp(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+               void *data)
+{
+       struct nfs4_lookupp_res *res = data;
+       struct compound_hdr hdr;
+       int status;
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, rqstp);
+       if (status)
+               goto out;
+       status = decode_putfh(xdr);
+       if (status)
+               goto out;
+       status = decode_lookupp(xdr);
+       if (status)
+               goto out;
+       status = decode_getfh(xdr, res->fh);
+       if (status)
+               goto out;
+       status = decode_getfattr_label(xdr, res->fattr, res->label, res->server);
+out:
+       return status;
+}
+
+/*
  * Decode LOOKUP_ROOT response
  */
 static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
                                    struct xdr_stream *xdr,
-                                   struct nfs4_lookup_res *res)
+                                   void *data)
 {
+       struct nfs4_lookup_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6212,8 +6343,9 @@ out:
  * Decode REMOVE response
  */
 static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                              struct nfs_removeres *res)
+                              void *data)
 {
+       struct nfs_removeres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6235,8 +6367,9 @@ out:
  * Decode RENAME response
  */
 static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                              struct nfs_renameres *res)
+                              void *data)
 {
+       struct nfs_renameres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6264,8 +6397,9 @@ out:
  * Decode LINK response
  */
 static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                            struct nfs4_link_res *res)
+                            void *data)
 {
+       struct nfs4_link_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6303,8 +6437,9 @@ out:
  * Decode CREATE response
  */
 static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                              struct nfs4_create_res *res)
+                              void *data)
 {
+       struct nfs4_create_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6332,7 +6467,7 @@ out:
  * Decode SYMLINK response
  */
 static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                               struct nfs4_create_res *res)
+                               void *res)
 {
        return nfs4_xdr_dec_create(rqstp, xdr, res);
 }
@@ -6341,8 +6476,9 @@ static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
  * Decode GETATTR response
  */
 static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                               struct nfs4_getattr_res *res)
+                               void *data)
 {
+       struct nfs4_getattr_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6364,8 +6500,9 @@ out:
  * Encode an SETACL request
  */
 static void nfs4_xdr_enc_setacl(struct rpc_rqst *req, struct xdr_stream *xdr,
-                               struct nfs_setaclargs *args)
+                               const void *data)
 {
+       const struct nfs_setaclargs *args = data;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -6382,8 +6519,9 @@ static void nfs4_xdr_enc_setacl(struct rpc_rqst *req, struct xdr_stream *xdr,
  */
 static int
 nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                   struct nfs_setaclres *res)
+                   void *data)
 {
+       struct nfs_setaclres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6406,8 +6544,9 @@ out:
  */
 static int
 nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                   struct nfs_getaclres *res)
+                   void *data)
 {
+       struct nfs_getaclres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6434,8 +6573,9 @@ out:
  * Decode CLOSE response
  */
 static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                             struct nfs_closeres *res)
+                             void *data)
 {
+       struct nfs_closeres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6468,8 +6608,9 @@ out:
  * Decode OPEN response
  */
 static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                            struct nfs_openres *res)
+                            void *data)
 {
+       struct nfs_openres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6500,8 +6641,9 @@ out:
  */
 static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp,
                                     struct xdr_stream *xdr,
-                                    struct nfs_open_confirmres *res)
+                                    void *data)
 {
+       struct nfs_open_confirmres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6521,8 +6663,9 @@ out:
  */
 static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
                                    struct xdr_stream *xdr,
-                                   struct nfs_openres *res)
+                                   void *data)
 {
+       struct nfs_openres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6550,8 +6693,9 @@ out:
  */
 static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
                                struct xdr_stream *xdr,
-                               struct nfs_setattrres *res)
+                               void *data)
 {
+       struct nfs_setattrres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6576,8 +6720,9 @@ out:
  * Decode LOCK response
  */
 static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                            struct nfs_lock_res *res)
+                            void *data)
 {
+       struct nfs_lock_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6599,8 +6744,9 @@ out:
  * Decode LOCKT response
  */
 static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                             struct nfs_lockt_res *res)
+                             void *data)
 {
+       struct nfs_lockt_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6622,8 +6768,9 @@ out:
  * Decode LOCKU response
  */
 static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                             struct nfs_locku_res *res)
+                             void *data)
 {
+       struct nfs_locku_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6658,8 +6805,9 @@ static int nfs4_xdr_dec_release_lockowner(struct rpc_rqst *rqstp,
  */
 static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp,
                                 struct xdr_stream *xdr,
-                                struct nfs4_readlink_res *res)
+                                void *data)
 {
+       struct nfs4_readlink_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6681,8 +6829,9 @@ out:
  * Decode READDIR response
  */
 static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                               struct nfs4_readdir_res *res)
+                               void *data)
 {
+       struct nfs4_readdir_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6704,8 +6853,9 @@ out:
  * Decode Read response
  */
 static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                            struct nfs_pgio_res *res)
+                            void *data)
 {
+       struct nfs_pgio_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6730,8 +6880,9 @@ out:
  * Decode WRITE response
  */
 static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                             struct nfs_pgio_res *res)
+                             void *data)
 {
+       struct nfs_pgio_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6760,8 +6911,9 @@ out:
  * Decode COMMIT response
  */
 static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
-                              struct nfs_commitres *res)
+                              void *data)
 {
+       struct nfs_commitres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6784,8 +6936,9 @@ out:
  * Decode FSINFO response
  */
 static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, struct xdr_stream *xdr,
-                              struct nfs4_fsinfo_res *res)
+                              void *data)
 {
+       struct nfs4_fsinfo_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6803,8 +6956,9 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Decode PATHCONF response
  */
 static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                struct nfs4_pathconf_res *res)
+                                void *data)
 {
+       struct nfs4_pathconf_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6822,8 +6976,9 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr,
  * Decode STATFS response
  */
 static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, struct xdr_stream *xdr,
-                              struct nfs4_statfs_res *res)
+                              void *data)
 {
+       struct nfs4_statfs_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6842,8 +6997,9 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, struct xdr_stream *xdr,
  */
 static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   struct nfs4_server_caps_res *res)
+                                   void *data)
 {
+       struct nfs4_server_caps_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6881,8 +7037,9 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
  */
 static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req,
                                    struct xdr_stream *xdr,
-                                   struct nfs4_setclientid_res *res)
+                                   void *data)
 {
+       struct nfs4_setclientid_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6896,7 +7053,8 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req,
  * Decode SETCLIENTID_CONFIRM response
  */
 static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
-                                           struct xdr_stream *xdr)
+                                           struct xdr_stream *xdr,
+                                           void *data)
 {
        struct compound_hdr hdr;
        int status;
@@ -6912,8 +7070,9 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
  */
 static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
                                    struct xdr_stream *xdr,
-                                   struct nfs4_delegreturnres *res)
+                                   void *data)
 {
+       struct nfs4_delegreturnres *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6947,8 +7106,9 @@ out:
  */
 static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
                                     struct xdr_stream *xdr,
-                                    struct nfs4_fs_locations_res *res)
+                                    void *data)
 {
+       struct nfs4_fs_locations_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -6990,8 +7150,9 @@ out:
  */
 static int nfs4_xdr_dec_secinfo(struct rpc_rqst *rqstp,
                                struct xdr_stream *xdr,
-                               struct nfs4_secinfo_res *res)
+                               void *data)
 {
+       struct nfs4_secinfo_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -7014,8 +7175,9 @@ out:
  */
 static int nfs4_xdr_dec_fsid_present(struct rpc_rqst *rqstp,
                                     struct xdr_stream *xdr,
-                                    struct nfs4_fsid_present_res *res)
+                                    void *data)
 {
+       struct nfs4_fsid_present_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -7075,7 +7237,7 @@ static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp,
  */
 static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp,
                                       struct xdr_stream *xdr,
-                                      struct nfs41_create_session_res *res)
+                                      void *res)
 {
        struct compound_hdr hdr;
        int status;
@@ -7123,7 +7285,7 @@ static int nfs4_xdr_dec_destroy_clientid(struct rpc_rqst *rqstp,
  */
 static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp,
                                 struct xdr_stream *xdr,
-                                struct nfs4_sequence_res *res)
+                                void *res)
 {
        struct compound_hdr hdr;
        int status;
@@ -7139,8 +7301,9 @@ static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp,
  */
 static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp,
                                       struct xdr_stream *xdr,
-                                      struct nfs4_get_lease_time_res *res)
+                                      void *data)
 {
+       struct nfs4_get_lease_time_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -7159,8 +7322,9 @@ static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp,
  */
 static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp,
                                         struct xdr_stream *xdr,
-                                        struct nfs41_reclaim_complete_res *res)
+                                        void *data)
 {
+       struct nfs41_reclaim_complete_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -7177,8 +7341,9 @@ static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp,
  */
 static int nfs4_xdr_dec_getdeviceinfo(struct rpc_rqst *rqstp,
                                      struct xdr_stream *xdr,
-                                     struct nfs4_getdeviceinfo_res *res)
+                                     void *data)
 {
+       struct nfs4_getdeviceinfo_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -7198,8 +7363,9 @@ out:
  */
 static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp,
                                  struct xdr_stream *xdr,
-                                 struct nfs4_layoutget_res *res)
+                                 void *data)
 {
+       struct nfs4_layoutget_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -7222,8 +7388,9 @@ out:
  */
 static int nfs4_xdr_dec_layoutreturn(struct rpc_rqst *rqstp,
                                     struct xdr_stream *xdr,
-                                    struct nfs4_layoutreturn_res *res)
+                                    void *data)
 {
+       struct nfs4_layoutreturn_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -7246,8 +7413,9 @@ out:
  */
 static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
                                     struct xdr_stream *xdr,
-                                    struct nfs4_layoutcommit_res *res)
+                                    void *data)
 {
+       struct nfs4_layoutcommit_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -7273,8 +7441,9 @@ out:
  */
 static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp,
                                        struct xdr_stream *xdr,
-                                       struct nfs4_secinfo_res *res)
+                                       void *data)
 {
+       struct nfs4_secinfo_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -7297,8 +7466,9 @@ out:
  */
 static int nfs4_xdr_dec_test_stateid(struct rpc_rqst *rqstp,
                                     struct xdr_stream *xdr,
-                                    struct nfs41_test_stateid_res *res)
+                                    void *data)
 {
+       struct nfs41_test_stateid_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -7318,8 +7488,9 @@ out:
  */
 static int nfs4_xdr_dec_free_stateid(struct rpc_rqst *rqstp,
                                     struct xdr_stream *xdr,
-                                    struct nfs41_free_stateid_res *res)
+                                    void *data)
 {
+       struct nfs41_free_stateid_res *res = data;
        struct compound_hdr hdr;
        int status;
 
@@ -7350,7 +7521,7 @@ out:
  * on a directory already in our cache.
  */
 int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
-                      int plus)
+                      bool plus)
 {
        unsigned int savep;
        uint32_t bitmap[3] = {0};
@@ -7484,8 +7655,8 @@ nfs4_stat_to_errno(int stat)
 #define PROC(proc, argtype, restype)                           \
 [NFSPROC4_CLNT_##proc] = {                                     \
        .p_proc   = NFSPROC4_COMPOUND,                          \
-       .p_encode = (kxdreproc_t)nfs4_xdr_##argtype,            \
-       .p_decode = (kxdrdproc_t)nfs4_xdr_##restype,            \
+       .p_encode = nfs4_xdr_##argtype,                         \
+       .p_decode = nfs4_xdr_##restype,                         \
        .p_arglen = NFS4_##argtype##_sz,                        \
        .p_replen = NFS4_##restype##_sz,                        \
        .p_statidx = NFSPROC4_CLNT_##proc,                      \
@@ -7497,7 +7668,7 @@ nfs4_stat_to_errno(int stat)
        .p_name = #proc,        \
 }
 
-struct rpc_procinfo    nfs4_procedures[] = {
+const struct rpc_procinfo nfs4_procedures[] = {
        PROC(READ,              enc_read,               dec_read),
        PROC(WRITE,             enc_write,              dec_write),
        PROC(COMMIT,            enc_commit,             dec_commit),
@@ -7517,6 +7688,7 @@ struct rpc_procinfo       nfs4_procedures[] = {
        PROC(ACCESS,            enc_access,             dec_access),
        PROC(GETATTR,           enc_getattr,            dec_getattr),
        PROC(LOOKUP,            enc_lookup,             dec_lookup),
+       PROC(LOOKUPP,           enc_lookupp,            dec_lookupp),
        PROC(LOOKUP_ROOT,       enc_lookup_root,        dec_lookup_root),
        PROC(REMOVE,            enc_remove,             dec_remove),
        PROC(RENAME,            enc_rename,             dec_rename),
@@ -7564,10 +7736,12 @@ struct rpc_procinfo     nfs4_procedures[] = {
 #endif /* CONFIG_NFS_V4_2 */
 };
 
+static unsigned int nfs_version4_counts[ARRAY_SIZE(nfs4_procedures)];
 const struct rpc_version nfs_version4 = {
        .number                 = 4,
        .nrprocs                = ARRAY_SIZE(nfs4_procedures),
-       .procs                  = nfs4_procedures
+       .procs                  = nfs4_procedures,
+       .counts                 = nfs_version4_counts,
 };
 
 /*
index ad92b40..de9066a 100644 (file)
@@ -50,8 +50,8 @@ void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
        hdr->cred = hdr->req->wb_context->cred;
        hdr->io_start = req_offset(hdr->req);
        hdr->good_bytes = mirror->pg_count;
+       hdr->io_completion = desc->pg_io_completion;
        hdr->dreq = desc->pg_dreq;
-       hdr->layout_private = desc->pg_layout_private;
        hdr->release = release;
        hdr->completion_ops = desc->pg_completion_ops;
        if (hdr->completion_ops->init_hdr)
@@ -155,9 +155,12 @@ nfs_page_group_lock(struct nfs_page *req, bool nonblock)
        if (!test_and_set_bit(PG_HEADLOCK, &head->wb_flags))
                return 0;
 
-       if (!nonblock)
+       if (!nonblock) {
+               set_bit(PG_CONTENDED1, &head->wb_flags);
+               smp_mb__after_atomic();
                return wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK,
                                TASK_UNINTERRUPTIBLE);
+       }
 
        return -EAGAIN;
 }
@@ -175,6 +178,10 @@ nfs_page_group_lock_wait(struct nfs_page *req)
 
        WARN_ON_ONCE(head != head->wb_head);
 
+       if (!test_bit(PG_HEADLOCK, &head->wb_flags))
+               return;
+       set_bit(PG_CONTENDED1, &head->wb_flags);
+       smp_mb__after_atomic();
        wait_on_bit(&head->wb_flags, PG_HEADLOCK,
                TASK_UNINTERRUPTIBLE);
 }
@@ -193,6 +200,8 @@ nfs_page_group_unlock(struct nfs_page *req)
        smp_mb__before_atomic();
        clear_bit(PG_HEADLOCK, &head->wb_flags);
        smp_mb__after_atomic();
+       if (!test_bit(PG_CONTENDED1, &head->wb_flags))
+               return;
        wake_up_bit(&head->wb_flags, PG_HEADLOCK);
 }
 
@@ -383,6 +392,8 @@ void nfs_unlock_request(struct nfs_page *req)
        smp_mb__before_atomic();
        clear_bit(PG_BUSY, &req->wb_flags);
        smp_mb__after_atomic();
+       if (!test_bit(PG_CONTENDED2, &req->wb_flags))
+               return;
        wake_up_bit(&req->wb_flags, PG_BUSY);
 }
 
@@ -465,6 +476,10 @@ void nfs_release_request(struct nfs_page *req)
 int
 nfs_wait_on_request(struct nfs_page *req)
 {
+       if (!test_bit(PG_BUSY, &req->wb_flags))
+               return 0;
+       set_bit(PG_CONTENDED2, &req->wb_flags);
+       smp_mb__after_atomic();
        return wait_on_bit_io(&req->wb_flags, PG_BUSY,
                              TASK_UNINTERRUPTIBLE);
 }
@@ -710,8 +725,8 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
        desc->pg_ioflags = io_flags;
        desc->pg_error = 0;
        desc->pg_lseg = NULL;
+       desc->pg_io_completion = NULL;
        desc->pg_dreq = NULL;
-       desc->pg_layout_private = NULL;
        desc->pg_bsize = bsize;
 
        desc->pg_mirror_count = 1;
@@ -779,6 +794,7 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
        gfp_t gfp_flags = GFP_KERNEL;
 
        pagecount = nfs_page_array_len(mirror->pg_base, mirror->pg_count);
+       pg_array->npages = pagecount;
 
        if (pagecount <= ARRAY_SIZE(pg_array->page_array))
                pg_array->pagevec = pg_array->page_array;
@@ -1233,6 +1249,7 @@ int nfs_pageio_resend(struct nfs_pageio_descriptor *desc,
 {
        LIST_HEAD(failed);
 
+       desc->pg_io_completion = hdr->io_completion;
        desc->pg_dreq = hdr->dreq;
        while (!list_empty(&hdr->pages)) {
                struct nfs_page *req = nfs_list_entry(hdr->pages.next);
index d40755a..25f28fa 100644 (file)
@@ -159,13 +159,18 @@ void pnfs_generic_recover_commit_reqs(struct list_head *dst,
 {
        struct pnfs_commit_bucket *b;
        struct pnfs_layout_segment *freeme;
+       int nwritten;
        int i;
 
        lockdep_assert_held(&cinfo->inode->i_lock);
 restart:
        for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
-               if (pnfs_generic_transfer_commit_list(&b->written, dst,
-                                                     cinfo, 0)) {
+               nwritten = pnfs_generic_transfer_commit_list(&b->written,
+                               dst, cinfo, 0);
+               if (!nwritten)
+                       continue;
+               cinfo->ds->nwritten -= nwritten;
+               if (list_empty(&b->written)) {
                        freeme = b->wlseg;
                        b->wlseg = NULL;
                        spin_unlock(&cinfo->inode->i_lock);
@@ -174,7 +179,6 @@ restart:
                        goto restart;
                }
        }
-       cinfo->ds->nwritten = 0;
 }
 EXPORT_SYMBOL_GPL(pnfs_generic_recover_commit_reqs);
 
@@ -183,6 +187,7 @@ static void pnfs_generic_retry_commit(struct nfs_commit_info *cinfo, int idx)
        struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds;
        struct pnfs_commit_bucket *bucket;
        struct pnfs_layout_segment *freeme;
+       struct list_head *pos;
        LIST_HEAD(pages);
        int i;
 
@@ -193,6 +198,8 @@ static void pnfs_generic_retry_commit(struct nfs_commit_info *cinfo, int idx)
                        continue;
                freeme = bucket->clseg;
                bucket->clseg = NULL;
+               list_for_each(pos, &bucket->committing)
+                       cinfo->ds->ncommitting--;
                list_splice_init(&bucket->committing, &pages);
                spin_unlock(&cinfo->inode->i_lock);
                nfs_retry_commit(&pages, freeme, cinfo, i);
@@ -217,13 +224,6 @@ pnfs_generic_alloc_ds_commits(struct nfs_commit_info *cinfo,
        for (i = 0; i < fl_cinfo->nbuckets; i++, bucket++) {
                if (list_empty(&bucket->committing))
                        continue;
-               /*
-                * If the layout segment is invalid, then let
-                * pnfs_generic_retry_commit() clean up the bucket.
-                */
-               if (bucket->clseg && !pnfs_is_valid_lseg(bucket->clseg) &&
-                   !test_bit(NFS_LSEG_LAYOUTRETURN, &bucket->clseg->pls_flags))
-                       break;
                data = nfs_commitdata_alloc(false);
                if (!data)
                        break;
@@ -243,9 +243,12 @@ void pnfs_fetch_commit_bucket_list(struct list_head *pages,
                struct nfs_commit_info *cinfo)
 {
        struct pnfs_commit_bucket *bucket;
+       struct list_head *pos;
 
        bucket = &cinfo->ds->buckets[data->ds_commit_index];
        spin_lock(&cinfo->inode->i_lock);
+       list_for_each(pos, &bucket->committing)
+               cinfo->ds->ncommitting--;
        list_splice_init(&bucket->committing, pages);
        data->lseg = bucket->clseg;
        bucket->clseg = NULL;
@@ -330,7 +333,6 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
                }
        }
 out:
-       cinfo->ds->ncommitting = 0;
        return PNFS_ATTEMPTED;
 }
 EXPORT_SYMBOL_GPL(pnfs_generic_commit_pagelist);
index 9872cf6..7962e49 100644 (file)
@@ -485,7 +485,7 @@ nfs_proc_rmdir(struct inode *dir, const struct qstr *name)
  */
 static int
 nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
-                u64 cookie, struct page **pages, unsigned int count, int plus)
+                u64 cookie, struct page **pages, unsigned int count, bool plus)
 {
        struct inode            *dir = d_inode(dentry);
        struct nfs_readdirargs  arg = {
index c5334c0..d828ef8 100644 (file)
@@ -879,7 +879,7 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root)
        if (nfss->options & NFS_OPTION_FSCACHE) {
                seq_printf(m, "\n\tfsc:\t");
                for (i = 0; i < __NFSIOS_FSCACHEMAX; i++)
-                       seq_printf(m, "%Lu ", totals.bytes[i]);
+                       seq_printf(m, "%Lu ", totals.fscache[i]);
        }
 #endif
        seq_printf(m, "\n");
@@ -2339,6 +2339,7 @@ void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
                 */
                sb->s_flags |= MS_POSIXACL;
                sb->s_time_gran = 1;
+               sb->s_export_op = &nfs_export_ops;
        }
 
        nfs_initialise_sb(sb);
@@ -2360,6 +2361,7 @@ static void nfs_clone_super(struct super_block *sb,
        sb->s_xattr = old_sb->s_xattr;
        sb->s_op = old_sb->s_op;
        sb->s_time_gran = 1;
+       sb->s_export_op = old_sb->s_export_op;
 
        if (server->nfs_client->rpc_ops->version != 2) {
                /* The VFS shouldn't apply the umask to mode bits. We will do
index 191aa57..e3949d9 100644 (file)
@@ -288,6 +288,19 @@ static void nfs_async_rename_release(void *calldata)
        if (d_really_is_positive(data->old_dentry))
                nfs_mark_for_revalidate(d_inode(data->old_dentry));
 
+       /* The result of the rename is unknown. Play it safe by
+        * forcing a new lookup */
+       if (data->cancelled) {
+               spin_lock(&data->old_dir->i_lock);
+               nfs_force_lookup_revalidate(data->old_dir);
+               spin_unlock(&data->old_dir->i_lock);
+               if (data->new_dir != data->old_dir) {
+                       spin_lock(&data->new_dir->i_lock);
+                       nfs_force_lookup_revalidate(data->new_dir);
+                       spin_unlock(&data->new_dir->i_lock);
+               }
+       }
+
        dput(data->old_dentry);
        dput(data->new_dentry);
        iput(data->old_dir);
index db7ba54..b1af5de 100644 (file)
 #define MIN_POOL_WRITE         (32)
 #define MIN_POOL_COMMIT                (4)
 
+struct nfs_io_completion {
+       void (*complete)(void *data);
+       void *data;
+       struct kref refcount;
+};
+
 /*
  * Local function declarations
  */
@@ -108,6 +114,39 @@ static void nfs_writehdr_free(struct nfs_pgio_header *hdr)
        mempool_free(hdr, nfs_wdata_mempool);
 }
 
+static struct nfs_io_completion *nfs_io_completion_alloc(gfp_t gfp_flags)
+{
+       return kmalloc(sizeof(struct nfs_io_completion), gfp_flags);
+}
+
+static void nfs_io_completion_init(struct nfs_io_completion *ioc,
+               void (*complete)(void *), void *data)
+{
+       ioc->complete = complete;
+       ioc->data = data;
+       kref_init(&ioc->refcount);
+}
+
+static void nfs_io_completion_release(struct kref *kref)
+{
+       struct nfs_io_completion *ioc = container_of(kref,
+                       struct nfs_io_completion, refcount);
+       ioc->complete(ioc->data);
+       kfree(ioc);
+}
+
+static void nfs_io_completion_get(struct nfs_io_completion *ioc)
+{
+       if (ioc != NULL)
+               kref_get(&ioc->refcount);
+}
+
+static void nfs_io_completion_put(struct nfs_io_completion *ioc)
+{
+       if (ioc != NULL)
+               kref_put(&ioc->refcount, nfs_io_completion_release);
+}
+
 static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
 {
        ctx->error = error;
@@ -681,18 +720,29 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control *
        return ret;
 }
 
+static void nfs_io_completion_commit(void *inode)
+{
+       nfs_commit_inode(inode, 0);
+}
+
 int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
        struct inode *inode = mapping->host;
        struct nfs_pageio_descriptor pgio;
+       struct nfs_io_completion *ioc = nfs_io_completion_alloc(GFP_NOFS);
        int err;
 
        nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
 
+       if (ioc)
+               nfs_io_completion_init(ioc, nfs_io_completion_commit, inode);
+
        nfs_pageio_init_write(&pgio, inode, wb_priority(wbc), false,
                                &nfs_async_write_completion_ops);
+       pgio.pg_io_completion = ioc;
        err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
        nfs_pageio_complete(&pgio);
+       nfs_io_completion_put(ioc);
 
        if (err < 0)
                goto out_err;
@@ -940,6 +990,11 @@ int nfs_write_need_commit(struct nfs_pgio_header *hdr)
        return hdr->verf.committed != NFS_FILE_SYNC;
 }
 
+static void nfs_async_write_init(struct nfs_pgio_header *hdr)
+{
+       nfs_io_completion_get(hdr->io_completion);
+}
+
 static void nfs_write_completion(struct nfs_pgio_header *hdr)
 {
        struct nfs_commit_info cinfo;
@@ -973,6 +1028,7 @@ next:
                nfs_release_request(req);
        }
 out:
+       nfs_io_completion_put(hdr->io_completion);
        hdr->release(hdr);
 }
 
@@ -1378,6 +1434,7 @@ static void nfs_async_write_reschedule_io(struct nfs_pgio_header *hdr)
 }
 
 static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops = {
+       .init_hdr = nfs_async_write_init,
        .error_cleanup = nfs_async_write_error,
        .completion = nfs_write_completion,
        .reschedule_io = nfs_async_write_reschedule_io,
@@ -1884,7 +1941,7 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
                /* Don't commit yet if this is a non-blocking flush and there
                 * are a lot of outstanding writes for this mapping.
                 */
-               if (nfsi->commit_info.ncommit <= (nfsi->nrequests >> 1))
+               if (mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK))
                        goto out_mark_dirty;
 
                /* don't wait for the COMMIT response */
index 4123551..34075ce 100644 (file)
@@ -8,21 +8,33 @@ extern void clear_current_stateid(struct nfsd4_compound_state *cstate);
 /*
  * functions to set current state id
  */
-extern void nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *);
-extern void nfsd4_set_openstateid(struct nfsd4_compound_state *, struct nfsd4_open *);
-extern void nfsd4_set_lockstateid(struct nfsd4_compound_state *, struct nfsd4_lock *);
-extern void nfsd4_set_closestateid(struct nfsd4_compound_state *, struct nfsd4_close *);
+extern void nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *,
+               union nfsd4_op_u *);
+extern void nfsd4_set_openstateid(struct nfsd4_compound_state *,
+               union nfsd4_op_u *);
+extern void nfsd4_set_lockstateid(struct nfsd4_compound_state *,
+               union nfsd4_op_u *);
+extern void nfsd4_set_closestateid(struct nfsd4_compound_state *,
+               union nfsd4_op_u *);
 
 /*
  * functions to consume current state id
  */
-extern void nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *);
-extern void nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *, struct nfsd4_delegreturn *);
-extern void nfsd4_get_freestateid(struct nfsd4_compound_state *, struct nfsd4_free_stateid *);
-extern void nfsd4_get_setattrstateid(struct nfsd4_compound_state *, struct nfsd4_setattr *);
-extern void nfsd4_get_closestateid(struct nfsd4_compound_state *, struct nfsd4_close *);
-extern void nfsd4_get_lockustateid(struct nfsd4_compound_state *, struct nfsd4_locku *);
-extern void nfsd4_get_readstateid(struct nfsd4_compound_state *, struct nfsd4_read *);
-extern void nfsd4_get_writestateid(struct nfsd4_compound_state *, struct nfsd4_write *);
+extern void nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *,
+               union nfsd4_op_u *);
+extern void nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *,
+               union nfsd4_op_u *);
+extern void nfsd4_get_freestateid(struct nfsd4_compound_state *,
+               union nfsd4_op_u *);
+extern void nfsd4_get_setattrstateid(struct nfsd4_compound_state *,
+               union nfsd4_op_u *);
+extern void nfsd4_get_closestateid(struct nfsd4_compound_state *,
+               union nfsd4_op_u *);
+extern void nfsd4_get_lockustateid(struct nfsd4_compound_state *,
+               union nfsd4_op_u *);
+extern void nfsd4_get_readstateid(struct nfsd4_compound_state *,
+               union nfsd4_op_u *);
+extern void nfsd4_get_writestateid(struct nfsd4_compound_state *,
+               union nfsd4_op_u *);
 
 #endif   /* _NFSD4_CURRENT_STATE_H */
index 838f90f..6276ec8 100644 (file)
@@ -19,7 +19,7 @@
  * NULL call.
  */
 static __be32
-nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+nfsacld_proc_null(struct svc_rqst *rqstp)
 {
        return nfs_ok;
 }
@@ -27,9 +27,10 @@ nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 /*
  * Get the Access and/or Default ACL of a file.
  */
-static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
-               struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
+static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
 {
+       struct nfsd3_getaclargs *argp = rqstp->rq_argp;
+       struct nfsd3_getaclres *resp = rqstp->rq_resp;
        struct posix_acl *acl;
        struct inode *inode;
        svc_fh *fh;
@@ -87,10 +88,10 @@ fail:
 /*
  * Set the Access and/or Default ACL of a file.
  */
-static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
-               struct nfsd3_setaclargs *argp,
-               struct nfsd_attrstat *resp)
+static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
 {
+       struct nfsd3_setaclargs *argp = rqstp->rq_argp;
+       struct nfsd_attrstat *resp = rqstp->rq_resp;
        struct inode *inode;
        svc_fh *fh;
        __be32 nfserr = 0;
@@ -141,9 +142,10 @@ out_errno:
 /*
  * Check file attributes
  */
-static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp,
-               struct nfsd_fhandle *argp, struct nfsd_attrstat *resp)
+static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp)
 {
+       struct nfsd_fhandle *argp = rqstp->rq_argp;
+       struct nfsd_attrstat *resp = rqstp->rq_resp;
        __be32 nfserr;
        dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
 
@@ -158,9 +160,10 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp,
 /*
  * Check file access
  */
-static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
-               struct nfsd3_accessres *resp)
+static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)
 {
+       struct nfsd3_accessargs *argp = rqstp->rq_argp;
+       struct nfsd3_accessres *resp = rqstp->rq_resp;
        __be32 nfserr;
 
        dprintk("nfsd: ACCESS(2acl)   %s 0x%x\n",
@@ -179,9 +182,10 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessarg
 /*
  * XDR decode functions
  */
-static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd3_getaclargs *argp)
+static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_getaclargs *argp = rqstp->rq_argp;
+
        p = nfs2svc_decode_fh(p, &argp->fh);
        if (!p)
                return 0;
@@ -191,9 +195,9 @@ static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 
-static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd3_setaclargs *argp)
+static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_setaclargs *argp = rqstp->rq_argp;
        struct kvec *head = rqstp->rq_arg.head;
        unsigned int base;
        int n;
@@ -217,18 +221,20 @@ static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
        return (n > 0);
 }
 
-static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd_fhandle *argp)
+static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_fhandle *argp = rqstp->rq_argp;
+
        p = nfs2svc_decode_fh(p, &argp->fh);
        if (!p)
                return 0;
        return xdr_argsize_check(rqstp, p);
 }
 
-static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd3_accessargs *argp)
+static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_accessargs *argp = rqstp->rq_argp;
+
        p = nfs2svc_decode_fh(p, &argp->fh);
        if (!p)
                return 0;
@@ -245,15 +251,15 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
  * There must be an encoding function for void results so svc_process
  * will work properly.
  */
-static int nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+static int nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p)
 {
        return xdr_ressize_check(rqstp, p);
 }
 
 /* GETACL */
-static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd3_getaclres *resp)
+static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_getaclres *resp = rqstp->rq_resp;
        struct dentry *dentry = resp->fh.fh_dentry;
        struct inode *inode;
        struct kvec *head = rqstp->rq_res.head;
@@ -296,17 +302,19 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
        return (n > 0);
 }
 
-static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd_attrstat *resp)
+static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_attrstat *resp = rqstp->rq_resp;
+
        p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
        return xdr_ressize_check(rqstp, p);
 }
 
 /* ACCESS */
-static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd3_accessres *resp)
+static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_accessres *resp = rqstp->rq_resp;
+
        p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
        *p++ = htonl(resp->access);
        return xdr_ressize_check(rqstp, p);
@@ -315,27 +323,27 @@ static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
 /*
  * XDR release functions
  */
-static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd3_getaclres *resp)
+static void nfsaclsvc_release_getacl(struct svc_rqst *rqstp)
 {
+       struct nfsd3_getaclres *resp = rqstp->rq_resp;
+
        fh_put(&resp->fh);
        posix_acl_release(resp->acl_access);
        posix_acl_release(resp->acl_default);
-       return 1;
 }
 
-static int nfsaclsvc_release_attrstat(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd_attrstat *resp)
+static void nfsaclsvc_release_attrstat(struct svc_rqst *rqstp)
 {
+       struct nfsd_attrstat *resp = rqstp->rq_resp;
+
        fh_put(&resp->fh);
-       return 1;
 }
 
-static int nfsaclsvc_release_access(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd3_accessres *resp)
+static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
 {
-       fh_put(&resp->fh);
-       return 1;
+       struct nfsd3_accessres *resp = rqstp->rq_resp;
+
+       fh_put(&resp->fh);
 }
 
 #define nfsaclsvc_decode_voidargs      NULL
@@ -345,24 +353,24 @@ static int nfsaclsvc_release_access(struct svc_rqst *rqstp, __be32 *p,
 #define nfsd3_voidres          nfsd3_voidargs
 struct nfsd3_voidargs { int dummy; };
 
-#define PROC(name, argt, rest, relt, cache, respsize)  \
- { (svc_procfunc) nfsacld_proc_##name,         \
-   (kxdrproc_t) nfsaclsvc_decode_##argt##args, \
-   (kxdrproc_t) nfsaclsvc_encode_##rest##res,  \
-   (kxdrproc_t) nfsaclsvc_release_##relt,              \
-   sizeof(struct nfsd3_##argt##args),          \
-   sizeof(struct nfsd3_##rest##res),           \
-   0,                                          \
-   cache,                                      \
-   respsize,                                   \
- }
+#define PROC(name, argt, rest, relt, cache, respsize)                  \
+{                                                                      \
+       .pc_func        = nfsacld_proc_##name,                          \
+       .pc_decode      = nfsaclsvc_decode_##argt##args,                \
+       .pc_encode      = nfsaclsvc_encode_##rest##res,                 \
+       .pc_release     = nfsaclsvc_release_##relt,     \
+       .pc_argsize     = sizeof(struct nfsd3_##argt##args),            \
+       .pc_ressize     = sizeof(struct nfsd3_##rest##res),             \
+       .pc_cachetype   = cache,                                        \
+       .pc_xdrressize  = respsize,                                     \
+}
 
 #define ST 1           /* status*/
 #define AT 21          /* attributes */
 #define pAT (1+AT)     /* post attributes - conditional */
 #define ACL (1+NFS_ACL_MAX_ENTRIES*3)  /* Access Control List */
 
-static struct svc_procedure            nfsd_acl_procedures2[] = {
+static const struct svc_procedure nfsd_acl_procedures2[] = {
   PROC(null,   void,           void,           void,     RC_NOCACHE, ST),
   PROC(getacl, getacl,         getacl,         getacl,   RC_NOCACHE, ST+1+2*(1+ACL)),
   PROC(setacl, setacl,         attrstat,       attrstat, RC_NOCACHE, ST+AT),
@@ -370,10 +378,12 @@ static struct svc_procedure               nfsd_acl_procedures2[] = {
   PROC(access, access,         access,         access,   RC_NOCACHE, ST+AT+1),
 };
 
-struct svc_version     nfsd_acl_version2 = {
-               .vs_vers        = 2,
-               .vs_nproc       = 5,
-               .vs_proc        = nfsd_acl_procedures2,
-               .vs_dispatch    = nfsd_dispatch,
-               .vs_xdrsize     = NFS3_SVC_XDRSIZE,
+static unsigned int nfsd_acl_count2[ARRAY_SIZE(nfsd_acl_procedures2)];
+const struct svc_version nfsd_acl_version2 = {
+       .vs_vers        = 2,
+       .vs_nproc       = 5,
+       .vs_proc        = nfsd_acl_procedures2,
+       .vs_count       = nfsd_acl_count2,
+       .vs_dispatch    = nfsd_dispatch,
+       .vs_xdrsize     = NFS3_SVC_XDRSIZE,
 };
index dcb5f79..0197652 100644 (file)
@@ -18,7 +18,7 @@
  * NULL call.
  */
 static __be32
-nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+nfsd3_proc_null(struct svc_rqst *rqstp)
 {
        return nfs_ok;
 }
@@ -26,9 +26,10 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 /*
  * Get the Access and/or Default ACL of a file.
  */
-static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp,
-               struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
+static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp)
 {
+       struct nfsd3_getaclargs *argp = rqstp->rq_argp;
+       struct nfsd3_getaclres *resp = rqstp->rq_resp;
        struct posix_acl *acl;
        struct inode *inode;
        svc_fh *fh;
@@ -80,10 +81,10 @@ fail:
 /*
  * Set the Access and/or Default ACL of a file.
  */
-static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp,
-               struct nfsd3_setaclargs *argp,
-               struct nfsd3_attrstat *resp)
+static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
 {
+       struct nfsd3_setaclargs *argp = rqstp->rq_argp;
+       struct nfsd3_attrstat *resp = rqstp->rq_resp;
        struct inode *inode;
        svc_fh *fh;
        __be32 nfserr = 0;
@@ -123,9 +124,10 @@ out:
 /*
  * XDR decode functions
  */
-static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd3_getaclargs *args)
+static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_getaclargs *args = rqstp->rq_argp;
+
        p = nfs3svc_decode_fh(p, &args->fh);
        if (!p)
                return 0;
@@ -135,9 +137,9 @@ static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 
-static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd3_setaclargs *args)
+static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_setaclargs *args = rqstp->rq_argp;
        struct kvec *head = rqstp->rq_arg.head;
        unsigned int base;
        int n;
@@ -166,9 +168,9 @@ static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
  */
 
 /* GETACL */
-static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd3_getaclres *resp)
+static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_getaclres *resp = rqstp->rq_resp;
        struct dentry *dentry = resp->fh.fh_dentry;
 
        p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
@@ -211,9 +213,10 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
 }
 
 /* SETACL */
-static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd3_attrstat *resp)
+static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_attrstat *resp = rqstp->rq_resp;
+
        p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
 
        return xdr_ressize_check(rqstp, p);
@@ -222,13 +225,13 @@ static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p,
 /*
  * XDR release functions
  */
-static int nfs3svc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
-               struct nfsd3_getaclres *resp)
+static void nfs3svc_release_getacl(struct svc_rqst *rqstp)
 {
+       struct nfsd3_getaclres *resp = rqstp->rq_resp;
+
        fh_put(&resp->fh);
        posix_acl_release(resp->acl_access);
        posix_acl_release(resp->acl_default);
-       return 1;
 }
 
 #define nfs3svc_decode_voidargs                NULL
@@ -237,34 +240,36 @@ static int nfs3svc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
 #define nfsd3_voidres                  nfsd3_voidargs
 struct nfsd3_voidargs { int dummy; };
 
-#define PROC(name, argt, rest, relt, cache, respsize)  \
- { (svc_procfunc) nfsd3_proc_##name,           \
-   (kxdrproc_t) nfs3svc_decode_##argt##args,   \
-   (kxdrproc_t) nfs3svc_encode_##rest##res,    \
-   (kxdrproc_t) nfs3svc_release_##relt,                \
-   sizeof(struct nfsd3_##argt##args),          \
-   sizeof(struct nfsd3_##rest##res),           \
-   0,                                          \
-   cache,                                      \
-   respsize,                                   \
- }
+#define PROC(name, argt, rest, relt, cache, respsize)                  \
+{                                                                      \
+       .pc_func        = nfsd3_proc_##name,                            \
+       .pc_decode      = nfs3svc_decode_##argt##args,                  \
+       .pc_encode      = nfs3svc_encode_##rest##res,                   \
+       .pc_release     = nfs3svc_release_##relt,                       \
+       .pc_argsize     = sizeof(struct nfsd3_##argt##args),            \
+       .pc_ressize     = sizeof(struct nfsd3_##rest##res),             \
+       .pc_cachetype   = cache,                                        \
+       .pc_xdrressize  = respsize,                                     \
+}
 
 #define ST 1           /* status*/
 #define AT 21          /* attributes */
 #define pAT (1+AT)     /* post attributes - conditional */
 #define ACL (1+NFS_ACL_MAX_ENTRIES*3)  /* Access Control List */
 
-static struct svc_procedure            nfsd_acl_procedures3[] = {
+static const struct svc_procedure nfsd_acl_procedures3[] = {
   PROC(null,   void,           void,           void,     RC_NOCACHE, ST),
   PROC(getacl, getacl,         getacl,         getacl,   RC_NOCACHE, ST+1+2*(1+ACL)),
   PROC(setacl, setacl,         setacl,         fhandle,  RC_NOCACHE, ST+pAT),
 };
 
-struct svc_version     nfsd_acl_version3 = {
-               .vs_vers        = 3,
-               .vs_nproc       = 3,
-               .vs_proc        = nfsd_acl_procedures3,
-               .vs_dispatch    = nfsd_dispatch,
-               .vs_xdrsize     = NFS3_SVC_XDRSIZE,
+static unsigned int nfsd_acl_count3[ARRAY_SIZE(nfsd_acl_procedures3)];
+const struct svc_version nfsd_acl_version3 = {
+       .vs_vers        = 3,
+       .vs_nproc       = 3,
+       .vs_proc        = nfsd_acl_procedures3,
+       .vs_count       = nfsd_acl_count3,
+       .vs_dispatch    = nfsd_dispatch,
+       .vs_xdrsize     = NFS3_SVC_XDRSIZE,
 };
 
index 045c908..2cb56a0 100644 (file)
@@ -31,7 +31,7 @@ static int    nfs3_ftypes[] = {
  * NULL call.
  */
 static __be32
-nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+nfsd3_proc_null(struct svc_rqst *rqstp)
 {
        return nfs_ok;
 }
@@ -40,9 +40,10 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
  * Get a file's attributes
  */
 static __be32
-nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
-                                          struct nfsd3_attrstat *resp)
+nfsd3_proc_getattr(struct svc_rqst *rqstp)
 {
+       struct nfsd_fhandle *argp = rqstp->rq_argp;
+       struct nfsd3_attrstat *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: GETATTR(3)  %s\n",
@@ -63,9 +64,10 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
  * Set a file's attributes
  */
 static __be32
-nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
-                                          struct nfsd3_attrstat  *resp)
+nfsd3_proc_setattr(struct svc_rqst *rqstp)
 {
+       struct nfsd3_sattrargs *argp = rqstp->rq_argp;
+       struct nfsd3_attrstat *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: SETATTR(3)  %s\n",
@@ -81,9 +83,10 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
  * Look up a path name component
  */
 static __be32
-nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
-                                         struct nfsd3_diropres  *resp)
+nfsd3_proc_lookup(struct svc_rqst *rqstp)
 {
+       struct nfsd3_diropargs *argp = rqstp->rq_argp;
+       struct nfsd3_diropres  *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: LOOKUP(3)   %s %.*s\n",
@@ -105,9 +108,10 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
  * Check file access
  */
 static __be32
-nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
-                                         struct nfsd3_accessres *resp)
+nfsd3_proc_access(struct svc_rqst *rqstp)
 {
+       struct nfsd3_accessargs *argp = rqstp->rq_argp;
+       struct nfsd3_accessres *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: ACCESS(3)   %s 0x%x\n",
@@ -124,9 +128,10 @@ nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
  * Read a symlink.
  */
 static __be32
-nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
-                                          struct nfsd3_readlinkres *resp)
+nfsd3_proc_readlink(struct svc_rqst *rqstp)
 {
+       struct nfsd3_readlinkargs *argp = rqstp->rq_argp;
+       struct nfsd3_readlinkres *resp = rqstp->rq_resp;
        __be32 nfserr;
 
        dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
@@ -142,9 +147,10 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
  * Read a portion of a file.
  */
 static __be32
-nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
-                                       struct nfsd3_readres  *resp)
+nfsd3_proc_read(struct svc_rqst *rqstp)
 {
+       struct nfsd3_readargs *argp = rqstp->rq_argp;
+       struct nfsd3_readres *resp = rqstp->rq_resp;
        __be32  nfserr;
        u32     max_blocksize = svc_max_payload(rqstp);
        unsigned long cnt = min(argp->count, max_blocksize);
@@ -179,9 +185,10 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
  * Write data to a file
  */
 static __be32
-nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
-                                        struct nfsd3_writeres  *resp)
+nfsd3_proc_write(struct svc_rqst *rqstp)
 {
+       struct nfsd3_writeargs *argp = rqstp->rq_argp;
+       struct nfsd3_writeres *resp = rqstp->rq_resp;
        __be32  nfserr;
        unsigned long cnt = argp->len;
 
@@ -206,9 +213,10 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
  * first reports about SunOS compatibility problems start to pour in...
  */
 static __be32
-nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
-                                         struct nfsd3_diropres   *resp)
+nfsd3_proc_create(struct svc_rqst *rqstp)
 {
+       struct nfsd3_createargs *argp = rqstp->rq_argp;
+       struct nfsd3_diropres *resp = rqstp->rq_resp;
        svc_fh          *dirfhp, *newfhp = NULL;
        struct iattr    *attr;
        __be32          nfserr;
@@ -243,9 +251,10 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
  * Make directory. This operation is not idempotent.
  */
 static __be32
-nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
-                                        struct nfsd3_diropres   *resp)
+nfsd3_proc_mkdir(struct svc_rqst *rqstp)
 {
+       struct nfsd3_createargs *argp = rqstp->rq_argp;
+       struct nfsd3_diropres *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: MKDIR(3)    %s %.*s\n",
@@ -263,9 +272,10 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
 }
 
 static __be32
-nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
-                                          struct nfsd3_diropres    *resp)
+nfsd3_proc_symlink(struct svc_rqst *rqstp)
 {
+       struct nfsd3_symlinkargs *argp = rqstp->rq_argp;
+       struct nfsd3_diropres *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: SYMLINK(3)  %s %.*s -> %.*s\n",
@@ -284,9 +294,10 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
  * Make socket/fifo/device.
  */
 static __be32
-nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
-                                        struct nfsd3_diropres  *resp)
+nfsd3_proc_mknod(struct svc_rqst *rqstp)
 {
+       struct nfsd3_mknodargs *argp = rqstp->rq_argp;
+       struct nfsd3_diropres  *resp = rqstp->rq_resp;
        __be32  nfserr;
        int type;
        dev_t   rdev = 0;
@@ -321,9 +332,10 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
  * Remove file/fifo/socket etc.
  */
 static __be32
-nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
-                                         struct nfsd3_attrstat  *resp)
+nfsd3_proc_remove(struct svc_rqst *rqstp)
 {
+       struct nfsd3_diropargs *argp = rqstp->rq_argp;
+       struct nfsd3_attrstat *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: REMOVE(3)   %s %.*s\n",
@@ -342,9 +354,10 @@ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
  * Remove a directory
  */
 static __be32
-nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
-                                        struct nfsd3_attrstat  *resp)
+nfsd3_proc_rmdir(struct svc_rqst *rqstp)
 {
+       struct nfsd3_diropargs *argp = rqstp->rq_argp;
+       struct nfsd3_attrstat *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: RMDIR(3)    %s %.*s\n",
@@ -359,9 +372,10 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
 }
 
 static __be32
-nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
-                                         struct nfsd3_renameres  *resp)
+nfsd3_proc_rename(struct svc_rqst *rqstp)
 {
+       struct nfsd3_renameargs *argp = rqstp->rq_argp;
+       struct nfsd3_renameres *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: RENAME(3)   %s %.*s ->\n",
@@ -381,9 +395,10 @@ nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
 }
 
 static __be32
-nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
-                                       struct nfsd3_linkres  *resp)
+nfsd3_proc_link(struct svc_rqst *rqstp)
 {
+       struct nfsd3_linkargs *argp = rqstp->rq_argp;
+       struct nfsd3_linkres  *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: LINK(3)     %s ->\n",
@@ -404,9 +419,10 @@ nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
  * Read a portion of a directory.
  */
 static __be32
-nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
-                                          struct nfsd3_readdirres  *resp)
+nfsd3_proc_readdir(struct svc_rqst *rqstp)
 {
+       struct nfsd3_readdirargs *argp = rqstp->rq_argp;
+       struct nfsd3_readdirres  *resp = rqstp->rq_resp;
        __be32          nfserr;
        int             count;
 
@@ -440,9 +456,10 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
  * For now, we choose to ignore the dircount parameter.
  */
 static __be32
-nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
-                                              struct nfsd3_readdirres  *resp)
+nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
 {
+       struct nfsd3_readdirargs *argp = rqstp->rq_argp;
+       struct nfsd3_readdirres  *resp = rqstp->rq_resp;
        __be32  nfserr;
        int     count = 0;
        loff_t  offset;
@@ -507,9 +524,10 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
  * Get file system stats
  */
 static __be32
-nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
-                                          struct nfsd3_fsstatres *resp)
+nfsd3_proc_fsstat(struct svc_rqst *rqstp)
 {
+       struct nfsd_fhandle *argp = rqstp->rq_argp;
+       struct nfsd3_fsstatres *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: FSSTAT(3)   %s\n",
@@ -524,9 +542,10 @@ nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
  * Get file system info
  */
 static __be32
-nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
-                                          struct nfsd3_fsinfores *resp)
+nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
 {
+       struct nfsd_fhandle *argp = rqstp->rq_argp;
+       struct nfsd3_fsinfores *resp = rqstp->rq_resp;
        __be32  nfserr;
        u32     max_blocksize = svc_max_payload(rqstp);
 
@@ -567,9 +586,10 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
  * Get pathconf info for the specified file
  */
 static __be32
-nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle      *argp,
-                                            struct nfsd3_pathconfres *resp)
+nfsd3_proc_pathconf(struct svc_rqst *rqstp)
 {
+       struct nfsd_fhandle *argp = rqstp->rq_argp;
+       struct nfsd3_pathconfres *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: PATHCONF(3) %s\n",
@@ -610,9 +630,10 @@ nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle      *argp,
  * Commit a file (range) to stable storage.
  */
 static __be32
-nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
-                                          struct nfsd3_commitres  *resp)
+nfsd3_proc_commit(struct svc_rqst *rqstp)
 {
+       struct nfsd3_commitargs *argp = rqstp->rq_argp;
+       struct nfsd3_commitres *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: COMMIT(3)   %s %u@%Lu\n",
@@ -647,233 +668,221 @@ nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
 #define nfsd3_voidres                  nfsd3_voidargs
 struct nfsd3_voidargs { int dummy; };
 
-#define PROC(name, argt, rest, relt, cache, respsize)  \
- { (svc_procfunc) nfsd3_proc_##name,           \
-   (kxdrproc_t) nfs3svc_decode_##argt##args,   \
-   (kxdrproc_t) nfs3svc_encode_##rest##res,    \
-   (kxdrproc_t) nfs3svc_release_##relt,                \
-   sizeof(struct nfsd3_##argt##args),          \
-   sizeof(struct nfsd3_##rest##res),           \
-   0,                                          \
-   cache,                                      \
-   respsize,                                   \
- }
-
 #define ST 1           /* status*/
 #define FH 17          /* filehandle with length */
 #define AT 21          /* attributes */
 #define pAT (1+AT)     /* post attributes - conditional */
 #define WC (7+pAT)     /* WCC attributes */
 
-static struct svc_procedure            nfsd_procedures3[22] = {
+static const struct svc_procedure nfsd_procedures3[22] = {
        [NFS3PROC_NULL] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_null,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_voidres,
+               .pc_func = nfsd3_proc_null,
+               .pc_encode = nfs3svc_encode_voidres,
                .pc_argsize = sizeof(struct nfsd3_voidargs),
                .pc_ressize = sizeof(struct nfsd3_voidres),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST,
        },
        [NFS3PROC_GETATTR] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_getattr,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_attrstatres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
+               .pc_func = nfsd3_proc_getattr,
+               .pc_decode = nfs3svc_decode_fhandleargs,
+               .pc_encode = nfs3svc_encode_attrstatres,
+               .pc_release = nfs3svc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd3_fhandleargs),
                .pc_ressize = sizeof(struct nfsd3_attrstatres),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST+AT,
        },
        [NFS3PROC_SETATTR] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_setattr,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_sattrargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
+               .pc_func = nfsd3_proc_setattr,
+               .pc_decode = nfs3svc_decode_sattrargs,
+               .pc_encode = nfs3svc_encode_wccstatres,
+               .pc_release = nfs3svc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd3_sattrargs),
                .pc_ressize = sizeof(struct nfsd3_wccstatres),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+WC,
        },
        [NFS3PROC_LOOKUP] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_lookup,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_diropres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
+               .pc_func = nfsd3_proc_lookup,
+               .pc_decode = nfs3svc_decode_diropargs,
+               .pc_encode = nfs3svc_encode_diropres,
+               .pc_release = nfs3svc_release_fhandle2,
                .pc_argsize = sizeof(struct nfsd3_diropargs),
                .pc_ressize = sizeof(struct nfsd3_diropres),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST+FH+pAT+pAT,
        },
        [NFS3PROC_ACCESS] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_access,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_accessargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_accessres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
+               .pc_func = nfsd3_proc_access,
+               .pc_decode = nfs3svc_decode_accessargs,
+               .pc_encode = nfs3svc_encode_accessres,
+               .pc_release = nfs3svc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd3_accessargs),
                .pc_ressize = sizeof(struct nfsd3_accessres),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST+pAT+1,
        },
        [NFS3PROC_READLINK] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_readlink,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_readlinkargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_readlinkres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
+               .pc_func = nfsd3_proc_readlink,
+               .pc_decode = nfs3svc_decode_readlinkargs,
+               .pc_encode = nfs3svc_encode_readlinkres,
+               .pc_release = nfs3svc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd3_readlinkargs),
                .pc_ressize = sizeof(struct nfsd3_readlinkres),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4,
        },
        [NFS3PROC_READ] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_read,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_readargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_readres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
+               .pc_func = nfsd3_proc_read,
+               .pc_decode = nfs3svc_decode_readargs,
+               .pc_encode = nfs3svc_encode_readres,
+               .pc_release = nfs3svc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd3_readargs),
                .pc_ressize = sizeof(struct nfsd3_readres),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4,
        },
        [NFS3PROC_WRITE] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_write,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_writeargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_writeres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
+               .pc_func = nfsd3_proc_write,
+               .pc_decode = nfs3svc_decode_writeargs,
+               .pc_encode = nfs3svc_encode_writeres,
+               .pc_release = nfs3svc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd3_writeargs),
                .pc_ressize = sizeof(struct nfsd3_writeres),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+WC+4,
        },
        [NFS3PROC_CREATE] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_create,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_createargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
+               .pc_func = nfsd3_proc_create,
+               .pc_decode = nfs3svc_decode_createargs,
+               .pc_encode = nfs3svc_encode_createres,
+               .pc_release = nfs3svc_release_fhandle2,
                .pc_argsize = sizeof(struct nfsd3_createargs),
                .pc_ressize = sizeof(struct nfsd3_createres),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+(1+FH+pAT)+WC,
        },
        [NFS3PROC_MKDIR] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_mkdir,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_mkdirargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
+               .pc_func = nfsd3_proc_mkdir,
+               .pc_decode = nfs3svc_decode_mkdirargs,
+               .pc_encode = nfs3svc_encode_createres,
+               .pc_release = nfs3svc_release_fhandle2,
                .pc_argsize = sizeof(struct nfsd3_mkdirargs),
                .pc_ressize = sizeof(struct nfsd3_createres),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+(1+FH+pAT)+WC,
        },
        [NFS3PROC_SYMLINK] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_symlink,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_symlinkargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
+               .pc_func = nfsd3_proc_symlink,
+               .pc_decode = nfs3svc_decode_symlinkargs,
+               .pc_encode = nfs3svc_encode_createres,
+               .pc_release = nfs3svc_release_fhandle2,
                .pc_argsize = sizeof(struct nfsd3_symlinkargs),
                .pc_ressize = sizeof(struct nfsd3_createres),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+(1+FH+pAT)+WC,
        },
        [NFS3PROC_MKNOD] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_mknod,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_mknodargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
+               .pc_func = nfsd3_proc_mknod,
+               .pc_decode = nfs3svc_decode_mknodargs,
+               .pc_encode = nfs3svc_encode_createres,
+               .pc_release = nfs3svc_release_fhandle2,
                .pc_argsize = sizeof(struct nfsd3_mknodargs),
                .pc_ressize = sizeof(struct nfsd3_createres),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+(1+FH+pAT)+WC,
        },
        [NFS3PROC_REMOVE] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_remove,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
+               .pc_func = nfsd3_proc_remove,
+               .pc_decode = nfs3svc_decode_diropargs,
+               .pc_encode = nfs3svc_encode_wccstatres,
+               .pc_release = nfs3svc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd3_diropargs),
                .pc_ressize = sizeof(struct nfsd3_wccstatres),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+WC,
        },
        [NFS3PROC_RMDIR] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_rmdir,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
+               .pc_func = nfsd3_proc_rmdir,
+               .pc_decode = nfs3svc_decode_diropargs,
+               .pc_encode = nfs3svc_encode_wccstatres,
+               .pc_release = nfs3svc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd3_diropargs),
                .pc_ressize = sizeof(struct nfsd3_wccstatres),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+WC,
        },
        [NFS3PROC_RENAME] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_rename,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_renameargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_renameres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
+               .pc_func = nfsd3_proc_rename,
+               .pc_decode = nfs3svc_decode_renameargs,
+               .pc_encode = nfs3svc_encode_renameres,
+               .pc_release = nfs3svc_release_fhandle2,
                .pc_argsize = sizeof(struct nfsd3_renameargs),
                .pc_ressize = sizeof(struct nfsd3_renameres),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+WC+WC,
        },
        [NFS3PROC_LINK] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_link,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_linkargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_linkres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
+               .pc_func = nfsd3_proc_link,
+               .pc_decode = nfs3svc_decode_linkargs,
+               .pc_encode = nfs3svc_encode_linkres,
+               .pc_release = nfs3svc_release_fhandle2,
                .pc_argsize = sizeof(struct nfsd3_linkargs),
                .pc_ressize = sizeof(struct nfsd3_linkres),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+pAT+WC,
        },
        [NFS3PROC_READDIR] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_readdir,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
+               .pc_func = nfsd3_proc_readdir,
+               .pc_decode = nfs3svc_decode_readdirargs,
+               .pc_encode = nfs3svc_encode_readdirres,
+               .pc_release = nfs3svc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd3_readdirargs),
                .pc_ressize = sizeof(struct nfsd3_readdirres),
                .pc_cachetype = RC_NOCACHE,
        },
        [NFS3PROC_READDIRPLUS] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_readdirplus,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirplusargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
+               .pc_func = nfsd3_proc_readdirplus,
+               .pc_decode = nfs3svc_decode_readdirplusargs,
+               .pc_encode = nfs3svc_encode_readdirres,
+               .pc_release = nfs3svc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd3_readdirplusargs),
                .pc_ressize = sizeof(struct nfsd3_readdirres),
                .pc_cachetype = RC_NOCACHE,
        },
        [NFS3PROC_FSSTAT] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_fsstat,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_fsstatres,
+               .pc_func = nfsd3_proc_fsstat,
+               .pc_decode = nfs3svc_decode_fhandleargs,
+               .pc_encode = nfs3svc_encode_fsstatres,
                .pc_argsize = sizeof(struct nfsd3_fhandleargs),
                .pc_ressize = sizeof(struct nfsd3_fsstatres),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST+pAT+2*6+1,
        },
        [NFS3PROC_FSINFO] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_fsinfo,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_fsinfores,
+               .pc_func = nfsd3_proc_fsinfo,
+               .pc_decode = nfs3svc_decode_fhandleargs,
+               .pc_encode = nfs3svc_encode_fsinfores,
                .pc_argsize = sizeof(struct nfsd3_fhandleargs),
                .pc_ressize = sizeof(struct nfsd3_fsinfores),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST+pAT+12,
        },
        [NFS3PROC_PATHCONF] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_pathconf,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_pathconfres,
+               .pc_func = nfsd3_proc_pathconf,
+               .pc_decode = nfs3svc_decode_fhandleargs,
+               .pc_encode = nfs3svc_encode_pathconfres,
                .pc_argsize = sizeof(struct nfsd3_fhandleargs),
                .pc_ressize = sizeof(struct nfsd3_pathconfres),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST+pAT+6,
        },
        [NFS3PROC_COMMIT] = {
-               .pc_func = (svc_procfunc) nfsd3_proc_commit,
-               .pc_decode = (kxdrproc_t) nfs3svc_decode_commitargs,
-               .pc_encode = (kxdrproc_t) nfs3svc_encode_commitres,
-               .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
+               .pc_func = nfsd3_proc_commit,
+               .pc_decode = nfs3svc_decode_commitargs,
+               .pc_encode = nfs3svc_encode_commitres,
+               .pc_release = nfs3svc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd3_commitargs),
                .pc_ressize = sizeof(struct nfsd3_commitres),
                .pc_cachetype = RC_NOCACHE,
@@ -881,10 +890,12 @@ static struct svc_procedure               nfsd_procedures3[22] = {
        },
 };
 
-struct svc_version     nfsd_version3 = {
-               .vs_vers        = 3,
-               .vs_nproc       = 22,
-               .vs_proc        = nfsd_procedures3,
-               .vs_dispatch    = nfsd_dispatch,
-               .vs_xdrsize     = NFS3_SVC_XDRSIZE,
+static unsigned int nfsd_count3[ARRAY_SIZE(nfsd_procedures3)];
+const struct svc_version nfsd_version3 = {
+       .vs_vers        = 3,
+       .vs_nproc       = 22,
+       .vs_proc        = nfsd_procedures3,
+       .vs_dispatch    = nfsd_dispatch,
+       .vs_count       = nfsd_count3,
+       .vs_xdrsize     = NFS3_SVC_XDRSIZE,
 };
index 4523346..bf444b6 100644 (file)
@@ -260,7 +260,7 @@ void fill_post_wcc(struct svc_fh *fhp)
                printk("nfsd: inode locked twice during operation.\n");
 
        err = fh_getattr(fhp, &fhp->fh_post_attr);
-       fhp->fh_post_change = d_inode(fhp->fh_dentry)->i_version;
+       fhp->fh_post_change = nfsd4_change_attribute(d_inode(fhp->fh_dentry));
        if (err) {
                fhp->fh_post_saved = false;
                /* Grab the ctime anyway - set_change_info might use it */
@@ -273,8 +273,10 @@ void fill_post_wcc(struct svc_fh *fhp)
  * XDR decode functions
  */
 int
-nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
+nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_fhandle *args = rqstp->rq_argp;
+
        p = decode_fh(p, &args->fh);
        if (!p)
                return 0;
@@ -282,9 +284,10 @@ nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *a
 }
 
 int
-nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_sattrargs *args)
+nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_sattrargs *args = rqstp->rq_argp;
+
        p = decode_fh(p, &args->fh);
        if (!p)
                return 0;
@@ -300,9 +303,10 @@ nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_diropargs *args)
+nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_diropargs *args = rqstp->rq_argp;
+
        if (!(p = decode_fh(p, &args->fh))
         || !(p = decode_filename(p, &args->name, &args->len)))
                return 0;
@@ -311,9 +315,10 @@ nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_accessargs *args)
+nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_accessargs *args = rqstp->rq_argp;
+
        p = decode_fh(p, &args->fh);
        if (!p)
                return 0;
@@ -323,9 +328,9 @@ nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_readargs *args)
+nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_readargs *args = rqstp->rq_argp;
        unsigned int len;
        int v;
        u32 max_blocksize = svc_max_payload(rqstp);
@@ -353,9 +358,9 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_writeargs *args)
+nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_writeargs *args = rqstp->rq_argp;
        unsigned int len, v, hdr, dlen;
        u32 max_blocksize = svc_max_payload(rqstp);
        struct kvec *head = rqstp->rq_arg.head;
@@ -413,9 +418,10 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_createargs *args)
+nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_createargs *args = rqstp->rq_argp;
+
        if (!(p = decode_fh(p, &args->fh))
         || !(p = decode_filename(p, &args->name, &args->len)))
                return 0;
@@ -435,10 +441,12 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
 
        return xdr_argsize_check(rqstp, p);
 }
+
 int
-nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_createargs *args)
+nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_createargs *args = rqstp->rq_argp;
+
        if (!(p = decode_fh(p, &args->fh)) ||
            !(p = decode_filename(p, &args->name, &args->len)))
                return 0;
@@ -448,9 +456,9 @@ nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_symlinkargs *args)
+nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_symlinkargs *args = rqstp->rq_argp;
        unsigned int len, avail;
        char *old, *new;
        struct kvec *vec;
@@ -500,9 +508,10 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_mknodargs *args)
+nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_mknodargs *args = rqstp->rq_argp;
+
        if (!(p = decode_fh(p, &args->fh))
         || !(p = decode_filename(p, &args->name, &args->len)))
                return 0;
@@ -522,9 +531,10 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_renameargs *args)
+nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_renameargs *args = rqstp->rq_argp;
+
        if (!(p = decode_fh(p, &args->ffh))
         || !(p = decode_filename(p, &args->fname, &args->flen))
         || !(p = decode_fh(p, &args->tfh))
@@ -535,9 +545,10 @@ nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_readlinkargs *args)
+nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_readlinkargs *args = rqstp->rq_argp;
+
        p = decode_fh(p, &args->fh);
        if (!p)
                return 0;
@@ -547,9 +558,10 @@ nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_linkargs *args)
+nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_linkargs *args = rqstp->rq_argp;
+
        if (!(p = decode_fh(p, &args->ffh))
         || !(p = decode_fh(p, &args->tfh))
         || !(p = decode_filename(p, &args->tname, &args->tlen)))
@@ -559,9 +571,9 @@ nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_readdirargs *args)
+nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_readdirargs *args = rqstp->rq_argp;
        p = decode_fh(p, &args->fh);
        if (!p)
                return 0;
@@ -576,9 +588,9 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_readdirargs *args)
+nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_readdirargs *args = rqstp->rq_argp;
        int len;
        u32 max_blocksize = svc_max_payload(rqstp);
 
@@ -602,9 +614,9 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_commitargs *args)
+nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_commitargs *args = rqstp->rq_argp;
        p = decode_fh(p, &args->fh);
        if (!p)
                return 0;
@@ -622,16 +634,17 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p,
  * will work properly.
  */
 int
-nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p)
 {
        return xdr_ressize_check(rqstp, p);
 }
 
 /* GETATTR */
 int
-nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_attrstat *resp)
+nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_attrstat *resp = rqstp->rq_resp;
+
        if (resp->status == 0) {
                lease_get_mtime(d_inode(resp->fh.fh_dentry),
                                &resp->stat.mtime);
@@ -642,18 +655,20 @@ nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
 
 /* SETATTR, REMOVE, RMDIR */
 int
-nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_attrstat *resp)
+nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_attrstat *resp = rqstp->rq_resp;
+
        p = encode_wcc_data(rqstp, p, &resp->fh);
        return xdr_ressize_check(rqstp, p);
 }
 
 /* LOOKUP */
 int
-nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_diropres *resp)
+nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_diropres *resp = rqstp->rq_resp;
+
        if (resp->status == 0) {
                p = encode_fh(p, &resp->fh);
                p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -664,9 +679,10 @@ nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
 
 /* ACCESS */
 int
-nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_accessres *resp)
+nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_accessres *resp = rqstp->rq_resp;
+
        p = encode_post_op_attr(rqstp, p, &resp->fh);
        if (resp->status == 0)
                *p++ = htonl(resp->access);
@@ -675,9 +691,10 @@ nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
 
 /* READLINK */
 int
-nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_readlinkres *resp)
+nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_readlinkres *resp = rqstp->rq_resp;
+
        p = encode_post_op_attr(rqstp, p, &resp->fh);
        if (resp->status == 0) {
                *p++ = htonl(resp->len);
@@ -696,9 +713,10 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
 
 /* READ */
 int
-nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_readres *resp)
+nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_readres *resp = rqstp->rq_resp;
+
        p = encode_post_op_attr(rqstp, p, &resp->fh);
        if (resp->status == 0) {
                *p++ = htonl(resp->count);
@@ -720,9 +738,9 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
 
 /* WRITE */
 int
-nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_writeres *resp)
+nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_writeres *resp = rqstp->rq_resp;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        p = encode_wcc_data(rqstp, p, &resp->fh);
@@ -737,9 +755,10 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p,
 
 /* CREATE, MKDIR, SYMLINK, MKNOD */
 int
-nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_diropres *resp)
+nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_diropres *resp = rqstp->rq_resp;
+
        if (resp->status == 0) {
                *p++ = xdr_one;
                p = encode_fh(p, &resp->fh);
@@ -751,9 +770,10 @@ nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p,
 
 /* RENAME */
 int
-nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_renameres *resp)
+nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_renameres *resp = rqstp->rq_resp;
+
        p = encode_wcc_data(rqstp, p, &resp->ffh);
        p = encode_wcc_data(rqstp, p, &resp->tfh);
        return xdr_ressize_check(rqstp, p);
@@ -761,9 +781,10 @@ nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p,
 
 /* LINK */
 int
-nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_linkres *resp)
+nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_linkres *resp = rqstp->rq_resp;
+
        p = encode_post_op_attr(rqstp, p, &resp->fh);
        p = encode_wcc_data(rqstp, p, &resp->tfh);
        return xdr_ressize_check(rqstp, p);
@@ -771,9 +792,10 @@ nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p,
 
 /* READDIR */
 int
-nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_readdirres *resp)
+nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_readdirres *resp = rqstp->rq_resp;
+
        p = encode_post_op_attr(rqstp, p, &resp->fh);
 
        if (resp->status == 0) {
@@ -1021,9 +1043,9 @@ nfs3svc_encode_entry_plus(void *cd, const char *name,
 
 /* FSSTAT */
 int
-nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_fsstatres *resp)
+nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_fsstatres *resp = rqstp->rq_resp;
        struct kstatfs  *s = &resp->stats;
        u64             bs = s->f_bsize;
 
@@ -1043,9 +1065,10 @@ nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p,
 
 /* FSINFO */
 int
-nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_fsinfores *resp)
+nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_fsinfores *resp = rqstp->rq_resp;
+
        *p++ = xdr_zero;        /* no post_op_attr */
 
        if (resp->status == 0) {
@@ -1067,9 +1090,10 @@ nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p,
 
 /* PATHCONF */
 int
-nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_pathconfres *resp)
+nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_pathconfres *resp = rqstp->rq_resp;
+
        *p++ = xdr_zero;        /* no post_op_attr */
 
        if (resp->status == 0) {
@@ -1086,9 +1110,9 @@ nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p,
 
 /* COMMIT */
 int
-nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_commitres *resp)
+nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd3_commitres *resp = rqstp->rq_resp;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        p = encode_wcc_data(rqstp, p, &resp->fh);
@@ -1103,19 +1127,19 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p,
 /*
  * XDR release functions
  */
-int
-nfs3svc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_attrstat *resp)
+void
+nfs3svc_release_fhandle(struct svc_rqst *rqstp)
 {
+       struct nfsd3_attrstat *resp = rqstp->rq_resp;
+
        fh_put(&resp->fh);
-       return 1;
 }
 
-int
-nfs3svc_release_fhandle2(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd3_fhandle_pair *resp)
+void
+nfs3svc_release_fhandle2(struct svc_rqst *rqstp)
 {
+       struct nfsd3_fhandle_pair *resp = rqstp->rq_resp;
+
        fh_put(&resp->fh1);
        fh_put(&resp->fh2);
-       return 1;
 }
index 0274db6..49b0a9e 100644 (file)
@@ -468,7 +468,7 @@ static int decode_cb_sequence4res(struct xdr_stream *xdr,
  * NB: Without this zero space reservation, callbacks over krb5p fail
  */
 static void nfs4_xdr_enc_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                void *__unused)
+                                const void *__unused)
 {
        xdr_reserve_space(xdr, 0);
 }
@@ -477,8 +477,9 @@ static void nfs4_xdr_enc_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr,
  * 20.2. Operation 4: CB_RECALL - Recall a Delegation
  */
 static void nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, struct xdr_stream *xdr,
-                                  const struct nfsd4_callback *cb)
+                                  const void *data)
 {
+       const struct nfsd4_callback *cb = data;
        const struct nfs4_delegation *dp = cb_to_delegation(cb);
        struct nfs4_cb_compound_hdr hdr = {
                .ident = cb->cb_clp->cl_cb_ident,
@@ -512,8 +513,9 @@ static int nfs4_xdr_dec_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr,
  */
 static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp,
                                  struct xdr_stream *xdr,
-                                 struct nfsd4_callback *cb)
+                                 void *data)
 {
+       struct nfsd4_callback *cb = data;
        struct nfs4_cb_compound_hdr hdr;
        int status;
 
@@ -585,8 +587,9 @@ static void encode_cb_layout4args(struct xdr_stream *xdr,
 
 static void nfs4_xdr_enc_cb_layout(struct rpc_rqst *req,
                                   struct xdr_stream *xdr,
-                                  const struct nfsd4_callback *cb)
+                                  const void *data)
 {
+       const struct nfsd4_callback *cb = data;
        const struct nfs4_layout_stateid *ls =
                container_of(cb, struct nfs4_layout_stateid, ls_recall);
        struct nfs4_cb_compound_hdr hdr = {
@@ -602,8 +605,9 @@ static void nfs4_xdr_enc_cb_layout(struct rpc_rqst *req,
 
 static int nfs4_xdr_dec_cb_layout(struct rpc_rqst *rqstp,
                                  struct xdr_stream *xdr,
-                                 struct nfsd4_callback *cb)
+                                 void *data)
 {
+       struct nfsd4_callback *cb = data;
        struct nfs4_cb_compound_hdr hdr;
        int status;
 
@@ -631,8 +635,9 @@ static void encode_stateowner(struct xdr_stream *xdr, struct nfs4_stateowner *so
 
 static void nfs4_xdr_enc_cb_notify_lock(struct rpc_rqst *req,
                                        struct xdr_stream *xdr,
-                                       const struct nfsd4_callback *cb)
+                                       const void *data)
 {
+       const struct nfsd4_callback *cb = data;
        const struct nfsd4_blocked_lock *nbl =
                container_of(cb, struct nfsd4_blocked_lock, nbl_cb);
        struct nfs4_lockowner *lo = (struct nfs4_lockowner *)nbl->nbl_lock.fl_owner;
@@ -659,8 +664,9 @@ static void nfs4_xdr_enc_cb_notify_lock(struct rpc_rqst *req,
 
 static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp,
                                        struct xdr_stream *xdr,
-                                       struct nfsd4_callback *cb)
+                                       void *data)
 {
+       struct nfsd4_callback *cb = data;
        struct nfs4_cb_compound_hdr hdr;
        int status;
 
@@ -682,15 +688,15 @@ static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp,
 #define PROC(proc, call, argtype, restype)                             \
 [NFSPROC4_CLNT_##proc] = {                                             \
        .p_proc    = NFSPROC4_CB_##call,                                \
-       .p_encode  = (kxdreproc_t)nfs4_xdr_enc_##argtype,               \
-       .p_decode  = (kxdrdproc_t)nfs4_xdr_dec_##restype,               \
+       .p_encode  = nfs4_xdr_enc_##argtype,            \
+       .p_decode  = nfs4_xdr_dec_##restype,                            \
        .p_arglen  = NFS4_enc_##argtype##_sz,                           \
        .p_replen  = NFS4_dec_##restype##_sz,                           \
        .p_statidx = NFSPROC4_CB_##call,                                \
        .p_name    = #proc,                                             \
 }
 
-static struct rpc_procinfo nfs4_cb_procedures[] = {
+static const struct rpc_procinfo nfs4_cb_procedures[] = {
        PROC(CB_NULL,   NULL,           cb_null,        cb_null),
        PROC(CB_RECALL, COMPOUND,       cb_recall,      cb_recall),
 #ifdef CONFIG_NFSD_PNFS
@@ -699,7 +705,8 @@ static struct rpc_procinfo nfs4_cb_procedures[] = {
        PROC(CB_NOTIFY_LOCK,    COMPOUND,       cb_notify_lock, cb_notify_lock),
 };
 
-static struct rpc_version nfs_cb_version4 = {
+static unsigned int nfs4_cb_counts[ARRAY_SIZE(nfs4_cb_procedures)];
+static const struct rpc_version nfs_cb_version4 = {
 /*
  * Note on the callback rpc program version number: despite language in rfc
  * 5661 section 18.36.3 requiring servers to use 4 in this field, the
@@ -709,11 +716,12 @@ static struct rpc_version nfs_cb_version4 = {
  */
        .number                 = 1,
        .nrprocs                = ARRAY_SIZE(nfs4_cb_procedures),
-       .procs                  = nfs4_cb_procedures
+       .procs                  = nfs4_cb_procedures,
+       .counts                 = nfs4_cb_counts,
 };
 
-static const struct rpc_version *nfs_cb_version[] = {
-       &nfs_cb_version4,
+static const struct rpc_version *nfs_cb_version[2] = {
+       [1] = &nfs_cb_version4,
 };
 
 static const struct rpc_program cb_program;
@@ -787,7 +795,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
                .saddress       = (struct sockaddr *) &conn->cb_saddr,
                .timeout        = &timeparms,
                .program        = &cb_program,
-               .version        = 0,
+               .version        = 1,
                .flags          = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
        };
        struct rpc_clnt *client;
index dadb3bf..d27e75a 100644 (file)
@@ -344,8 +344,9 @@ copy_clientid(clientid_t *clid, struct nfsd4_session *session)
 
 static __be32
 nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-          struct nfsd4_open *open)
+          union nfsd4_op_u *u)
 {
+       struct nfsd4_open *open = &u->open;
        __be32 status;
        struct svc_fh *resfh = NULL;
        struct net *net = SVC_NET(rqstp);
@@ -467,14 +468,14 @@ out:
  */
 static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_op *op)
 {
-       struct nfsd4_open *open = (struct nfsd4_open *)&op->u;
+       struct nfsd4_open *open = &op->u.open;
 
        if (!seqid_mutating_err(ntohl(op->status)))
                return op->status;
        if (nfsd4_has_session(cstate))
                return op->status;
        open->op_xdr_error = op->status;
-       return nfsd4_open(rqstp, cstate, open);
+       return nfsd4_open(rqstp, cstate, &op->u);
 }
 
 /*
@@ -482,19 +483,21 @@ static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_stat
  */
 static __be32
 nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-           struct svc_fh **getfh)
+           union nfsd4_op_u *u)
 {
        if (!cstate->current_fh.fh_dentry)
                return nfserr_nofilehandle;
 
-       *getfh = &cstate->current_fh;
+       u->getfh = &cstate->current_fh;
        return nfs_ok;
 }
 
 static __be32
 nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-           struct nfsd4_putfh *putfh)
+           union nfsd4_op_u *u)
 {
+       struct nfsd4_putfh *putfh = &u->putfh;
+
        fh_put(&cstate->current_fh);
        cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen;
        memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval,
@@ -504,7 +507,7 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 static __be32
 nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-               void *arg)
+               union nfsd4_op_u *u)
 {
        __be32 status;
 
@@ -515,7 +518,7 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 static __be32
 nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-               void *arg)
+               union nfsd4_op_u *u)
 {
        if (!cstate->save_fh.fh_dentry)
                return nfserr_restorefh;
@@ -530,7 +533,7 @@ nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 static __be32
 nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-            void *arg)
+            union nfsd4_op_u *u)
 {
        if (!cstate->current_fh.fh_dentry)
                return nfserr_nofilehandle;
@@ -548,8 +551,10 @@ nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
  */
 static __be32
 nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-            struct nfsd4_access *access)
+            union nfsd4_op_u *u)
 {
+       struct nfsd4_access *access = &u->access;
+
        if (access->ac_req_access & ~NFS3_ACCESS_FULL)
                return nfserr_inval;
 
@@ -574,8 +579,10 @@ static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net)
 
 static __be32
 nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-            struct nfsd4_commit *commit)
+            union nfsd4_op_u *u)
 {
+       struct nfsd4_commit *commit = &u->commit;
+
        gen_boot_verifier(&commit->co_verf, SVC_NET(rqstp));
        return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
                             commit->co_count);
@@ -583,8 +590,9 @@ nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 static __be32
 nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-            struct nfsd4_create *create)
+            union nfsd4_op_u *u)
 {
+       struct nfsd4_create *create = &u->create;
        struct svc_fh resfh;
        __be32 status;
        dev_t rdev;
@@ -670,8 +678,9 @@ out:
 
 static __be32
 nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-             struct nfsd4_getattr *getattr)
+             union nfsd4_op_u *u)
 {
+       struct nfsd4_getattr *getattr = &u->getattr;
        __be32 status;
 
        status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
@@ -691,8 +700,9 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 static __be32
 nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-          struct nfsd4_link *link)
+          union nfsd4_op_u *u)
 {
+       struct nfsd4_link *link = &u->link;
        __be32 status = nfserr_nofilehandle;
 
        if (!cstate->save_fh.fh_dentry)
@@ -723,24 +733,25 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
 
 static __be32
 nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-             void *arg)
+             union nfsd4_op_u *u)
 {
        return nfsd4_do_lookupp(rqstp, &cstate->current_fh);
 }
 
 static __be32
 nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-            struct nfsd4_lookup *lookup)
+            union nfsd4_op_u *u)
 {
        return nfsd_lookup(rqstp, &cstate->current_fh,
-                          lookup->lo_name, lookup->lo_len,
+                          u->lookup.lo_name, u->lookup.lo_len,
                           &cstate->current_fh);
 }
 
 static __be32
 nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-          struct nfsd4_read *read)
+          union nfsd4_op_u *u)
 {
+       struct nfsd4_read *read = &u->read;
        __be32 status;
 
        read->rd_filp = NULL;
@@ -775,8 +786,9 @@ out:
 
 static __be32
 nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-             struct nfsd4_readdir *readdir)
+             union nfsd4_op_u *u)
 {
+       struct nfsd4_readdir *readdir = &u->readdir;
        u64 cookie = readdir->rd_cookie;
        static const nfs4_verifier zeroverf;
 
@@ -800,17 +812,18 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 static __be32
 nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-              struct nfsd4_readlink *readlink)
+              union nfsd4_op_u *u)
 {
-       readlink->rl_rqstp = rqstp;
-       readlink->rl_fhp = &cstate->current_fh;
+       u->readlink.rl_rqstp = rqstp;
+       u->readlink.rl_fhp = &cstate->current_fh;
        return nfs_ok;
 }
 
 static __be32
 nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-            struct nfsd4_remove *remove)
+            union nfsd4_op_u *u)
 {
+       struct nfsd4_remove *remove = &u->remove;
        __be32 status;
 
        if (opens_in_grace(SVC_NET(rqstp)))
@@ -826,8 +839,9 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 static __be32
 nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-            struct nfsd4_rename *rename)
+            union nfsd4_op_u *u)
 {
+       struct nfsd4_rename *rename = &u->rename;
        __be32 status = nfserr_nofilehandle;
 
        if (!cstate->save_fh.fh_dentry)
@@ -847,8 +861,9 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 static __be32
 nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-             struct nfsd4_secinfo *secinfo)
+             union nfsd4_op_u *u)
 {
+       struct nfsd4_secinfo *secinfo = &u->secinfo;
        struct svc_export *exp;
        struct dentry *dentry;
        __be32 err;
@@ -876,11 +891,11 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 static __be32
 nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-             struct nfsd4_secinfo_no_name *sin)
+               union nfsd4_op_u *u)
 {
        __be32 err;
 
-       switch (sin->sin_style) {
+       switch (u->secinfo_no_name.sin_style) {
        case NFS4_SECINFO_STYLE4_CURRENT_FH:
                break;
        case NFS4_SECINFO_STYLE4_PARENT:
@@ -892,15 +907,16 @@ nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstat
                return nfserr_inval;
        }
 
-       sin->sin_exp = exp_get(cstate->current_fh.fh_export);
+       u->secinfo_no_name.sin_exp = exp_get(cstate->current_fh.fh_export);
        fh_put(&cstate->current_fh);
        return nfs_ok;
 }
 
 static __be32
 nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-             struct nfsd4_setattr *setattr)
+             union nfsd4_op_u *u)
 {
+       struct nfsd4_setattr *setattr = &u->setattr;
        __be32 status = nfs_ok;
        int err;
 
@@ -960,8 +976,9 @@ static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write)
 
 static __be32
 nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-           struct nfsd4_write *write)
+           union nfsd4_op_u *u)
 {
+       struct nfsd4_write *write = &u->write;
        stateid_t *stateid = &write->wr_stateid;
        struct file *filp = NULL;
        __be32 status = nfs_ok;
@@ -1034,8 +1051,9 @@ out_put_src:
 
 static __be32
 nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-               struct nfsd4_clone *clone)
+               union nfsd4_op_u *u)
 {
+       struct nfsd4_clone *clone = &u->clone;
        struct file *src, *dst;
        __be32 status;
 
@@ -1055,8 +1073,9 @@ out:
 
 static __be32
 nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-               struct nfsd4_copy *copy)
+               union nfsd4_op_u *u)
 {
+       struct nfsd4_copy *copy = &u->copy;
        struct file *src, *dst;
        __be32 status;
        ssize_t bytes;
@@ -1111,23 +1130,24 @@ nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 static __be32
 nfsd4_allocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-              struct nfsd4_fallocate *fallocate)
+              union nfsd4_op_u *u)
 {
-       return nfsd4_fallocate(rqstp, cstate, fallocate, 0);
+       return nfsd4_fallocate(rqstp, cstate, &u->allocate, 0);
 }
 
 static __be32
 nfsd4_deallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-                struct nfsd4_fallocate *fallocate)
+                union nfsd4_op_u *u)
 {
-       return nfsd4_fallocate(rqstp, cstate, fallocate,
+       return nfsd4_fallocate(rqstp, cstate, &u->deallocate,
                               FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE);
 }
 
 static __be32
 nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-               struct nfsd4_seek *seek)
+          union nfsd4_op_u *u)
 {
+       struct nfsd4_seek *seek = &u->seek;
        int whence;
        __be32 status;
        struct file *file;
@@ -1232,21 +1252,21 @@ out_kfree:
 
 static __be32
 nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-             struct nfsd4_verify *verify)
+             union nfsd4_op_u *u)
 {
        __be32 status;
 
-       status = _nfsd4_verify(rqstp, cstate, verify);
+       status = _nfsd4_verify(rqstp, cstate, &u->verify);
        return status == nfserr_not_same ? nfs_ok : status;
 }
 
 static __be32
 nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-            struct nfsd4_verify *verify)
+            union nfsd4_op_u *u)
 {
        __be32 status;
 
-       status = _nfsd4_verify(rqstp, cstate, verify);
+       status = _nfsd4_verify(rqstp, cstate, &u->nverify);
        return status == nfserr_same ? nfs_ok : status;
 }
 
@@ -1271,9 +1291,9 @@ nfsd4_layout_verify(struct svc_export *exp, unsigned int layout_type)
 
 static __be32
 nfsd4_getdeviceinfo(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *cstate,
-               struct nfsd4_getdeviceinfo *gdp)
+               struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
 {
+       struct nfsd4_getdeviceinfo *gdp = &u->getdeviceinfo;
        const struct nfsd4_layout_ops *ops;
        struct nfsd4_deviceid_map *map;
        struct svc_export *exp;
@@ -1317,9 +1337,9 @@ out:
 
 static __be32
 nfsd4_layoutget(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *cstate,
-               struct nfsd4_layoutget *lgp)
+               struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
 {
+       struct nfsd4_layoutget *lgp = &u->layoutget;
        struct svc_fh *current_fh = &cstate->current_fh;
        const struct nfsd4_layout_ops *ops;
        struct nfs4_layout_stateid *ls;
@@ -1397,9 +1417,9 @@ out:
 
 static __be32
 nfsd4_layoutcommit(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *cstate,
-               struct nfsd4_layoutcommit *lcp)
+               struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
 {
+       struct nfsd4_layoutcommit *lcp = &u->layoutcommit;
        const struct nfsd4_layout_seg *seg = &lcp->lc_seg;
        struct svc_fh *current_fh = &cstate->current_fh;
        const struct nfsd4_layout_ops *ops;
@@ -1461,9 +1481,9 @@ out:
 
 static __be32
 nfsd4_layoutreturn(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *cstate,
-               struct nfsd4_layoutreturn *lrp)
+               struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
 {
+       struct nfsd4_layoutreturn *lrp = &u->layoutreturn;
        struct svc_fh *current_fh = &cstate->current_fh;
        __be32 nfserr;
 
@@ -1510,7 +1530,7 @@ out:
  * NULL call.
  */
 static __be32
-nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+nfsd4_proc_null(struct svc_rqst *rqstp)
 {
        return nfs_ok;
 }
@@ -1521,12 +1541,6 @@ static inline void nfsd4_increment_op_stats(u32 opnum)
                nfsdstats.nfs4_opcount[opnum]++;
 }
 
-typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
-                             void *);
-typedef u32(*nfsd4op_rsize)(struct svc_rqst *, struct nfsd4_op *op);
-typedef void(*stateid_setter)(struct nfsd4_compound_state *, void *);
-typedef void(*stateid_getter)(struct nfsd4_compound_state *, void *);
-
 enum nfsd4_op_flags {
        ALLOWED_WITHOUT_FH = 1 << 0,    /* No current filehandle required */
        ALLOWED_ON_ABSENT_FS = 1 << 1,  /* ops processed on absent fs */
@@ -1558,16 +1572,19 @@ enum nfsd4_op_flags {
 };
 
 struct nfsd4_operation {
-       nfsd4op_func op_func;
+       __be32 (*op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
+                       union nfsd4_op_u *);
        u32 op_flags;
        char *op_name;
        /* Try to get response size before operation */
-       nfsd4op_rsize op_rsize_bop;
-       stateid_getter op_get_currentstateid;
-       stateid_setter op_set_currentstateid;
+       u32 (*op_rsize_bop)(struct svc_rqst *, struct nfsd4_op *);
+       void (*op_get_currentstateid)(struct nfsd4_compound_state *,
+                       union nfsd4_op_u *);
+       void (*op_set_currentstateid)(struct nfsd4_compound_state *,
+                       union nfsd4_op_u *);
 };
 
-static struct nfsd4_operation nfsd4_ops[];
+static const struct nfsd4_operation nfsd4_ops[];
 
 static const char *nfsd4_op_name(unsigned opnum);
 
@@ -1604,7 +1621,7 @@ static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args)
        return nfs_ok;
 }
 
-static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op)
+static inline const struct nfsd4_operation *OPDESC(struct nfsd4_op *op)
 {
        return &nfsd4_ops[op->opnum];
 }
@@ -1622,10 +1639,9 @@ static bool need_wrongsec_check(struct svc_rqst *rqstp)
        struct nfsd4_compoundargs *argp = rqstp->rq_argp;
        struct nfsd4_op *this = &argp->ops[resp->opcnt - 1];
        struct nfsd4_op *next = &argp->ops[resp->opcnt];
-       struct nfsd4_operation *thisd;
-       struct nfsd4_operation *nextd;
+       const struct nfsd4_operation *thisd = OPDESC(this);
+       const struct nfsd4_operation *nextd;
 
-       thisd = OPDESC(this);
        /*
         * Most ops check wronsec on our own; only the putfh-like ops
         * have special rules.
@@ -1673,12 +1689,12 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp,
  * COMPOUND call.
  */
 static __be32
-nfsd4_proc_compound(struct svc_rqst *rqstp,
-                   struct nfsd4_compoundargs *args,
-                   struct nfsd4_compoundres *resp)
+nfsd4_proc_compound(struct svc_rqst *rqstp)
 {
+       struct nfsd4_compoundargs *args = rqstp->rq_argp;
+       struct nfsd4_compoundres *resp = rqstp->rq_resp;
        struct nfsd4_op *op;
-       struct nfsd4_operation *opdesc;
+       const struct nfsd4_operation *opdesc;
        struct nfsd4_compound_state *cstate = &resp->cstate;
        struct svc_fh *current_fh = &cstate->current_fh;
        struct svc_fh *save_fh = &cstate->save_fh;
@@ -2091,360 +2107,360 @@ static inline u32 nfsd4_seek_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
        return (op_encode_hdr_size + 3) * sizeof(__be32);
 }
 
-static struct nfsd4_operation nfsd4_ops[] = {
+static const struct nfsd4_operation nfsd4_ops[] = {
        [OP_ACCESS] = {
-               .op_func = (nfsd4op_func)nfsd4_access,
+               .op_func = nfsd4_access,
                .op_name = "OP_ACCESS",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_access_rsize,
+               .op_rsize_bop = nfsd4_access_rsize,
        },
        [OP_CLOSE] = {
-               .op_func = (nfsd4op_func)nfsd4_close,
+               .op_func = nfsd4_close,
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_CLOSE",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
-               .op_get_currentstateid = (stateid_getter)nfsd4_get_closestateid,
-               .op_set_currentstateid = (stateid_setter)nfsd4_set_closestateid,
+               .op_rsize_bop = nfsd4_status_stateid_rsize,
+               .op_get_currentstateid = nfsd4_get_closestateid,
+               .op_set_currentstateid = nfsd4_set_closestateid,
        },
        [OP_COMMIT] = {
-               .op_func = (nfsd4op_func)nfsd4_commit,
+               .op_func = nfsd4_commit,
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_COMMIT",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_commit_rsize,
+               .op_rsize_bop = nfsd4_commit_rsize,
        },
        [OP_CREATE] = {
-               .op_func = (nfsd4op_func)nfsd4_create,
+               .op_func = nfsd4_create,
                .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME | OP_CLEAR_STATEID,
                .op_name = "OP_CREATE",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_rsize,
+               .op_rsize_bop = nfsd4_create_rsize,
        },
        [OP_DELEGRETURN] = {
-               .op_func = (nfsd4op_func)nfsd4_delegreturn,
+               .op_func = nfsd4_delegreturn,
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_DELEGRETURN",
                .op_rsize_bop = nfsd4_only_status_rsize,
-               .op_get_currentstateid = (stateid_getter)nfsd4_get_delegreturnstateid,
+               .op_get_currentstateid = nfsd4_get_delegreturnstateid,
        },
        [OP_GETATTR] = {
-               .op_func = (nfsd4op_func)nfsd4_getattr,
+               .op_func = nfsd4_getattr,
                .op_flags = ALLOWED_ON_ABSENT_FS,
                .op_rsize_bop = nfsd4_getattr_rsize,
                .op_name = "OP_GETATTR",
        },
        [OP_GETFH] = {
-               .op_func = (nfsd4op_func)nfsd4_getfh,
+               .op_func = nfsd4_getfh,
                .op_name = "OP_GETFH",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_getfh_rsize,
+               .op_rsize_bop = nfsd4_getfh_rsize,
        },
        [OP_LINK] = {
-               .op_func = (nfsd4op_func)nfsd4_link,
+               .op_func = nfsd4_link,
                .op_flags = ALLOWED_ON_ABSENT_FS | OP_MODIFIES_SOMETHING
                                | OP_CACHEME,
                .op_name = "OP_LINK",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_link_rsize,
+               .op_rsize_bop = nfsd4_link_rsize,
        },
        [OP_LOCK] = {
-               .op_func = (nfsd4op_func)nfsd4_lock,
+               .op_func = nfsd4_lock,
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_LOCK",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize,
-               .op_set_currentstateid = (stateid_setter)nfsd4_set_lockstateid,
+               .op_rsize_bop = nfsd4_lock_rsize,
+               .op_set_currentstateid = nfsd4_set_lockstateid,
        },
        [OP_LOCKT] = {
-               .op_func = (nfsd4op_func)nfsd4_lockt,
+               .op_func = nfsd4_lockt,
                .op_name = "OP_LOCKT",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize,
+               .op_rsize_bop = nfsd4_lock_rsize,
        },
        [OP_LOCKU] = {
-               .op_func = (nfsd4op_func)nfsd4_locku,
+               .op_func = nfsd4_locku,
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_LOCKU",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
-               .op_get_currentstateid = (stateid_getter)nfsd4_get_lockustateid,
+               .op_rsize_bop = nfsd4_status_stateid_rsize,
+               .op_get_currentstateid = nfsd4_get_lockustateid,
        },
        [OP_LOOKUP] = {
-               .op_func = (nfsd4op_func)nfsd4_lookup,
+               .op_func = nfsd4_lookup,
                .op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID,
                .op_name = "OP_LOOKUP",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_LOOKUPP] = {
-               .op_func = (nfsd4op_func)nfsd4_lookupp,
+               .op_func = nfsd4_lookupp,
                .op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID,
                .op_name = "OP_LOOKUPP",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_NVERIFY] = {
-               .op_func = (nfsd4op_func)nfsd4_nverify,
+               .op_func = nfsd4_nverify,
                .op_name = "OP_NVERIFY",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_OPEN] = {
-               .op_func = (nfsd4op_func)nfsd4_open,
+               .op_func = nfsd4_open,
                .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING,
                .op_name = "OP_OPEN",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_open_rsize,
-               .op_set_currentstateid = (stateid_setter)nfsd4_set_openstateid,
+               .op_rsize_bop = nfsd4_open_rsize,
+               .op_set_currentstateid = nfsd4_set_openstateid,
        },
        [OP_OPEN_CONFIRM] = {
-               .op_func = (nfsd4op_func)nfsd4_open_confirm,
+               .op_func = nfsd4_open_confirm,
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_OPEN_CONFIRM",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
+               .op_rsize_bop = nfsd4_status_stateid_rsize,
        },
        [OP_OPEN_DOWNGRADE] = {
-               .op_func = (nfsd4op_func)nfsd4_open_downgrade,
+               .op_func = nfsd4_open_downgrade,
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_OPEN_DOWNGRADE",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
-               .op_get_currentstateid = (stateid_getter)nfsd4_get_opendowngradestateid,
-               .op_set_currentstateid = (stateid_setter)nfsd4_set_opendowngradestateid,
+               .op_rsize_bop = nfsd4_status_stateid_rsize,
+               .op_get_currentstateid = nfsd4_get_opendowngradestateid,
+               .op_set_currentstateid = nfsd4_set_opendowngradestateid,
        },
        [OP_PUTFH] = {
-               .op_func = (nfsd4op_func)nfsd4_putfh,
+               .op_func = nfsd4_putfh,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
                                | OP_IS_PUTFH_LIKE | OP_CLEAR_STATEID,
                .op_name = "OP_PUTFH",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_PUTPUBFH] = {
-               .op_func = (nfsd4op_func)nfsd4_putrootfh,
+               .op_func = nfsd4_putrootfh,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
                                | OP_IS_PUTFH_LIKE | OP_CLEAR_STATEID,
                .op_name = "OP_PUTPUBFH",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_PUTROOTFH] = {
-               .op_func = (nfsd4op_func)nfsd4_putrootfh,
+               .op_func = nfsd4_putrootfh,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
                                | OP_IS_PUTFH_LIKE | OP_CLEAR_STATEID,
                .op_name = "OP_PUTROOTFH",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_READ] = {
-               .op_func = (nfsd4op_func)nfsd4_read,
+               .op_func = nfsd4_read,
                .op_name = "OP_READ",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_read_rsize,
-               .op_get_currentstateid = (stateid_getter)nfsd4_get_readstateid,
+               .op_rsize_bop = nfsd4_read_rsize,
+               .op_get_currentstateid = nfsd4_get_readstateid,
        },
        [OP_READDIR] = {
-               .op_func = (nfsd4op_func)nfsd4_readdir,
+               .op_func = nfsd4_readdir,
                .op_name = "OP_READDIR",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_readdir_rsize,
+               .op_rsize_bop = nfsd4_readdir_rsize,
        },
        [OP_READLINK] = {
-               .op_func = (nfsd4op_func)nfsd4_readlink,
+               .op_func = nfsd4_readlink,
                .op_name = "OP_READLINK",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_readlink_rsize,
+               .op_rsize_bop = nfsd4_readlink_rsize,
        },
        [OP_REMOVE] = {
-               .op_func = (nfsd4op_func)nfsd4_remove,
+               .op_func = nfsd4_remove,
                .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
                .op_name = "OP_REMOVE",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_remove_rsize,
+               .op_rsize_bop = nfsd4_remove_rsize,
        },
        [OP_RENAME] = {
-               .op_func = (nfsd4op_func)nfsd4_rename,
+               .op_func = nfsd4_rename,
                .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
                .op_name = "OP_RENAME",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_rename_rsize,
+               .op_rsize_bop = nfsd4_rename_rsize,
        },
        [OP_RENEW] = {
-               .op_func = (nfsd4op_func)nfsd4_renew,
+               .op_func = nfsd4_renew,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
                                | OP_MODIFIES_SOMETHING,
                .op_name = "OP_RENEW",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
 
        },
        [OP_RESTOREFH] = {
-               .op_func = (nfsd4op_func)nfsd4_restorefh,
+               .op_func = nfsd4_restorefh,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
                                | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
                .op_name = "OP_RESTOREFH",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_SAVEFH] = {
-               .op_func = (nfsd4op_func)nfsd4_savefh,
+               .op_func = nfsd4_savefh,
                .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING,
                .op_name = "OP_SAVEFH",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_SECINFO] = {
-               .op_func = (nfsd4op_func)nfsd4_secinfo,
+               .op_func = nfsd4_secinfo,
                .op_flags = OP_HANDLES_WRONGSEC,
                .op_name = "OP_SECINFO",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_secinfo_rsize,
+               .op_rsize_bop = nfsd4_secinfo_rsize,
        },
        [OP_SETATTR] = {
-               .op_func = (nfsd4op_func)nfsd4_setattr,
+               .op_func = nfsd4_setattr,
                .op_name = "OP_SETATTR",
                .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_setattr_rsize,
-               .op_get_currentstateid = (stateid_getter)nfsd4_get_setattrstateid,
+               .op_rsize_bop = nfsd4_setattr_rsize,
+               .op_get_currentstateid = nfsd4_get_setattrstateid,
        },
        [OP_SETCLIENTID] = {
-               .op_func = (nfsd4op_func)nfsd4_setclientid,
+               .op_func = nfsd4_setclientid,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
                                | OP_MODIFIES_SOMETHING | OP_CACHEME,
                .op_name = "OP_SETCLIENTID",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_setclientid_rsize,
+               .op_rsize_bop = nfsd4_setclientid_rsize,
        },
        [OP_SETCLIENTID_CONFIRM] = {
-               .op_func = (nfsd4op_func)nfsd4_setclientid_confirm,
+               .op_func = nfsd4_setclientid_confirm,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
                                | OP_MODIFIES_SOMETHING | OP_CACHEME,
                .op_name = "OP_SETCLIENTID_CONFIRM",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_VERIFY] = {
-               .op_func = (nfsd4op_func)nfsd4_verify,
+               .op_func = nfsd4_verify,
                .op_name = "OP_VERIFY",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_WRITE] = {
-               .op_func = (nfsd4op_func)nfsd4_write,
+               .op_func = nfsd4_write,
                .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
                .op_name = "OP_WRITE",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize,
-               .op_get_currentstateid = (stateid_getter)nfsd4_get_writestateid,
+               .op_rsize_bop = nfsd4_write_rsize,
+               .op_get_currentstateid = nfsd4_get_writestateid,
        },
        [OP_RELEASE_LOCKOWNER] = {
-               .op_func = (nfsd4op_func)nfsd4_release_lockowner,
+               .op_func = nfsd4_release_lockowner,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
                                | OP_MODIFIES_SOMETHING,
                .op_name = "OP_RELEASE_LOCKOWNER",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
 
        /* NFSv4.1 operations */
        [OP_EXCHANGE_ID] = {
-               .op_func = (nfsd4op_func)nfsd4_exchange_id,
+               .op_func = nfsd4_exchange_id,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
                                | OP_MODIFIES_SOMETHING,
                .op_name = "OP_EXCHANGE_ID",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize,
+               .op_rsize_bop = nfsd4_exchange_id_rsize,
        },
        [OP_BACKCHANNEL_CTL] = {
-               .op_func = (nfsd4op_func)nfsd4_backchannel_ctl,
+               .op_func = nfsd4_backchannel_ctl,
                .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
                .op_name = "OP_BACKCHANNEL_CTL",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_BIND_CONN_TO_SESSION] = {
-               .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session,
+               .op_func = nfsd4_bind_conn_to_session,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
                                | OP_MODIFIES_SOMETHING,
                .op_name = "OP_BIND_CONN_TO_SESSION",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_bind_conn_to_session_rsize,
+               .op_rsize_bop = nfsd4_bind_conn_to_session_rsize,
        },
        [OP_CREATE_SESSION] = {
-               .op_func = (nfsd4op_func)nfsd4_create_session,
+               .op_func = nfsd4_create_session,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
                                | OP_MODIFIES_SOMETHING,
                .op_name = "OP_CREATE_SESSION",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_session_rsize,
+               .op_rsize_bop = nfsd4_create_session_rsize,
        },
        [OP_DESTROY_SESSION] = {
-               .op_func = (nfsd4op_func)nfsd4_destroy_session,
+               .op_func = nfsd4_destroy_session,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
                                | OP_MODIFIES_SOMETHING,
                .op_name = "OP_DESTROY_SESSION",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_SEQUENCE] = {
-               .op_func = (nfsd4op_func)nfsd4_sequence,
+               .op_func = nfsd4_sequence,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
                .op_name = "OP_SEQUENCE",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_sequence_rsize,
+               .op_rsize_bop = nfsd4_sequence_rsize,
        },
        [OP_DESTROY_CLIENTID] = {
-               .op_func = (nfsd4op_func)nfsd4_destroy_clientid,
+               .op_func = nfsd4_destroy_clientid,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
                                | OP_MODIFIES_SOMETHING,
                .op_name = "OP_DESTROY_CLIENTID",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_RECLAIM_COMPLETE] = {
-               .op_func = (nfsd4op_func)nfsd4_reclaim_complete,
+               .op_func = nfsd4_reclaim_complete,
                .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
                .op_name = "OP_RECLAIM_COMPLETE",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_SECINFO_NO_NAME] = {
-               .op_func = (nfsd4op_func)nfsd4_secinfo_no_name,
+               .op_func = nfsd4_secinfo_no_name,
                .op_flags = OP_HANDLES_WRONGSEC,
                .op_name = "OP_SECINFO_NO_NAME",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_secinfo_rsize,
+               .op_rsize_bop = nfsd4_secinfo_rsize,
        },
        [OP_TEST_STATEID] = {
-               .op_func = (nfsd4op_func)nfsd4_test_stateid,
+               .op_func = nfsd4_test_stateid,
                .op_flags = ALLOWED_WITHOUT_FH,
                .op_name = "OP_TEST_STATEID",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_test_stateid_rsize,
+               .op_rsize_bop = nfsd4_test_stateid_rsize,
        },
        [OP_FREE_STATEID] = {
-               .op_func = (nfsd4op_func)nfsd4_free_stateid,
+               .op_func = nfsd4_free_stateid,
                .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
                .op_name = "OP_FREE_STATEID",
-               .op_get_currentstateid = (stateid_getter)nfsd4_get_freestateid,
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_get_currentstateid = nfsd4_get_freestateid,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
 #ifdef CONFIG_NFSD_PNFS
        [OP_GETDEVICEINFO] = {
-               .op_func = (nfsd4op_func)nfsd4_getdeviceinfo,
+               .op_func = nfsd4_getdeviceinfo,
                .op_flags = ALLOWED_WITHOUT_FH,
                .op_name = "OP_GETDEVICEINFO",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_getdeviceinfo_rsize,
+               .op_rsize_bop = nfsd4_getdeviceinfo_rsize,
        },
        [OP_LAYOUTGET] = {
-               .op_func = (nfsd4op_func)nfsd4_layoutget,
+               .op_func = nfsd4_layoutget,
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_LAYOUTGET",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_layoutget_rsize,
+               .op_rsize_bop = nfsd4_layoutget_rsize,
        },
        [OP_LAYOUTCOMMIT] = {
-               .op_func = (nfsd4op_func)nfsd4_layoutcommit,
+               .op_func = nfsd4_layoutcommit,
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_LAYOUTCOMMIT",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_layoutcommit_rsize,
+               .op_rsize_bop = nfsd4_layoutcommit_rsize,
        },
        [OP_LAYOUTRETURN] = {
-               .op_func = (nfsd4op_func)nfsd4_layoutreturn,
+               .op_func = nfsd4_layoutreturn,
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_LAYOUTRETURN",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_layoutreturn_rsize,
+               .op_rsize_bop = nfsd4_layoutreturn_rsize,
        },
 #endif /* CONFIG_NFSD_PNFS */
 
        /* NFSv4.2 operations */
        [OP_ALLOCATE] = {
-               .op_func = (nfsd4op_func)nfsd4_allocate,
+               .op_func = nfsd4_allocate,
                .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
                .op_name = "OP_ALLOCATE",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_DEALLOCATE] = {
-               .op_func = (nfsd4op_func)nfsd4_deallocate,
+               .op_func = nfsd4_deallocate,
                .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
                .op_name = "OP_DEALLOCATE",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_CLONE] = {
-               .op_func = (nfsd4op_func)nfsd4_clone,
+               .op_func = nfsd4_clone,
                .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
                .op_name = "OP_CLONE",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+               .op_rsize_bop = nfsd4_only_status_rsize,
        },
        [OP_COPY] = {
-               .op_func = (nfsd4op_func)nfsd4_copy,
+               .op_func = nfsd4_copy,
                .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
                .op_name = "OP_COPY",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_copy_rsize,
+               .op_rsize_bop = nfsd4_copy_rsize,
        },
        [OP_SEEK] = {
-               .op_func = (nfsd4op_func)nfsd4_seek,
+               .op_func = nfsd4_seek,
                .op_name = "OP_SEEK",
-               .op_rsize_bop = (nfsd4op_rsize)nfsd4_seek_rsize,
+               .op_rsize_bop = nfsd4_seek_rsize,
        },
 };
 
@@ -2515,19 +2531,19 @@ static const char *nfsd4_op_name(unsigned opnum)
 #define nfsd4_voidres                  nfsd4_voidargs
 struct nfsd4_voidargs { int dummy; };
 
-static struct svc_procedure            nfsd_procedures4[2] = {
+static const struct svc_procedure nfsd_procedures4[2] = {
        [NFSPROC4_NULL] = {
-               .pc_func = (svc_procfunc) nfsd4_proc_null,
-               .pc_encode = (kxdrproc_t) nfs4svc_encode_voidres,
+               .pc_func = nfsd4_proc_null,
+               .pc_encode = nfs4svc_encode_voidres,
                .pc_argsize = sizeof(struct nfsd4_voidargs),
                .pc_ressize = sizeof(struct nfsd4_voidres),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = 1,
        },
        [NFSPROC4_COMPOUND] = {
-               .pc_func = (svc_procfunc) nfsd4_proc_compound,
-               .pc_decode = (kxdrproc_t) nfs4svc_decode_compoundargs,
-               .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres,
+               .pc_func = nfsd4_proc_compound,
+               .pc_decode = nfs4svc_decode_compoundargs,
+               .pc_encode = nfs4svc_encode_compoundres,
                .pc_argsize = sizeof(struct nfsd4_compoundargs),
                .pc_ressize = sizeof(struct nfsd4_compoundres),
                .pc_release = nfsd4_release_compoundargs,
@@ -2536,10 +2552,12 @@ static struct svc_procedure             nfsd_procedures4[2] = {
        },
 };
 
-struct svc_version     nfsd_version4 = {
+static unsigned int nfsd_count3[ARRAY_SIZE(nfsd_procedures4)];
+const struct svc_version nfsd_version4 = {
        .vs_vers                = 4,
        .vs_nproc               = 2,
        .vs_proc                = nfsd_procedures4,
+       .vs_count               = nfsd_count3,
        .vs_dispatch            = nfsd_dispatch,
        .vs_xdrsize             = NFS4_SVC_XDRSIZE,
        .vs_rpcb_optnl          = true,
index 22002fb..0c04f81 100644 (file)
@@ -2402,10 +2402,10 @@ static bool client_has_state(struct nfs4_client *clp)
 }
 
 __be32
-nfsd4_exchange_id(struct svc_rqst *rqstp,
-                 struct nfsd4_compound_state *cstate,
-                 struct nfsd4_exchange_id *exid)
+nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
+       struct nfsd4_exchange_id *exid = &u->exchange_id;
        struct nfs4_client *conf, *new;
        struct nfs4_client *unconf = NULL;
        __be32 status;
@@ -2698,9 +2698,9 @@ static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs)
 
 __be32
 nfsd4_create_session(struct svc_rqst *rqstp,
-                    struct nfsd4_compound_state *cstate,
-                    struct nfsd4_create_session *cr_ses)
+               struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
 {
+       struct nfsd4_create_session *cr_ses = &u->create_session;
        struct sockaddr *sa = svc_addr(rqstp);
        struct nfs4_client *conf, *unconf;
        struct nfs4_client *old = NULL;
@@ -2824,8 +2824,11 @@ static __be32 nfsd4_map_bcts_dir(u32 *dir)
        return nfserr_inval;
 }
 
-__be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc)
+__be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp,
+               struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
+       struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl;
        struct nfsd4_session *session = cstate->session;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
        __be32 status;
@@ -2845,8 +2848,9 @@ __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state
 
 __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
                     struct nfsd4_compound_state *cstate,
-                    struct nfsd4_bind_conn_to_session *bcts)
+                    union nfsd4_op_u *u)
 {
+       struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session;
        __be32 status;
        struct nfsd4_conn *conn;
        struct nfsd4_session *session;
@@ -2886,10 +2890,10 @@ static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4
 }
 
 __be32
-nfsd4_destroy_session(struct svc_rqst *r,
-                     struct nfsd4_compound_state *cstate,
-                     struct nfsd4_destroy_session *sessionid)
+nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
+       struct nfsd4_destroy_session *sessionid = &u->destroy_session;
        struct nfsd4_session *ses;
        __be32 status;
        int ref_held_by_me = 0;
@@ -2983,10 +2987,10 @@ static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
 }
 
 __be32
-nfsd4_sequence(struct svc_rqst *rqstp,
-              struct nfsd4_compound_state *cstate,
-              struct nfsd4_sequence *seq)
+nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
+       struct nfsd4_sequence *seq = &u->sequence;
        struct nfsd4_compoundres *resp = rqstp->rq_resp;
        struct xdr_stream *xdr = &resp->xdr;
        struct nfsd4_session *session;
@@ -3120,8 +3124,11 @@ nfsd4_sequence_done(struct nfsd4_compoundres *resp)
 }
 
 __be32
-nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc)
+nfsd4_destroy_clientid(struct svc_rqst *rqstp,
+               struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
+       struct nfsd4_destroy_clientid *dc = &u->destroy_clientid;
        struct nfs4_client *conf, *unconf;
        struct nfs4_client *clp = NULL;
        __be32 status = 0;
@@ -3161,8 +3168,10 @@ out:
 }
 
 __be32
-nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc)
+nfsd4_reclaim_complete(struct svc_rqst *rqstp,
+               struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
 {
+       struct nfsd4_reclaim_complete *rc = &u->reclaim_complete;
        __be32 status = 0;
 
        if (rc->rca_one_fs) {
@@ -3199,8 +3208,9 @@ out:
 
 __be32
 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-                 struct nfsd4_setclientid *setclid)
+                 union nfsd4_op_u *u)
 {
+       struct nfsd4_setclientid *setclid = &u->setclientid;
        struct xdr_netobj       clname = setclid->se_name;
        nfs4_verifier           clverifier = setclid->se_verf;
        struct nfs4_client      *conf, *new;
@@ -3257,9 +3267,11 @@ out:
 
 __be32
 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
-                        struct nfsd4_compound_state *cstate,
-                        struct nfsd4_setclientid_confirm *setclientid_confirm)
+                       struct nfsd4_compound_state *cstate,
+                       union nfsd4_op_u *u)
 {
+       struct nfsd4_setclientid_confirm *setclientid_confirm =
+                       &u->setclientid_confirm;
        struct nfs4_client *conf, *unconf;
        struct nfs4_client *old = NULL;
        nfs4_verifier confirm = setclientid_confirm->sc_confirm; 
@@ -4506,8 +4518,9 @@ void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
 
 __be32
 nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-           clientid_t *clid)
+           union nfsd4_op_u *u)
 {
+       clientid_t *clid = &u->renew;
        struct nfs4_client *clp;
        __be32 status;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
@@ -4993,8 +5006,9 @@ out:
  */
 __be32
 nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-                  struct nfsd4_test_stateid *test_stateid)
+                  union nfsd4_op_u *u)
 {
+       struct nfsd4_test_stateid *test_stateid = &u->test_stateid;
        struct nfsd4_test_stateid_id *stateid;
        struct nfs4_client *cl = cstate->session->se_client;
 
@@ -5033,8 +5047,9 @@ out:
 
 __be32
 nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-                  struct nfsd4_free_stateid *free_stateid)
+                  union nfsd4_op_u *u)
 {
+       struct nfsd4_free_stateid *free_stateid = &u->free_stateid;
        stateid_t *stateid = &free_stateid->fr_stateid;
        struct nfs4_stid *s;
        struct nfs4_delegation *dp;
@@ -5162,8 +5177,9 @@ static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cs
 
 __be32
 nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-                  struct nfsd4_open_confirm *oc)
+                  union nfsd4_op_u *u)
 {
+       struct nfsd4_open_confirm *oc = &u->open_confirm;
        __be32 status;
        struct nfs4_openowner *oo;
        struct nfs4_ol_stateid *stp;
@@ -5230,9 +5246,9 @@ static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_ac
 
 __be32
 nfsd4_open_downgrade(struct svc_rqst *rqstp,
-                    struct nfsd4_compound_state *cstate,
-                    struct nfsd4_open_downgrade *od)
+                    struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
 {
+       struct nfsd4_open_downgrade *od = &u->open_downgrade;
        __be32 status;
        struct nfs4_ol_stateid *stp;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
@@ -5300,8 +5316,9 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
  */
 __be32
 nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-           struct nfsd4_close *close)
+               union nfsd4_op_u *u)
 {
+       struct nfsd4_close *close = &u->close;
        __be32 status;
        struct nfs4_ol_stateid *stp;
        struct net *net = SVC_NET(rqstp);
@@ -5330,8 +5347,9 @@ out:
 
 __be32
 nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-                 struct nfsd4_delegreturn *dr)
+                 union nfsd4_op_u *u)
 {
+       struct nfsd4_delegreturn *dr = &u->delegreturn;
        struct nfs4_delegation *dp;
        stateid_t *stateid = &dr->dr_stateid;
        struct nfs4_stid *s;
@@ -5706,8 +5724,9 @@ out:
  */
 __be32
 nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-          struct nfsd4_lock *lock)
+          union nfsd4_op_u *u)
 {
+       struct nfsd4_lock *lock = &u->lock;
        struct nfs4_openowner *open_sop = NULL;
        struct nfs4_lockowner *lock_sop = NULL;
        struct nfs4_ol_stateid *lock_stp = NULL;
@@ -5939,8 +5958,9 @@ static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct
  */
 __be32
 nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-           struct nfsd4_lockt *lockt)
+           union nfsd4_op_u *u)
 {
+       struct nfsd4_lockt *lockt = &u->lockt;
        struct file_lock *file_lock = NULL;
        struct nfs4_lockowner *lo = NULL;
        __be32 status;
@@ -6012,8 +6032,9 @@ out:
 
 __be32
 nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-           struct nfsd4_locku *locku)
+           union nfsd4_op_u *u)
 {
+       struct nfsd4_locku *locku = &u->locku;
        struct nfs4_ol_stateid *stp;
        struct file *filp = NULL;
        struct file_lock *file_lock = NULL;
@@ -6119,8 +6140,9 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
 __be32
 nfsd4_release_lockowner(struct svc_rqst *rqstp,
                        struct nfsd4_compound_state *cstate,
-                       struct nfsd4_release_lockowner *rlockowner)
+                       union nfsd4_op_u *u)
 {
+       struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner;
        clientid_t *clid = &rlockowner->rl_clientid;
        struct nfs4_stateowner *sop;
        struct nfs4_lockowner *lo = NULL;
@@ -7103,27 +7125,31 @@ clear_current_stateid(struct nfsd4_compound_state *cstate)
  * functions to set current state id
  */
 void
-nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
+nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
-       put_stateid(cstate, &odp->od_stateid);
+       put_stateid(cstate, &u->open_downgrade.od_stateid);
 }
 
 void
-nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
+nfsd4_set_openstateid(struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
-       put_stateid(cstate, &open->op_stateid);
+       put_stateid(cstate, &u->open.op_stateid);
 }
 
 void
-nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
+nfsd4_set_closestateid(struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
-       put_stateid(cstate, &close->cl_stateid);
+       put_stateid(cstate, &u->close.cl_stateid);
 }
 
 void
-nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock)
+nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
-       put_stateid(cstate, &lock->lk_resp_stateid);
+       put_stateid(cstate, &u->lock.lk_resp_stateid);
 }
 
 /*
@@ -7131,49 +7157,57 @@ nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lo
  */
 
 void
-nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
+nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
-       get_stateid(cstate, &odp->od_stateid);
+       get_stateid(cstate, &u->open_downgrade.od_stateid);
 }
 
 void
-nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp)
+nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
-       get_stateid(cstate, &drp->dr_stateid);
+       get_stateid(cstate, &u->delegreturn.dr_stateid);
 }
 
 void
-nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp)
+nfsd4_get_freestateid(struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
-       get_stateid(cstate, &fsp->fr_stateid);
+       get_stateid(cstate, &u->free_stateid.fr_stateid);
 }
 
 void
-nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr)
+nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
-       get_stateid(cstate, &setattr->sa_stateid);
+       get_stateid(cstate, &u->setattr.sa_stateid);
 }
 
 void
-nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
+nfsd4_get_closestateid(struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
-       get_stateid(cstate, &close->cl_stateid);
+       get_stateid(cstate, &u->close.cl_stateid);
 }
 
 void
-nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku)
+nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
-       get_stateid(cstate, &locku->lu_stateid);
+       get_stateid(cstate, &u->locku.lu_stateid);
 }
 
 void
-nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read)
+nfsd4_get_readstateid(struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
-       get_stateid(cstate, &read->rd_stateid);
+       get_stateid(cstate, &u->read.rd_stateid);
 }
 
 void
-nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write)
+nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
+               union nfsd4_op_u *u)
 {
-       get_stateid(cstate, &write->wr_stateid);
+       get_stateid(cstate, &u->write.wr_stateid);
 }
index 26780d5..20fbcab 100644 (file)
@@ -1973,7 +1973,7 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
                *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
                *p++ = 0;
        } else if (IS_I_VERSION(inode)) {
-               p = xdr_encode_hyper(p, inode->i_version);
+               p = xdr_encode_hyper(p, nfsd4_change_attribute(inode));
        } else {
                *p++ = cpu_to_be32(stat->ctime.tv_sec);
                *p++ = cpu_to_be32(stat->ctime.tv_nsec);
@@ -4538,14 +4538,13 @@ nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op)
 }
 
 int
-nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p)
 {
         return xdr_ressize_check(rqstp, p);
 }
 
-int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp)
+void nfsd4_release_compoundargs(struct svc_rqst *rqstp)
 {
-       struct svc_rqst *rqstp = rq;
        struct nfsd4_compoundargs *args = rqstp->rq_argp;
 
        if (args->ops != args->iops) {
@@ -4559,12 +4558,13 @@ int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp)
                args->to_free = tb->next;
                kfree(tb);
        }
-       return 1;
 }
 
 int
-nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args)
+nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd4_compoundargs *args = rqstp->rq_argp;
+
        if (rqstp->rq_arg.head[0].iov_len % 4) {
                /* client is nuts */
                dprintk("%s: compound not properly padded! (peeraddr=%pISc xid=0x%x)",
@@ -4584,11 +4584,12 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_comp
 }
 
 int
-nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp)
+nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p)
 {
        /*
         * All that remains is to write the tag and operation count...
         */
+       struct nfsd4_compoundres *resp = rqstp->rq_resp;
        struct xdr_buf *buf = resp->xdr.buf;
 
        WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len +
index d966068..b9c538a 100644 (file)
@@ -60,7 +60,7 @@ struct readdir_cd {
 
 
 extern struct svc_program      nfsd_program;
-extern struct svc_version      nfsd_version2, nfsd_version3,
+extern const struct svc_version        nfsd_version2, nfsd_version3,
                                nfsd_version4;
 extern struct mutex            nfsd_mutex;
 extern spinlock_t              nfsd_drc_lock;
@@ -86,12 +86,12 @@ void                nfsd_destroy(struct net *net);
 
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 #ifdef CONFIG_NFSD_V2_ACL
-extern struct svc_version nfsd_acl_version2;
+extern const struct svc_version nfsd_acl_version2;
 #else
 #define nfsd_acl_version2 NULL
 #endif
 #ifdef CONFIG_NFSD_V3_ACL
-extern struct svc_version nfsd_acl_version3;
+extern const struct svc_version nfsd_acl_version3;
 #else
 #define nfsd_acl_version3 NULL
 #endif
index f84fe6b..e47cf6c 100644 (file)
@@ -241,6 +241,28 @@ fh_clear_wcc(struct svc_fh *fhp)
 }
 
 /*
+ * We could use i_version alone as the change attribute.  However,
+ * i_version can go backwards after a reboot.  On its own that doesn't
+ * necessarily cause a problem, but if i_version goes backwards and then
+ * is incremented again it could reuse a value that was previously used
+ * before boot, and a client who queried the two values might
+ * incorrectly assume nothing changed.
+ *
+ * By using both ctime and the i_version counter we guarantee that as
+ * long as time doesn't go backwards we never reuse an old value.
+ */
+static inline u64 nfsd4_change_attribute(struct inode *inode)
+{
+       u64 chattr;
+
+       chattr =  inode->i_ctime.tv_sec;
+       chattr <<= 30;
+       chattr += inode->i_ctime.tv_nsec;
+       chattr += inode->i_version;
+       return chattr;
+}
+
+/*
  * Fill in the pre_op attr for the wcc data
  */
 static inline void
@@ -253,7 +275,7 @@ fill_pre_wcc(struct svc_fh *fhp)
                fhp->fh_pre_mtime = inode->i_mtime;
                fhp->fh_pre_ctime = inode->i_ctime;
                fhp->fh_pre_size  = inode->i_size;
-               fhp->fh_pre_change = inode->i_version;
+               fhp->fh_pre_change = nfsd4_change_attribute(inode);
                fhp->fh_pre_saved = true;
        }
 }
index 03a7e9d..5076ae2 100644 (file)
@@ -17,7 +17,7 @@ typedef struct svc_buf        svc_buf;
 
 
 static __be32
-nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+nfsd_proc_null(struct svc_rqst *rqstp)
 {
        return nfs_ok;
 }
@@ -39,9 +39,10 @@ nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp)
  * N.B. After this call resp->fh needs an fh_put
  */
 static __be32
-nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
-                                         struct nfsd_attrstat *resp)
+nfsd_proc_getattr(struct svc_rqst *rqstp)
 {
+       struct nfsd_fhandle *argp = rqstp->rq_argp;
+       struct nfsd_attrstat *resp = rqstp->rq_resp;
        __be32 nfserr;
        dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
 
@@ -56,9 +57,10 @@ nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
  * N.B. After this call resp->fh needs an fh_put
  */
 static __be32
-nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
-                                         struct nfsd_attrstat  *resp)
+nfsd_proc_setattr(struct svc_rqst *rqstp)
 {
+       struct nfsd_sattrargs *argp = rqstp->rq_argp;
+       struct nfsd_attrstat *resp = rqstp->rq_resp;
        struct iattr *iap = &argp->attrs;
        struct svc_fh *fhp;
        __be32 nfserr;
@@ -122,9 +124,10 @@ done:
  * N.B. After this call resp->fh needs an fh_put
  */
 static __be32
-nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
-                                        struct nfsd_diropres  *resp)
+nfsd_proc_lookup(struct svc_rqst *rqstp)
 {
+       struct nfsd_diropargs *argp = rqstp->rq_argp;
+       struct nfsd_diropres *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: LOOKUP   %s %.*s\n",
@@ -142,9 +145,10 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
  * Read a symlink.
  */
 static __be32
-nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp,
-                                          struct nfsd_readlinkres *resp)
+nfsd_proc_readlink(struct svc_rqst *rqstp)
 {
+       struct nfsd_readlinkargs *argp = rqstp->rq_argp;
+       struct nfsd_readlinkres *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
@@ -162,9 +166,10 @@ nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp,
  * N.B. After this call resp->fh needs an fh_put
  */
 static __be32
-nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
-                                      struct nfsd_readres  *resp)
+nfsd_proc_read(struct svc_rqst *rqstp)
 {
+       struct nfsd_readargs *argp = rqstp->rq_argp;
+       struct nfsd_readres *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: READ    %s %d bytes at %d\n",
@@ -200,9 +205,10 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
  * N.B. After this call resp->fh needs an fh_put
  */
 static __be32
-nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
-                                       struct nfsd_attrstat  *resp)
+nfsd_proc_write(struct svc_rqst *rqstp)
 {
+       struct nfsd_writeargs *argp = rqstp->rq_argp;
+       struct nfsd_attrstat *resp = rqstp->rq_resp;
        __be32  nfserr;
        unsigned long cnt = argp->len;
 
@@ -222,9 +228,10 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
  * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
  */
 static __be32
-nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
-                                        struct nfsd_diropres   *resp)
+nfsd_proc_create(struct svc_rqst *rqstp)
 {
+       struct nfsd_createargs *argp = rqstp->rq_argp;
+       struct nfsd_diropres *resp = rqstp->rq_resp;
        svc_fh          *dirfhp = &argp->fh;
        svc_fh          *newfhp = &resp->fh;
        struct iattr    *attr = &argp->attrs;
@@ -377,9 +384,9 @@ done:
 }
 
 static __be32
-nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
-                                        void                  *resp)
+nfsd_proc_remove(struct svc_rqst *rqstp)
 {
+       struct nfsd_diropargs *argp = rqstp->rq_argp;
        __be32  nfserr;
 
        dprintk("nfsd: REMOVE   %s %.*s\n", SVCFH_fmt(&argp->fh),
@@ -392,9 +399,9 @@ nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
 }
 
 static __be32
-nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
-                                        void                   *resp)
+nfsd_proc_rename(struct svc_rqst *rqstp)
 {
+       struct nfsd_renameargs *argp = rqstp->rq_argp;
        __be32  nfserr;
 
        dprintk("nfsd: RENAME   %s %.*s -> \n",
@@ -410,9 +417,9 @@ nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
 }
 
 static __be32
-nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
-                               void                        *resp)
+nfsd_proc_link(struct svc_rqst *rqstp)
 {
+       struct nfsd_linkargs *argp = rqstp->rq_argp;
        __be32  nfserr;
 
        dprintk("nfsd: LINK     %s ->\n",
@@ -430,9 +437,9 @@ nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
 }
 
 static __be32
-nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
-                                         void                    *resp)
+nfsd_proc_symlink(struct svc_rqst *rqstp)
 {
+       struct nfsd_symlinkargs *argp = rqstp->rq_argp;
        struct svc_fh   newfh;
        __be32          nfserr;
 
@@ -460,9 +467,10 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
  * N.B. After this call resp->fh needs an fh_put
  */
 static __be32
-nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
-                                       struct nfsd_diropres   *resp)
+nfsd_proc_mkdir(struct svc_rqst *rqstp)
 {
+       struct nfsd_createargs *argp = rqstp->rq_argp;
+       struct nfsd_diropres *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: MKDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
@@ -484,9 +492,9 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
  * Remove a directory
  */
 static __be32
-nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
-                                       void                  *resp)
+nfsd_proc_rmdir(struct svc_rqst *rqstp)
 {
+       struct nfsd_diropargs *argp = rqstp->rq_argp;
        __be32  nfserr;
 
        dprintk("nfsd: RMDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
@@ -500,9 +508,10 @@ nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
  * Read a portion of a directory.
  */
 static __be32
-nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
-                                         struct nfsd_readdirres  *resp)
+nfsd_proc_readdir(struct svc_rqst *rqstp)
 {
+       struct nfsd_readdirargs *argp = rqstp->rq_argp;
+       struct nfsd_readdirres *resp = rqstp->rq_resp;
        int             count;
        __be32          nfserr;
        loff_t          offset;
@@ -540,9 +549,10 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
  * Get file system info
  */
 static __be32
-nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle   *argp,
-                                         struct nfsd_statfsres *resp)
+nfsd_proc_statfs(struct svc_rqst *rqstp)
 {
+       struct nfsd_fhandle *argp = rqstp->rq_argp;
+       struct nfsd_statfsres *resp = rqstp->rq_resp;
        __be32  nfserr;
 
        dprintk("nfsd: STATFS   %s\n", SVCFH_fmt(&argp->fh));
@@ -563,168 +573,168 @@ struct nfsd_void { int dummy; };
 #define FH 8           /* filehandle */
 #define        AT 18           /* attributes */
 
-static struct svc_procedure            nfsd_procedures2[18] = {
+static const struct svc_procedure nfsd_procedures2[18] = {
        [NFSPROC_NULL] = {
-               .pc_func = (svc_procfunc) nfsd_proc_null,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_void,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_void,
+               .pc_func = nfsd_proc_null,
+               .pc_decode = nfssvc_decode_void,
+               .pc_encode = nfssvc_encode_void,
                .pc_argsize = sizeof(struct nfsd_void),
                .pc_ressize = sizeof(struct nfsd_void),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST,
        },
        [NFSPROC_GETATTR] = {
-               .pc_func = (svc_procfunc) nfsd_proc_getattr,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat,
-               .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
+               .pc_func = nfsd_proc_getattr,
+               .pc_decode = nfssvc_decode_fhandle,
+               .pc_encode = nfssvc_encode_attrstat,
+               .pc_release = nfssvc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd_fhandle),
                .pc_ressize = sizeof(struct nfsd_attrstat),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST+AT,
        },
        [NFSPROC_SETATTR] = {
-               .pc_func = (svc_procfunc) nfsd_proc_setattr,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_sattrargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat,
-               .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
+               .pc_func = nfsd_proc_setattr,
+               .pc_decode = nfssvc_decode_sattrargs,
+               .pc_encode = nfssvc_encode_attrstat,
+               .pc_release = nfssvc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd_sattrargs),
                .pc_ressize = sizeof(struct nfsd_attrstat),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+AT,
        },
        [NFSPROC_ROOT] = {
-               .pc_decode = (kxdrproc_t) nfssvc_decode_void,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_void,
+               .pc_decode = nfssvc_decode_void,
+               .pc_encode = nfssvc_encode_void,
                .pc_argsize = sizeof(struct nfsd_void),
                .pc_ressize = sizeof(struct nfsd_void),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST,
        },
        [NFSPROC_LOOKUP] = {
-               .pc_func = (svc_procfunc) nfsd_proc_lookup,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_diropres,
-               .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
+               .pc_func = nfsd_proc_lookup,
+               .pc_decode = nfssvc_decode_diropargs,
+               .pc_encode = nfssvc_encode_diropres,
+               .pc_release = nfssvc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd_diropargs),
                .pc_ressize = sizeof(struct nfsd_diropres),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST+FH+AT,
        },
        [NFSPROC_READLINK] = {
-               .pc_func = (svc_procfunc) nfsd_proc_readlink,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_readlinkargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_readlinkres,
+               .pc_func = nfsd_proc_readlink,
+               .pc_decode = nfssvc_decode_readlinkargs,
+               .pc_encode = nfssvc_encode_readlinkres,
                .pc_argsize = sizeof(struct nfsd_readlinkargs),
                .pc_ressize = sizeof(struct nfsd_readlinkres),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4,
        },
        [NFSPROC_READ] = {
-               .pc_func = (svc_procfunc) nfsd_proc_read,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_readargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_readres,
-               .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
+               .pc_func = nfsd_proc_read,
+               .pc_decode = nfssvc_decode_readargs,
+               .pc_encode = nfssvc_encode_readres,
+               .pc_release = nfssvc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd_readargs),
                .pc_ressize = sizeof(struct nfsd_readres),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4,
        },
        [NFSPROC_WRITECACHE] = {
-               .pc_decode = (kxdrproc_t) nfssvc_decode_void,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_void,
+               .pc_decode = nfssvc_decode_void,
+               .pc_encode = nfssvc_encode_void,
                .pc_argsize = sizeof(struct nfsd_void),
                .pc_ressize = sizeof(struct nfsd_void),
                .pc_cachetype = RC_NOCACHE,
                .pc_xdrressize = ST,
        },
        [NFSPROC_WRITE] = {
-               .pc_func = (svc_procfunc) nfsd_proc_write,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_writeargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat,
-               .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
+               .pc_func = nfsd_proc_write,
+               .pc_decode = nfssvc_decode_writeargs,
+               .pc_encode = nfssvc_encode_attrstat,
+               .pc_release = nfssvc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd_writeargs),
                .pc_ressize = sizeof(struct nfsd_attrstat),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+AT,
        },
        [NFSPROC_CREATE] = {
-               .pc_func = (svc_procfunc) nfsd_proc_create,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_createargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_diropres,
-               .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
+               .pc_func = nfsd_proc_create,
+               .pc_decode = nfssvc_decode_createargs,
+               .pc_encode = nfssvc_encode_diropres,
+               .pc_release = nfssvc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd_createargs),
                .pc_ressize = sizeof(struct nfsd_diropres),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+FH+AT,
        },
        [NFSPROC_REMOVE] = {
-               .pc_func = (svc_procfunc) nfsd_proc_remove,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_void,
+               .pc_func = nfsd_proc_remove,
+               .pc_decode = nfssvc_decode_diropargs,
+               .pc_encode = nfssvc_encode_void,
                .pc_argsize = sizeof(struct nfsd_diropargs),
                .pc_ressize = sizeof(struct nfsd_void),
                .pc_cachetype = RC_REPLSTAT,
                .pc_xdrressize = ST,
        },
        [NFSPROC_RENAME] = {
-               .pc_func = (svc_procfunc) nfsd_proc_rename,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_renameargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_void,
+               .pc_func = nfsd_proc_rename,
+               .pc_decode = nfssvc_decode_renameargs,
+               .pc_encode = nfssvc_encode_void,
                .pc_argsize = sizeof(struct nfsd_renameargs),
                .pc_ressize = sizeof(struct nfsd_void),
                .pc_cachetype = RC_REPLSTAT,
                .pc_xdrressize = ST,
        },
        [NFSPROC_LINK] = {
-               .pc_func = (svc_procfunc) nfsd_proc_link,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_linkargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_void,
+               .pc_func = nfsd_proc_link,
+               .pc_decode = nfssvc_decode_linkargs,
+               .pc_encode = nfssvc_encode_void,
                .pc_argsize = sizeof(struct nfsd_linkargs),
                .pc_ressize = sizeof(struct nfsd_void),
                .pc_cachetype = RC_REPLSTAT,
                .pc_xdrressize = ST,
        },
        [NFSPROC_SYMLINK] = {
-               .pc_func = (svc_procfunc) nfsd_proc_symlink,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_symlinkargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_void,
+               .pc_func = nfsd_proc_symlink,
+               .pc_decode = nfssvc_decode_symlinkargs,
+               .pc_encode = nfssvc_encode_void,
                .pc_argsize = sizeof(struct nfsd_symlinkargs),
                .pc_ressize = sizeof(struct nfsd_void),
                .pc_cachetype = RC_REPLSTAT,
                .pc_xdrressize = ST,
        },
        [NFSPROC_MKDIR] = {
-               .pc_func = (svc_procfunc) nfsd_proc_mkdir,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_createargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_diropres,
-               .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
+               .pc_func = nfsd_proc_mkdir,
+               .pc_decode = nfssvc_decode_createargs,
+               .pc_encode = nfssvc_encode_diropres,
+               .pc_release = nfssvc_release_fhandle,
                .pc_argsize = sizeof(struct nfsd_createargs),
                .pc_ressize = sizeof(struct nfsd_diropres),
                .pc_cachetype = RC_REPLBUFF,
                .pc_xdrressize = ST+FH+AT,
        },
        [NFSPROC_RMDIR] = {
-               .pc_func = (svc_procfunc) nfsd_proc_rmdir,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_void,
+               .pc_func = nfsd_proc_rmdir,
+               .pc_decode = nfssvc_decode_diropargs,
+               .pc_encode = nfssvc_encode_void,
                .pc_argsize = sizeof(struct nfsd_diropargs),
                .pc_ressize = sizeof(struct nfsd_void),
                .pc_cachetype = RC_REPLSTAT,
                .pc_xdrressize = ST,
        },
        [NFSPROC_READDIR] = {
-               .pc_func = (svc_procfunc) nfsd_proc_readdir,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_readdirargs,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_readdirres,
+               .pc_func = nfsd_proc_readdir,
+               .pc_decode = nfssvc_decode_readdirargs,
+               .pc_encode = nfssvc_encode_readdirres,
                .pc_argsize = sizeof(struct nfsd_readdirargs),
                .pc_ressize = sizeof(struct nfsd_readdirres),
                .pc_cachetype = RC_NOCACHE,
        },
        [NFSPROC_STATFS] = {
-               .pc_func = (svc_procfunc) nfsd_proc_statfs,
-               .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle,
-               .pc_encode = (kxdrproc_t) nfssvc_encode_statfsres,
+               .pc_func = nfsd_proc_statfs,
+               .pc_decode = nfssvc_decode_fhandle,
+               .pc_encode = nfssvc_encode_statfsres,
                .pc_argsize = sizeof(struct nfsd_fhandle),
                .pc_ressize = sizeof(struct nfsd_statfsres),
                .pc_cachetype = RC_NOCACHE,
@@ -733,12 +743,14 @@ static struct svc_procedure               nfsd_procedures2[18] = {
 };
 
 
-struct svc_version     nfsd_version2 = {
-               .vs_vers        = 2,
-               .vs_nproc       = 18,
-               .vs_proc        = nfsd_procedures2,
-               .vs_dispatch    = nfsd_dispatch,
-               .vs_xdrsize     = NFS2_SVC_XDRSIZE,
+static unsigned int nfsd_count2[ARRAY_SIZE(nfsd_procedures2)];
+const struct svc_version nfsd_version2 = {
+       .vs_vers        = 2,
+       .vs_nproc       = 18,
+       .vs_proc        = nfsd_procedures2,
+       .vs_count       = nfsd_count2,
+       .vs_dispatch    = nfsd_dispatch,
+       .vs_xdrsize     = NFS2_SVC_XDRSIZE,
 };
 
 /*
index 59979f0..063ae7d 100644 (file)
@@ -68,14 +68,14 @@ unsigned long       nfsd_drc_mem_used;
 
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 static struct svc_stat nfsd_acl_svcstats;
-static struct svc_version *    nfsd_acl_version[] = {
+static const struct svc_version *nfsd_acl_version[] = {
        [2] = &nfsd_acl_version2,
        [3] = &nfsd_acl_version3,
 };
 
 #define NFSD_ACL_MINVERS            2
 #define NFSD_ACL_NRVERS                ARRAY_SIZE(nfsd_acl_version)
-static struct svc_version *nfsd_acl_versions[NFSD_ACL_NRVERS];
+static const struct svc_version *nfsd_acl_versions[NFSD_ACL_NRVERS];
 
 static struct svc_program      nfsd_acl_program = {
        .pg_prog                = NFS_ACL_PROGRAM,
@@ -92,7 +92,7 @@ static struct svc_stat        nfsd_acl_svcstats = {
 };
 #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
 
-static struct svc_version *    nfsd_version[] = {
+static const struct svc_version *nfsd_version[] = {
        [2] = &nfsd_version2,
 #if defined(CONFIG_NFSD_V3)
        [3] = &nfsd_version3,
@@ -104,7 +104,7 @@ static struct svc_version * nfsd_version[] = {
 
 #define NFSD_MINVERS           2
 #define NFSD_NRVERS            ARRAY_SIZE(nfsd_version)
-static struct svc_version *nfsd_versions[NFSD_NRVERS];
+static const struct svc_version *nfsd_versions[NFSD_NRVERS];
 
 struct svc_program             nfsd_program = {
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
@@ -756,7 +756,7 @@ static __be32 map_new_errors(u32 vers, __be32 nfserr)
  * problem, we enforce these assumptions here:
  */
 static bool nfs_request_too_big(struct svc_rqst *rqstp,
-                               struct svc_procedure *proc)
+                               const struct svc_procedure *proc)
 {
        /*
         * The ACL code has more careful bounds-checking and is not
@@ -781,8 +781,7 @@ static bool nfs_request_too_big(struct svc_rqst *rqstp,
 int
 nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
 {
-       struct svc_procedure    *proc;
-       kxdrproc_t              xdr;
+       const struct svc_procedure *proc;
        __be32                  nfserr;
        __be32                  *nfserrp;
 
@@ -801,9 +800,8 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
         */
        rqstp->rq_cachetype = proc->pc_cachetype;
        /* Decode arguments */
-       xdr = proc->pc_decode;
-       if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base,
-                       rqstp->rq_argp)) {
+       if (proc->pc_decode &&
+           !proc->pc_decode(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base)) {
                dprintk("nfsd: failed to decode arguments!\n");
                *statp = rpc_garbage_args;
                return 1;
@@ -827,7 +825,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
        rqstp->rq_res.head[0].iov_len += sizeof(__be32);
 
        /* Now call the procedure handler, and encode NFS status. */
-       nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
+       nfserr = proc->pc_func(rqstp);
        nfserr = map_new_errors(rqstp->rq_vers, nfserr);
        if (nfserr == nfserr_dropit || test_bit(RQ_DROPME, &rqstp->rq_flags)) {
                dprintk("nfsd: Dropping request; may be revisited later\n");
@@ -842,9 +840,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
         * For NFSv2, additional info is never returned in case of an error.
         */
        if (!(nfserr && rqstp->rq_vers == 2)) {
-               xdr = proc->pc_encode;
-               if (xdr && !xdr(rqstp, nfserrp,
-                               rqstp->rq_resp)) {
+               if (proc->pc_encode && !proc->pc_encode(rqstp, nfserrp)) {
                        /* Failed to encode result. Release cache entry */
                        dprintk("nfsd: failed to encode result!\n");
                        nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
index de07ff6..e4da271 100644 (file)
@@ -206,14 +206,16 @@ __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *f
  * XDR decode functions
  */
 int
-nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p)
 {
        return xdr_argsize_check(rqstp, p);
 }
 
 int
-nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
+nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_fhandle *args = rqstp->rq_argp;
+
        p = decode_fh(p, &args->fh);
        if (!p)
                return 0;
@@ -221,9 +223,10 @@ nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *ar
 }
 
 int
-nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_sattrargs *args)
+nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_sattrargs *args = rqstp->rq_argp;
+
        p = decode_fh(p, &args->fh);
        if (!p)
                return 0;
@@ -233,9 +236,10 @@ nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_diropargs *args)
+nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_diropargs *args = rqstp->rq_argp;
+
        if (!(p = decode_fh(p, &args->fh))
         || !(p = decode_filename(p, &args->name, &args->len)))
                return 0;
@@ -244,9 +248,9 @@ nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_readargs *args)
+nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_readargs *args = rqstp->rq_argp;
        unsigned int len;
        int v;
        p = decode_fh(p, &args->fh);
@@ -276,9 +280,9 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_writeargs *args)
+nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_writeargs *args = rqstp->rq_argp;
        unsigned int len, hdr, dlen;
        struct kvec *head = rqstp->rq_arg.head;
        int v;
@@ -332,9 +336,10 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_createargs *args)
+nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_createargs *args = rqstp->rq_argp;
+
        if (   !(p = decode_fh(p, &args->fh))
            || !(p = decode_filename(p, &args->name, &args->len)))
                return 0;
@@ -344,9 +349,10 @@ nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_renameargs *args)
+nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_renameargs *args = rqstp->rq_argp;
+
        if (!(p = decode_fh(p, &args->ffh))
         || !(p = decode_filename(p, &args->fname, &args->flen))
         || !(p = decode_fh(p, &args->tfh))
@@ -357,8 +363,10 @@ nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readlinkargs *args)
+nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_readlinkargs *args = rqstp->rq_argp;
+
        p = decode_fh(p, &args->fh);
        if (!p)
                return 0;
@@ -368,9 +376,10 @@ nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readli
 }
 
 int
-nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_linkargs *args)
+nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_linkargs *args = rqstp->rq_argp;
+
        if (!(p = decode_fh(p, &args->ffh))
         || !(p = decode_fh(p, &args->tfh))
         || !(p = decode_filename(p, &args->tname, &args->tlen)))
@@ -380,9 +389,10 @@ nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_symlinkargs *args)
+nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_symlinkargs *args = rqstp->rq_argp;
+
        if (   !(p = decode_fh(p, &args->ffh))
            || !(p = decode_filename(p, &args->fname, &args->flen))
            || !(p = decode_pathname(p, &args->tname, &args->tlen)))
@@ -393,9 +403,10 @@ nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_readdirargs *args)
+nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_readdirargs *args = rqstp->rq_argp;
+
        p = decode_fh(p, &args->fh);
        if (!p)
                return 0;
@@ -411,32 +422,35 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
  * XDR encode functions
  */
 int
-nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
+nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
 {
        return xdr_ressize_check(rqstp, p);
 }
 
 int
-nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_attrstat *resp)
+nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_attrstat *resp = rqstp->rq_resp;
+
        p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
        return xdr_ressize_check(rqstp, p);
 }
 
 int
-nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_diropres *resp)
+nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_diropres *resp = rqstp->rq_resp;
+
        p = encode_fh(p, &resp->fh);
        p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
        return xdr_ressize_check(rqstp, p);
 }
 
 int
-nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_readlinkres *resp)
+nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_readlinkres *resp = rqstp->rq_resp;
+
        *p++ = htonl(resp->len);
        xdr_ressize_check(rqstp, p);
        rqstp->rq_res.page_len = resp->len;
@@ -450,9 +464,10 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_readres *resp)
+nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_readres *resp = rqstp->rq_resp;
+
        p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
        *p++ = htonl(resp->count);
        xdr_ressize_check(rqstp, p);
@@ -469,9 +484,10 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_readdirres *resp)
+nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_readdirres *resp = rqstp->rq_resp;
+
        xdr_ressize_check(rqstp, p);
        p = resp->buffer;
        *p++ = 0;                       /* no more entries */
@@ -482,9 +498,9 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
 }
 
 int
-nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_statfsres *resp)
+nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p)
 {
+       struct nfsd_statfsres *resp = rqstp->rq_resp;
        struct kstatfs  *stat = &resp->stats;
 
        *p++ = htonl(NFSSVC_MAXBLKSIZE_V2);     /* max transfer size */
@@ -543,10 +559,10 @@ nfssvc_encode_entry(void *ccdv, const char *name,
 /*
  * XDR release functions
  */
-int
-nfssvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
-                                       struct nfsd_fhandle *resp)
+void
+nfssvc_release_fhandle(struct svc_rqst *rqstp)
 {
+       struct nfsd_fhandle *resp = rqstp->rq_resp;
+
        fh_put(&resp->fh);
-       return 1;
 }
index 4f0481d..457ce45 100644 (file)
@@ -131,40 +131,30 @@ union nfsd_xdrstore {
 #define NFS2_SVC_XDRSIZE       sizeof(union nfsd_xdrstore)
 
 
-int nfssvc_decode_void(struct svc_rqst *, __be32 *, void *);
-int nfssvc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
-int nfssvc_decode_sattrargs(struct svc_rqst *, __be32 *,
-                               struct nfsd_sattrargs *);
-int nfssvc_decode_diropargs(struct svc_rqst *, __be32 *,
-                               struct nfsd_diropargs *);
-int nfssvc_decode_readargs(struct svc_rqst *, __be32 *,
-                               struct nfsd_readargs *);
-int nfssvc_decode_writeargs(struct svc_rqst *, __be32 *,
-                               struct nfsd_writeargs *);
-int nfssvc_decode_createargs(struct svc_rqst *, __be32 *,
-                               struct nfsd_createargs *);
-int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *,
-                               struct nfsd_renameargs *);
-int nfssvc_decode_readlinkargs(struct svc_rqst *, __be32 *,
-                               struct nfsd_readlinkargs *);
-int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *,
-                               struct nfsd_linkargs *);
-int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *,
-                               struct nfsd_symlinkargs *);
-int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *,
-                               struct nfsd_readdirargs *);
-int nfssvc_encode_void(struct svc_rqst *, __be32 *, void *);
-int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *, struct nfsd_attrstat *);
-int nfssvc_encode_diropres(struct svc_rqst *, __be32 *, struct nfsd_diropres *);
-int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *, struct nfsd_readlinkres *);
-int nfssvc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd_readres *);
-int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *, struct nfsd_statfsres *);
-int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *, struct nfsd_readdirres *);
+int nfssvc_decode_void(struct svc_rqst *, __be32 *);
+int nfssvc_decode_fhandle(struct svc_rqst *, __be32 *);
+int nfssvc_decode_sattrargs(struct svc_rqst *, __be32 *);
+int nfssvc_decode_diropargs(struct svc_rqst *, __be32 *);
+int nfssvc_decode_readargs(struct svc_rqst *, __be32 *);
+int nfssvc_decode_writeargs(struct svc_rqst *, __be32 *);
+int nfssvc_decode_createargs(struct svc_rqst *, __be32 *);
+int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *);
+int nfssvc_decode_readlinkargs(struct svc_rqst *, __be32 *);
+int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *);
+int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *);
+int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *);
+int nfssvc_encode_void(struct svc_rqst *, __be32 *);
+int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *);
+int nfssvc_encode_diropres(struct svc_rqst *, __be32 *);
+int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *);
+int nfssvc_encode_readres(struct svc_rqst *, __be32 *);
+int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *);
+int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *);
 
 int nfssvc_encode_entry(void *, const char *name,
                        int namlen, loff_t offset, u64 ino, unsigned int);
 
-int nfssvc_release_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
+void nfssvc_release_fhandle(struct svc_rqst *);
 
 /* Helper functions for NFSv2 ACL code */
 __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat);
index 335e04a..80d7da6 100644 (file)
@@ -269,71 +269,41 @@ union nfsd3_xdrstore {
 
 #define NFS3_SVC_XDRSIZE               sizeof(union nfsd3_xdrstore)
 
-int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
-int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_sattrargs *);
-int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_diropargs *);
-int nfs3svc_decode_accessargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_accessargs *);
-int nfs3svc_decode_readargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_readargs *);
-int nfs3svc_decode_writeargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_writeargs *);
-int nfs3svc_decode_createargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_createargs *);
-int nfs3svc_decode_mkdirargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_createargs *);
-int nfs3svc_decode_mknodargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_mknodargs *);
-int nfs3svc_decode_renameargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_renameargs *);
-int nfs3svc_decode_readlinkargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_readlinkargs *);
-int nfs3svc_decode_linkargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_linkargs *);
-int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_symlinkargs *);
-int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_readdirargs *);
-int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_readdirargs *);
-int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *,
-                               struct nfsd3_commitargs *);
-int nfs3svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
-int nfs3svc_encode_attrstat(struct svc_rqst *, __be32 *,
-                               struct nfsd3_attrstat *);
-int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *,
-                               struct nfsd3_attrstat *);
-int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *,
-                               struct nfsd3_diropres *);
-int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *,
-                               struct nfsd3_accessres *);
-int nfs3svc_encode_readlinkres(struct svc_rqst *, __be32 *,
-                               struct nfsd3_readlinkres *);
-int nfs3svc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd3_readres *);
-int nfs3svc_encode_writeres(struct svc_rqst *, __be32 *, struct nfsd3_writeres *);
-int nfs3svc_encode_createres(struct svc_rqst *, __be32 *,
-                               struct nfsd3_diropres *);
-int nfs3svc_encode_renameres(struct svc_rqst *, __be32 *,
-                               struct nfsd3_renameres *);
-int nfs3svc_encode_linkres(struct svc_rqst *, __be32 *,
-                               struct nfsd3_linkres *);
-int nfs3svc_encode_readdirres(struct svc_rqst *, __be32 *,
-                               struct nfsd3_readdirres *);
-int nfs3svc_encode_fsstatres(struct svc_rqst *, __be32 *,
-                               struct nfsd3_fsstatres *);
-int nfs3svc_encode_fsinfores(struct svc_rqst *, __be32 *,
-                               struct nfsd3_fsinfores *);
-int nfs3svc_encode_pathconfres(struct svc_rqst *, __be32 *,
-                               struct nfsd3_pathconfres *);
-int nfs3svc_encode_commitres(struct svc_rqst *, __be32 *,
-                               struct nfsd3_commitres *);
-
-int nfs3svc_release_fhandle(struct svc_rqst *, __be32 *,
-                               struct nfsd3_attrstat *);
-int nfs3svc_release_fhandle2(struct svc_rqst *, __be32 *,
-                               struct nfsd3_fhandle_pair *);
+int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_accessargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_readargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_writeargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_createargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_mkdirargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_mknodargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_renameargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_readlinkargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_linkargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *);
+int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_voidres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_attrstat(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_readlinkres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_readres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_writeres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_createres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_renameres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_linkres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_readdirres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_fsstatres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_fsinfores(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_pathconfres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_commitres(struct svc_rqst *, __be32 *);
+
+void nfs3svc_release_fhandle(struct svc_rqst *);
+void nfs3svc_release_fhandle2(struct svc_rqst *);
 int nfs3svc_encode_entry(void *, const char *name,
                                int namlen, loff_t offset, u64 ino,
                                unsigned int);
index 8fda4ab..72c6ad1 100644 (file)
@@ -539,7 +539,7 @@ struct nfsd4_seek {
 struct nfsd4_op {
        int                                     opnum;
        __be32                                  status;
-       union {
+       union nfsd4_op_u {
                struct nfsd4_access             access;
                struct nfsd4_close              close;
                struct nfsd4_commit             commit;
@@ -577,6 +577,7 @@ struct nfsd4_op {
                struct nfsd4_bind_conn_to_session bind_conn_to_session;
                struct nfsd4_create_session     create_session;
                struct nfsd4_destroy_session    destroy_session;
+               struct nfsd4_destroy_clientid   destroy_clientid;
                struct nfsd4_sequence           sequence;
                struct nfsd4_reclaim_complete   reclaim_complete;
                struct nfsd4_test_stateid       test_stateid;
@@ -585,6 +586,7 @@ struct nfsd4_op {
                struct nfsd4_layoutget          layoutget;
                struct nfsd4_layoutcommit       layoutcommit;
                struct nfsd4_layoutreturn       layoutreturn;
+               struct nfsd4_secinfo_no_name    secinfo_no_name;
 
                /* NFSv4.2 */
                struct nfsd4_fallocate          allocate;
@@ -682,11 +684,9 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
 
 
 bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp);
-int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
-int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *,
-               struct nfsd4_compoundargs *);
-int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *,
-               struct nfsd4_compoundres *);
+int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *);
+int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *);
+int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *);
 __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32);
 void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
 void nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op);
@@ -695,27 +695,26 @@ __be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words,
                struct dentry *dentry,
                u32 *bmval, struct svc_rqst *, int ignore_crossmnt);
 extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *,
-               struct nfsd4_setclientid *setclid);
+               struct nfsd4_compound_state *, union nfsd4_op_u *u);
 extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *,
-               struct nfsd4_setclientid_confirm *setclientid_confirm);
+               struct nfsd4_compound_state *, union nfsd4_op_u *u);
 extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *, struct nfsd4_exchange_id *);
-extern __be32 nfsd4_backchannel_ctl(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_backchannel_ctl *);
-extern __be32 nfsd4_bind_conn_to_session(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_bind_conn_to_session *);
+               struct nfsd4_compound_state *, union nfsd4_op_u *u);
+extern __be32 nfsd4_backchannel_ctl(struct svc_rqst *,
+               struct nfsd4_compound_state *, union nfsd4_op_u *u);
+extern __be32 nfsd4_bind_conn_to_session(struct svc_rqst *,
+               struct nfsd4_compound_state *, union nfsd4_op_u *u);
 extern __be32 nfsd4_create_session(struct svc_rqst *,
-               struct nfsd4_compound_state *,
-               struct nfsd4_create_session *);
+               struct nfsd4_compound_state *, union nfsd4_op_u *u);
 extern __be32 nfsd4_sequence(struct svc_rqst *,
-               struct nfsd4_compound_state *,
-               struct nfsd4_sequence *);
+               struct nfsd4_compound_state *, union nfsd4_op_u *u);
 extern void nfsd4_sequence_done(struct nfsd4_compoundres *resp);
 extern __be32 nfsd4_destroy_session(struct svc_rqst *,
-               struct nfsd4_compound_state *,
-               struct nfsd4_destroy_session *);
-extern __be32 nfsd4_destroy_clientid(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_destroy_clientid *);
-__be32 nfsd4_reclaim_complete(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_reclaim_complete *);
+               struct nfsd4_compound_state *, union nfsd4_op_u *u);
+extern __be32 nfsd4_destroy_clientid(struct svc_rqst *, struct nfsd4_compound_state *,
+               union nfsd4_op_u *u);
+__be32 nfsd4_reclaim_complete(struct svc_rqst *, struct nfsd4_compound_state *,
+               union nfsd4_op_u *u);
 extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *,
                struct nfsd4_open *open, struct nfsd_net *nn);
 extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp,
@@ -724,34 +723,29 @@ extern void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate);
 extern void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
                struct nfsd4_open *open);
 extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *, struct nfsd4_open_confirm *oc);
-extern __be32 nfsd4_close(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *,
-               struct nfsd4_close *close);
+               struct nfsd4_compound_state *, union nfsd4_op_u *u);
+extern __be32 nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *,
+               union nfsd4_op_u *u);
 extern __be32 nfsd4_open_downgrade(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *,
-               struct nfsd4_open_downgrade *od);
+               struct nfsd4_compound_state *, union nfsd4_op_u *u);
 extern __be32 nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *,
-               struct nfsd4_lock *lock);
-extern __be32 nfsd4_lockt(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *,
-               struct nfsd4_lockt *lockt);
-extern __be32 nfsd4_locku(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *,
-               struct nfsd4_locku *locku);
+               union nfsd4_op_u *u);
+extern __be32 nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *,
+               union nfsd4_op_u *u);
+extern __be32 nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *,
+               union nfsd4_op_u *u);
 extern __be32
 nfsd4_release_lockowner(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *,
-               struct nfsd4_release_lockowner *rlockowner);
-extern int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp);
+               struct nfsd4_compound_state *, union nfsd4_op_u *u);
+extern void nfsd4_release_compoundargs(struct svc_rqst *rqstp);
 extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr);
-extern __be32 nfsd4_renew(struct svc_rqst *rqstp,
-                         struct nfsd4_compound_state *, clientid_t *clid);
+               struct nfsd4_compound_state *, union nfsd4_op_u *u);
+extern __be32 nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *,
+               union nfsd4_op_u *u);
 extern __be32 nfsd4_test_stateid(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *, struct nfsd4_test_stateid *test_stateid);
+               struct nfsd4_compound_state *, union nfsd4_op_u *);
 extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
-               struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
+               struct nfsd4_compound_state *, union nfsd4_op_u *);
 extern void nfsd4_bump_seqid(struct nfsd4_compound_state *, __be32 nfserr);
 
 #endif
index f3db56e..08127a2 100644 (file)
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -53,7 +53,6 @@ static void nsfs_evict(struct inode *inode)
 static void *__ns_get_path(struct path *path, struct ns_common *ns)
 {
        struct vfsmount *mnt = nsfs_mnt;
-       struct qstr qname = { .name = "", };
        struct dentry *dentry;
        struct inode *inode;
        unsigned long d;
@@ -85,7 +84,7 @@ slow:
        inode->i_fop = &ns_file_operations;
        inode->i_private = ns;
 
-       dentry = d_alloc_pseudo(mnt->mnt_sb, &qname);
+       dentry = d_alloc_pseudo(mnt->mnt_sb, &empty_name);
        if (!dentry) {
                iput(inode);
                return ERR_PTR(-ENOMEM);
index 8c9034e..ee14af9 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/buffer_head.h>
 #include <linux/vmalloc.h>
 #include <linux/writeback.h>
+#include <linux/seq_file.h>
 #include <linux/crc-itu-t.h>
 #include "omfs.h"
 
@@ -290,12 +291,40 @@ static int omfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0;
 }
 
+/*
+ * Display the mount options in /proc/mounts.
+ */
+static int omfs_show_options(struct seq_file *m, struct dentry *root)
+{
+       struct omfs_sb_info *sbi = OMFS_SB(root->d_sb);
+       umode_t cur_umask = current_umask();
+
+       if (!uid_eq(sbi->s_uid, current_uid()))
+               seq_printf(m, ",uid=%u",
+                          from_kuid_munged(&init_user_ns, sbi->s_uid));
+       if (!gid_eq(sbi->s_gid, current_gid()))
+               seq_printf(m, ",gid=%u",
+                          from_kgid_munged(&init_user_ns, sbi->s_gid));
+
+       if (sbi->s_dmask == sbi->s_fmask) {
+               if (sbi->s_fmask != cur_umask)
+                       seq_printf(m, ",umask=%o", sbi->s_fmask);
+       } else {
+               if (sbi->s_dmask != cur_umask)
+                       seq_printf(m, ",dmask=%o", sbi->s_dmask);
+               if (sbi->s_fmask != cur_umask)
+                       seq_printf(m, ",fmask=%o", sbi->s_fmask);
+       }
+
+       return 0;
+}
+
 static const struct super_operations omfs_sops = {
        .write_inode    = omfs_write_inode,
        .evict_inode    = omfs_evict_inode,
        .put_super      = omfs_put_super,
        .statfs         = omfs_statfs,
-       .show_options   = generic_show_options,
+       .show_options   = omfs_show_options,
 };
 
 /*
@@ -434,8 +463,6 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent)
        struct inode *root;
        int ret = -EINVAL;
 
-       save_mount_options(sb, (char *) data);
-
        sbi = kzalloc(sizeof(struct omfs_sb_info), GFP_KERNEL);
        if (!sbi)
                return -ENOMEM;
index 5c7c273..5a1bed6 100644 (file)
@@ -35,6 +35,19 @@ static const match_table_t tokens = {
 
 uint64_t orangefs_features;
 
+static int orangefs_show_options(struct seq_file *m, struct dentry *root)
+{
+       struct orangefs_sb_info_s *orangefs_sb = ORANGEFS_SB(root->d_sb);
+
+       if (root->d_sb->s_flags & MS_POSIXACL)
+               seq_puts(m, ",acl");
+       if (orangefs_sb->flags & ORANGEFS_OPT_INTR)
+               seq_puts(m, ",intr");
+       if (orangefs_sb->flags & ORANGEFS_OPT_LOCAL_LOCK)
+               seq_puts(m, ",local_lock");
+       return 0;
+}
+
 static int parse_mount_options(struct super_block *sb, char *options,
                int silent)
 {
@@ -305,7 +318,7 @@ static const struct super_operations orangefs_s_ops = {
        .drop_inode = generic_delete_inode,
        .statfs = orangefs_statfs,
        .remount_fs = orangefs_remount_fs,
-       .show_options = generic_show_options,
+       .show_options = orangefs_show_options,
 };
 
 static struct dentry *orangefs_fh_to_dentry(struct super_block *sb,
index 641d9ee..48b70e6 100644 (file)
@@ -481,17 +481,30 @@ out_cleanup:
 }
 
 static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
-                             struct cattr *attr, struct dentry *hardlink)
+                             struct cattr *attr, struct dentry *hardlink,
+                             bool origin)
 {
        int err;
        const struct cred *old_cred;
        struct cred *override_cred;
+       struct dentry *parent = dentry->d_parent;
 
-       err = ovl_copy_up(dentry->d_parent);
+       err = ovl_copy_up(parent);
        if (err)
                return err;
 
        old_cred = ovl_override_creds(dentry->d_sb);
+
+       /*
+        * When linking a file with copy up origin into a new parent, mark the
+        * new parent dir "impure".
+        */
+       if (origin) {
+               err = ovl_set_impure(parent, ovl_dentry_upper(parent));
+               if (err)
+                       goto out_revert_creds;
+       }
+
        err = -ENOMEM;
        override_cred = prepare_creds();
        if (override_cred) {
@@ -550,7 +563,7 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
        inode_init_owner(inode, dentry->d_parent->d_inode, mode);
        attr.mode = inode->i_mode;
 
-       err = ovl_create_or_link(dentry, inode, &attr, NULL);
+       err = ovl_create_or_link(dentry, inode, &attr, NULL, false);
        if (err)
                iput(inode);
 
@@ -609,7 +622,8 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
        inode = d_inode(old);
        ihold(inode);
 
-       err = ovl_create_or_link(new, inode, NULL, ovl_dentry_upper(old));
+       err = ovl_create_or_link(new, inode, NULL, ovl_dentry_upper(old),
+                                ovl_type_origin(old));
        if (err)
                iput(inode);
 
index 69f4fc2..5bc7164 100644 (file)
@@ -202,37 +202,38 @@ bool ovl_is_private_xattr(const char *name)
                       sizeof(OVL_XATTR_PREFIX) - 1) == 0;
 }
 
-int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value,
-                 size_t size, int flags)
+int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
+                 const void *value, size_t size, int flags)
 {
        int err;
-       struct path realpath;
-       enum ovl_path_type type = ovl_path_real(dentry, &realpath);
+       struct dentry *upperdentry = ovl_i_dentry_upper(inode);
+       struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
        const struct cred *old_cred;
 
        err = ovl_want_write(dentry);
        if (err)
                goto out;
 
-       if (!value && !OVL_TYPE_UPPER(type)) {
-               err = vfs_getxattr(realpath.dentry, name, NULL, 0);
+       if (!value && !upperdentry) {
+               err = vfs_getxattr(realdentry, name, NULL, 0);
                if (err < 0)
                        goto out_drop_write;
        }
 
-       err = ovl_copy_up(dentry);
-       if (err)
-               goto out_drop_write;
+       if (!upperdentry) {
+               err = ovl_copy_up(dentry);
+               if (err)
+                       goto out_drop_write;
 
-       if (!OVL_TYPE_UPPER(type))
-               ovl_path_upper(dentry, &realpath);
+               realdentry = ovl_dentry_upper(dentry);
+       }
 
        old_cred = ovl_override_creds(dentry->d_sb);
        if (value)
-               err = vfs_setxattr(realpath.dentry, name, value, size, flags);
+               err = vfs_setxattr(realdentry, name, value, size, flags);
        else {
                WARN_ON(flags != XATTR_REPLACE);
-               err = vfs_removexattr(realpath.dentry, name);
+               err = vfs_removexattr(realdentry, name);
        }
        revert_creds(old_cred);
 
@@ -242,12 +243,13 @@ out:
        return err;
 }
 
-int ovl_xattr_get(struct dentry *dentry, const char *name,
+int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
                  void *value, size_t size)
 {
-       struct dentry *realdentry = ovl_dentry_real(dentry);
        ssize_t res;
        const struct cred *old_cred;
+       struct dentry *realdentry =
+               ovl_i_dentry_upper(inode) ?: ovl_dentry_lower(dentry);
 
        old_cred = ovl_override_creds(dentry->d_sb);
        res = vfs_getxattr(realdentry, name, value, size);
index 9bc0e58..8aef2b3 100644 (file)
@@ -397,8 +397,19 @@ int ovl_verify_index(struct dentry *index, struct path *lowerstack,
        if (!d_inode(index))
                return 0;
 
-       err = -EISDIR;
-       if (d_is_dir(index))
+       /*
+        * Directory index entries are going to be used for looking up
+        * redirected upper dirs by lower dir fh when decoding an overlay
+        * file handle of a merge dir. Whiteout index entries are going to be
+        * used as an indication that an exported overlay file handle should
+        * be treated as stale (i.e. after unlink of the overlay inode).
+        * We don't know the verification rules for directory and whiteout
+        * index entries, because they have not been implemented yet, so return
+        * EROFS if those entries are found to avoid corrupting an index that
+        * was created by a newer kernel.
+        */
+       err = -EROFS;
+       if (d_is_dir(index) || ovl_is_whiteout(index))
                goto fail;
 
        err = -EINVAL;
@@ -436,8 +447,8 @@ out:
        return err;
 
 fail:
-       pr_warn_ratelimited("overlayfs: failed to verify index (%pd2, err=%i)\n",
-                           index, err);
+       pr_warn_ratelimited("overlayfs: failed to verify index (%pd2, ftype=%x, err=%i)\n",
+                           index, d_inode(index)->i_mode & S_IFMT, err);
        goto out;
 }
 
@@ -502,6 +513,7 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry,
                goto out;
        }
 
+       inode = d_inode(index);
        if (d_is_negative(index)) {
                if (upper && d_inode(origin)->i_nlink > 1) {
                        pr_warn_ratelimited("overlayfs: hard link with origin but no index (ino=%lu).\n",
@@ -511,11 +523,22 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry,
 
                dput(index);
                index = NULL;
-       } else if (upper && d_inode(index) != d_inode(upper)) {
-               inode = d_inode(index);
-               pr_warn_ratelimited("overlayfs: wrong index found (index ino: %lu, upper ino: %lu).\n",
-                                   d_inode(index)->i_ino,
-                                   d_inode(upper)->i_ino);
+       } else if (upper && d_inode(upper) != inode) {
+               pr_warn_ratelimited("overlayfs: wrong index found (index=%pd2, ino=%lu, upper ino=%lu).\n",
+                                   index, inode->i_ino, d_inode(upper)->i_ino);
+               goto fail;
+       } else if (ovl_dentry_weird(index) || ovl_is_whiteout(index) ||
+                  ((inode->i_mode ^ d_inode(origin)->i_mode) & S_IFMT)) {
+               /*
+                * Index should always be of the same file type as origin
+                * except for the case of a whiteout index. A whiteout
+                * index should only exist if all lower aliases have been
+                * unlinked, which means that finding a lower origin on lookup
+                * whose index is a whiteout should be treated as an error.
+                */
+               pr_warn_ratelimited("overlayfs: bad index found (index=%pd2, ftype=%x, origin ftype=%x).\n",
+                                   index, d_inode(index)->i_mode & S_IFMT,
+                                   d_inode(origin)->i_mode & S_IFMT);
                goto fail;
        }
 
index 60d2660..e927a62 100644 (file)
@@ -47,7 +47,8 @@ enum ovl_flag {
 /* Is the real inode encoded in fid an upper inode? */
 #define OVL_FH_FLAG_PATH_UPPER (1 << 2)
 
-#define OVL_FH_FLAG_ALL (OVL_FH_FLAG_BIG_ENDIAN | OVL_FH_FLAG_ANY_ENDIAN)
+#define OVL_FH_FLAG_ALL (OVL_FH_FLAG_BIG_ENDIAN | OVL_FH_FLAG_ANY_ENDIAN | \
+                        OVL_FH_FLAG_PATH_UPPER)
 
 #if defined(__LITTLE_ENDIAN)
 #define OVL_FH_FLAG_CPU_ENDIAN 0
@@ -199,6 +200,7 @@ enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path);
 struct dentry *ovl_dentry_upper(struct dentry *dentry);
 struct dentry *ovl_dentry_lower(struct dentry *dentry);
 struct dentry *ovl_dentry_real(struct dentry *dentry);
+struct dentry *ovl_i_dentry_upper(struct inode *inode);
 struct inode *ovl_inode_upper(struct inode *inode);
 struct inode *ovl_inode_lower(struct inode *inode);
 struct inode *ovl_inode_real(struct inode *inode);
@@ -270,9 +272,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr);
 int ovl_getattr(const struct path *path, struct kstat *stat,
                u32 request_mask, unsigned int flags);
 int ovl_permission(struct inode *inode, int mask);
-int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value,
-                 size_t size, int flags);
-int ovl_xattr_get(struct dentry *dentry, const char *name,
+int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
+                 const void *value, size_t size, int flags);
+int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
                  void *value, size_t size);
 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
 struct posix_acl *ovl_get_acl(struct inode *inode, int type);
index 0298463..3d424a5 100644 (file)
@@ -703,7 +703,10 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
                        err = PTR_ERR(index);
                        break;
                }
-               if (ovl_verify_index(index, lowerstack, numlower)) {
+               err = ovl_verify_index(index, lowerstack, numlower);
+               if (err) {
+                       if (err == -EROFS)
+                               break;
                        err = ovl_cleanup(dir, index);
                        if (err)
                                break;
index 44dc2d6..d86e89f 100644 (file)
@@ -692,7 +692,7 @@ ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
                        struct dentry *dentry, struct inode *inode,
                        const char *name, void *buffer, size_t size)
 {
-       return ovl_xattr_get(dentry, handler->name, buffer, size);
+       return ovl_xattr_get(dentry, inode, handler->name, buffer, size);
 }
 
 static int __maybe_unused
@@ -742,7 +742,7 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
                        return err;
        }
 
-       err = ovl_xattr_set(dentry, handler->name, value, size, flags);
+       err = ovl_xattr_set(dentry, inode, handler->name, value, size, flags);
        if (!err)
                ovl_copyattr(ovl_inode_real(inode), inode);
 
@@ -772,7 +772,7 @@ static int ovl_other_xattr_get(const struct xattr_handler *handler,
                               struct dentry *dentry, struct inode *inode,
                               const char *name, void *buffer, size_t size)
 {
-       return ovl_xattr_get(dentry, name, buffer, size);
+       return ovl_xattr_get(dentry, inode, name, buffer, size);
 }
 
 static int ovl_other_xattr_set(const struct xattr_handler *handler,
@@ -780,7 +780,7 @@ static int ovl_other_xattr_set(const struct xattr_handler *handler,
                               const char *name, const void *value,
                               size_t size, int flags)
 {
-       return ovl_xattr_set(dentry, name, value, size, flags);
+       return ovl_xattr_set(dentry, inode, name, value, size, flags);
 }
 
 static const struct xattr_handler __maybe_unused
@@ -1058,10 +1058,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
                ufs->indexdir = ovl_workdir_create(sb, ufs, workpath.dentry,
                                                   OVL_INDEXDIR_NAME, true);
-               err = PTR_ERR(ufs->indexdir);
-               if (IS_ERR(ufs->indexdir))
-                       goto out_put_lower_mnt;
-
                if (ufs->indexdir) {
                        /* Verify upper root is index dir origin */
                        err = ovl_verify_origin(ufs->indexdir, ufs->upper_mnt,
@@ -1090,6 +1086,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        else
                sb->s_d_op = &ovl_dentry_operations;
 
+       err = -ENOMEM;
        ufs->creator_cred = cred = prepare_creds();
        if (!cred)
                goto out_put_indexdir;
index c492ba7..f46ad75 100644 (file)
@@ -157,9 +157,14 @@ struct dentry *ovl_dentry_real(struct dentry *dentry)
        return ovl_dentry_upper(dentry) ?: ovl_dentry_lower(dentry);
 }
 
+struct dentry *ovl_i_dentry_upper(struct inode *inode)
+{
+       return ovl_upperdentry_dereference(OVL_I(inode));
+}
+
 struct inode *ovl_inode_upper(struct inode *inode)
 {
-       struct dentry *upperdentry = ovl_upperdentry_dereference(OVL_I(inode));
+       struct dentry *upperdentry = ovl_i_dentry_upper(inode);
 
        return upperdentry ? d_inode(upperdentry) : NULL;
 }
index 73b84ba..97e5be8 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -739,13 +739,12 @@ int create_pipe_files(struct file **res, int flags)
        struct inode *inode = get_pipe_inode();
        struct file *f;
        struct path path;
-       static struct qstr name = { .name = "" };
 
        if (!inode)
                return -ENFILE;
 
        err = -ENOMEM;
-       path.dentry = d_alloc_pseudo(pipe_mnt->mnt_sb, &name);
+       path.dentry = d_alloc_pseudo(pipe_mnt->mnt_sb, &empty_name);
        if (!path.dentry)
                goto err_inode;
        path.mnt = mntget(pipe_mnt);
index f1e1927..719c2e9 100644 (file)
@@ -1355,6 +1355,49 @@ static const struct file_operations proc_fault_inject_operations = {
        .write          = proc_fault_inject_write,
        .llseek         = generic_file_llseek,
 };
+
+static ssize_t proc_fail_nth_write(struct file *file, const char __user *buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct task_struct *task;
+       int err;
+       unsigned int n;
+
+       err = kstrtouint_from_user(buf, count, 0, &n);
+       if (err)
+               return err;
+
+       task = get_proc_task(file_inode(file));
+       if (!task)
+               return -ESRCH;
+       WRITE_ONCE(task->fail_nth, n);
+       put_task_struct(task);
+
+       return count;
+}
+
+static ssize_t proc_fail_nth_read(struct file *file, char __user *buf,
+                                 size_t count, loff_t *ppos)
+{
+       struct task_struct *task;
+       char numbuf[PROC_NUMBUF];
+       ssize_t len;
+
+       task = get_proc_task(file_inode(file));
+       if (!task)
+               return -ESRCH;
+       len = snprintf(numbuf, sizeof(numbuf), "%u\n",
+                       READ_ONCE(task->fail_nth));
+       len = simple_read_from_buffer(buf, count, ppos, numbuf, len);
+       put_task_struct(task);
+
+       return len;
+}
+
+static const struct file_operations proc_fail_nth_operations = {
+       .read           = proc_fail_nth_read,
+       .write          = proc_fail_nth_write,
+};
 #endif
 
 
@@ -2919,6 +2962,7 @@ static const struct pid_entry tgid_base_stuff[] = {
 #endif
 #ifdef CONFIG_FAULT_INJECTION
        REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations),
+       REG("fail-nth", 0644, proc_fail_nth_operations),
 #endif
 #ifdef CONFIG_ELF_CORE
        REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations),
@@ -3311,6 +3355,7 @@ static const struct pid_entry tid_base_stuff[] = {
 #endif
 #ifdef CONFIG_FAULT_INJECTION
        REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations),
+       REG("fail-nth", 0644, proc_fail_nth_operations),
 #endif
 #ifdef CONFIG_TASK_IO_ACCOUNTING
        ONE("io",       S_IRUSR, proc_tid_io_accounting),
index c5ae09b..aa2b890 100644 (file)
@@ -51,7 +51,7 @@ struct proc_dir_entry {
        spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */
        u8 namelen;
        char name[];
-};
+} __randomize_layout;
 
 union proc_op {
        int (*proc_get_link)(struct dentry *, struct path *);
@@ -67,10 +67,10 @@ struct proc_inode {
        struct proc_dir_entry *pde;
        struct ctl_table_header *sysctl;
        struct ctl_table *sysctl_entry;
-       struct list_head sysctl_inodes;
+       struct hlist_node sysctl_inodes;
        const struct proc_ns_operations *ns_ops;
        struct inode vfs_inode;
-};
+} __randomize_layout;
 
 /*
  * General functions
@@ -279,7 +279,7 @@ struct proc_maps_private {
 #ifdef CONFIG_NUMA
        struct mempolicy *task_mempolicy;
 #endif
-};
+} __randomize_layout;
 
 struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode);
 
index 67985a7..8f47922 100644 (file)
@@ -191,7 +191,7 @@ static void init_header(struct ctl_table_header *head,
        head->set = set;
        head->parent = NULL;
        head->node = node;
-       INIT_LIST_HEAD(&head->inodes);
+       INIT_HLIST_HEAD(&head->inodes);
        if (node) {
                struct ctl_table *entry;
                for (entry = table; entry->procname; entry++, node++)
@@ -261,25 +261,42 @@ static void unuse_table(struct ctl_table_header *p)
                        complete(p->unregistering);
 }
 
-/* called under sysctl_lock */
 static void proc_sys_prune_dcache(struct ctl_table_header *head)
 {
-       struct inode *inode, *prev = NULL;
+       struct inode *inode;
        struct proc_inode *ei;
+       struct hlist_node *node;
+       struct super_block *sb;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(ei, &head->inodes, sysctl_inodes) {
-               inode = igrab(&ei->vfs_inode);
-               if (inode) {
-                       rcu_read_unlock();
-                       iput(prev);
-                       prev = inode;
-                       d_prune_aliases(inode);
+       for (;;) {
+               node = hlist_first_rcu(&head->inodes);
+               if (!node)
+                       break;
+               ei = hlist_entry(node, struct proc_inode, sysctl_inodes);
+               spin_lock(&sysctl_lock);
+               hlist_del_init_rcu(&ei->sysctl_inodes);
+               spin_unlock(&sysctl_lock);
+
+               inode = &ei->vfs_inode;
+               sb = inode->i_sb;
+               if (!atomic_inc_not_zero(&sb->s_active))
+                       continue;
+               inode = igrab(inode);
+               rcu_read_unlock();
+               if (unlikely(!inode)) {
+                       deactivate_super(sb);
                        rcu_read_lock();
+                       continue;
                }
+
+               d_prune_aliases(inode);
+               iput(inode);
+               deactivate_super(sb);
+
+               rcu_read_lock();
        }
        rcu_read_unlock();
-       iput(prev);
 }
 
 /* called under sysctl_lock, will reacquire if has to wait */
@@ -461,7 +478,7 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
        }
        ei->sysctl = head;
        ei->sysctl_entry = table;
-       list_add_rcu(&ei->sysctl_inodes, &head->inodes);
+       hlist_add_head_rcu(&ei->sysctl_inodes, &head->inodes);
        head->count++;
        spin_unlock(&sysctl_lock);
 
@@ -489,7 +506,7 @@ out:
 void proc_sys_evict_inode(struct inode *inode, struct ctl_table_header *head)
 {
        spin_lock(&sysctl_lock);
-       list_del_rcu(&PROC_I(inode)->sysctl_inodes);
+       hlist_del_init_rcu(&PROC_I(inode)->sysctl_inodes);
        if (!--head->count)
                kfree_rcu(head, rcu);
        spin_unlock(&sysctl_lock);
@@ -1061,16 +1078,30 @@ static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...)
        return -EINVAL;
 }
 
+static int sysctl_check_table_array(const char *path, struct ctl_table *table)
+{
+       int err = 0;
+
+       if ((table->proc_handler == proc_douintvec) ||
+           (table->proc_handler == proc_douintvec_minmax)) {
+               if (table->maxlen != sizeof(unsigned int))
+                       err |= sysctl_err(path, table, "array now allowed");
+       }
+
+       return err;
+}
+
 static int sysctl_check_table(const char *path, struct ctl_table *table)
 {
        int err = 0;
        for (; table->procname; table++) {
                if (table->child)
-                       err = sysctl_err(path, table, "Not a file");
+                       err |= sysctl_err(path, table, "Not a file");
 
                if ((table->proc_handler == proc_dostring) ||
                    (table->proc_handler == proc_dointvec) ||
                    (table->proc_handler == proc_douintvec) ||
+                   (table->proc_handler == proc_douintvec_minmax) ||
                    (table->proc_handler == proc_dointvec_minmax) ||
                    (table->proc_handler == proc_dointvec_jiffies) ||
                    (table->proc_handler == proc_dointvec_userhz_jiffies) ||
@@ -1078,15 +1109,17 @@ static int sysctl_check_table(const char *path, struct ctl_table *table)
                    (table->proc_handler == proc_doulongvec_minmax) ||
                    (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {
                        if (!table->data)
-                               err = sysctl_err(path, table, "No data");
+                               err |= sysctl_err(path, table, "No data");
                        if (!table->maxlen)
-                               err = sysctl_err(path, table, "No maxlen");
+                               err |= sysctl_err(path, table, "No maxlen");
+                       else
+                               err |= sysctl_check_table_array(path, table);
                }
                if (!table->proc_handler)
-                       err = sysctl_err(path, table, "No proc_handler");
+                       err |= sysctl_err(path, table, "No proc_handler");
 
                if ((table->mode & (S_IRUGO|S_IWUGO)) != table->mode)
-                       err = sysctl_err(path, table, "bogus .mode 0%o",
+                       err |= sysctl_err(path, table, "bogus .mode 0%o",
                                table->mode);
        }
        return err;
index 4d02c3b..fefd226 100644 (file)
@@ -283,6 +283,16 @@ static void parse_options(char *options)
        }
 }
 
+/*
+ * Display the mount options in /proc/mounts.
+ */
+static int pstore_show_options(struct seq_file *m, struct dentry *root)
+{
+       if (kmsg_bytes != PSTORE_DEFAULT_KMSG_BYTES)
+               seq_printf(m, ",kmsg_bytes=%lu", kmsg_bytes);
+       return 0;
+}
+
 static int pstore_remount(struct super_block *sb, int *flags, char *data)
 {
        sync_filesystem(sb);
@@ -296,7 +306,7 @@ static const struct super_operations pstore_ops = {
        .drop_inode     = generic_delete_inode,
        .evict_inode    = pstore_evict_inode,
        .remount_fs     = pstore_remount,
-       .show_options   = generic_show_options,
+       .show_options   = pstore_show_options,
 };
 
 static struct super_block *pstore_sb;
@@ -448,8 +458,6 @@ static int pstore_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct inode *inode;
 
-       save_mount_options(sb, data);
-
        pstore_sb = sb;
 
        sb->s_maxbytes          = MAX_LFS_FILESIZE;
index 5805126..7f4e48c 100644 (file)
@@ -5,6 +5,9 @@
 #include <linux/time.h>
 #include <linux/pstore.h>
 
+#define PSTORE_DEFAULT_KMSG_BYTES 10240
+extern unsigned long kmsg_bytes;
+
 #ifdef CONFIG_PSTORE_FTRACE
 extern void pstore_register_ftrace(void);
 extern void pstore_unregister_ftrace(void);
index 1b6e0ff..2b21d18 100644 (file)
@@ -99,7 +99,7 @@ static char *big_oops_buf;
 static size_t big_oops_buf_sz;
 
 /* How much of the console log to snapshot */
-static unsigned long kmsg_bytes = 10240;
+unsigned long kmsg_bytes = PSTORE_DEFAULT_KMSG_BYTES;
 
 void pstore_set_kmsg_bytes(int bytes)
 {
index 26e4586..11201b2 100644 (file)
 #include <linux/uaccess.h>
 #include "internal.h"
 
+struct ramfs_mount_opts {
+       umode_t mode;
+};
+
+struct ramfs_fs_info {
+       struct ramfs_mount_opts mount_opts;
+};
+
 #define RAMFS_DEFAULT_MODE     0755
 
 static const struct super_operations ramfs_ops;
@@ -149,14 +157,22 @@ static const struct inode_operations ramfs_dir_inode_operations = {
        .rename         = simple_rename,
 };
 
+/*
+ * Display the mount options in /proc/mounts.
+ */
+static int ramfs_show_options(struct seq_file *m, struct dentry *root)
+{
+       struct ramfs_fs_info *fsi = root->d_sb->s_fs_info;
+
+       if (fsi->mount_opts.mode != RAMFS_DEFAULT_MODE)
+               seq_printf(m, ",mode=%o", fsi->mount_opts.mode);
+       return 0;
+}
+
 static const struct super_operations ramfs_ops = {
        .statfs         = simple_statfs,
        .drop_inode     = generic_delete_inode,
-       .show_options   = generic_show_options,
-};
-
-struct ramfs_mount_opts {
-       umode_t mode;
+       .show_options   = ramfs_show_options,
 };
 
 enum {
@@ -169,10 +185,6 @@ static const match_table_t tokens = {
        {Opt_err, NULL}
 };
 
-struct ramfs_fs_info {
-       struct ramfs_mount_opts mount_opts;
-};
-
 static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts)
 {
        substring_t args[MAX_OPT_ARGS];
@@ -211,8 +223,6 @@ int ramfs_fill_super(struct super_block *sb, void *data, int silent)
        struct inode *inode;
        int err;
 
-       save_mount_options(sb, data);
-
        fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL);
        sb->s_fs_info = fsi;
        if (!fsi)
index dc198bc..edc8ef7 100644 (file)
@@ -513,9 +513,17 @@ static void __discard_prealloc(struct reiserfs_transaction_handle *th,
                               "inode has negative prealloc blocks count.");
 #endif
        while (ei->i_prealloc_count > 0) {
-               reiserfs_free_prealloc_block(th, inode, ei->i_prealloc_block);
-               ei->i_prealloc_block++;
+               b_blocknr_t block_to_free;
+
+               /*
+                * reiserfs_free_prealloc_block can drop the write lock,
+                * which could allow another caller to free the same block.
+                * We can protect against it by modifying the prealloc
+                * state before calling it.
+                */
+               block_to_free = ei->i_prealloc_block++;
                ei->i_prealloc_count--;
+               reiserfs_free_prealloc_block(th, inode, block_to_free);
                dirty = 1;
        }
        if (dirty)
@@ -1128,7 +1136,7 @@ static int determine_prealloc_size(reiserfs_blocknr_hint_t * hint)
        hint->prealloc_size = 0;
 
        if (!hint->formatted_node && hint->preallocate) {
-               if (S_ISREG(hint->inode->i_mode)
+               if (S_ISREG(hint->inode->i_mode) && !IS_PRIVATE(hint->inode)
                    && hint->inode->i_size >=
                    REISERFS_SB(hint->th->t_super)->s_alloc_options.
                    preallocmin * hint->inode->i_sb->s_blocksize)
index 685f1e0..306e4e9 100644 (file)
@@ -1599,8 +1599,6 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
        }
 
 out_ok_unlocked:
-       if (new_opts)
-               replace_mount_options(s, new_opts);
        return 0;
 
 out_err_unlock:
@@ -1916,8 +1914,6 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        char *qf_names[REISERFS_MAXQUOTAS] = {};
        unsigned int qfmt = 0;
 
-       save_mount_options(s, data);
-
        sbi = kzalloc(sizeof(struct reiserfs_sb_info), GFP_KERNEL);
        if (!sbi)
                return -ENOMEM;
index 3d2256a..54415f0 100644 (file)
@@ -23,7 +23,8 @@ reiserfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        struct reiserfs_transaction_handle th;
        size_t jcreate_blocks;
        int size = acl ? posix_acl_xattr_size(acl->a_count) : 0;
-
+       int update_mode = 0;
+       umode_t mode = inode->i_mode;
 
        /*
         * Pessimism: We can't assume that anything from the xattr root up
@@ -37,7 +38,16 @@ reiserfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        error = journal_begin(&th, inode->i_sb, jcreate_blocks);
        reiserfs_write_unlock(inode->i_sb);
        if (error == 0) {
+               if (type == ACL_TYPE_ACCESS && acl) {
+                       error = posix_acl_update_mode(inode, &mode, &acl);
+                       if (error)
+                               goto unlock;
+                       update_mode = 1;
+               }
                error = __reiserfs_set_acl(&th, inode, type, acl);
+               if (!error && update_mode)
+                       inode->i_mode = mode;
+unlock:
                reiserfs_write_lock(inode->i_sb);
                error2 = journal_end(&th);
                reiserfs_write_unlock(inode->i_sb);
@@ -241,11 +251,6 @@ __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
        switch (type) {
        case ACL_TYPE_ACCESS:
                name = XATTR_NAME_POSIX_ACL_ACCESS;
-               if (acl) {
-                       error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
-                       if (error)
-                               return error;
-               }
                break;
        case ACL_TYPE_DEFAULT:
                name = XATTR_NAME_POSIX_ACL_DEFAULT;
index adb0c0d..6bc3352 100644 (file)
@@ -168,7 +168,6 @@ static void destroy_super(struct super_block *s)
        WARN_ON(!list_empty(&s->s_mounts));
        put_user_ns(s->s_user_ns);
        kfree(s->s_subtype);
-       kfree(s->s_options);
        call_rcu(&s->rcu, destroy_super_rcu);
 }
 
@@ -508,7 +507,7 @@ retry:
                        return ERR_PTR(-ENOMEM);
                goto retry;
        }
-               
+
        err = set(s, data);
        if (err) {
                spin_unlock(&sb_lock);
@@ -771,7 +770,7 @@ restart:
        spin_unlock(&sb_lock);
        return NULL;
 }
+
 struct super_block *user_get_super(dev_t dev)
 {
        struct super_block *sb;
index 328e89c..bea8ad8 100644 (file)
@@ -270,8 +270,6 @@ static int trace_fill_super(struct super_block *sb, void *data, int silent)
        struct tracefs_fs_info *fsi;
        int err;
 
-       save_mount_options(sb, data);
-
        fsi = kzalloc(sizeof(struct tracefs_fs_info), GFP_KERNEL);
        sb->s_fs_info = fsi;
        if (!fsi) {
index 382ed42..114ba45 100644 (file)
@@ -9,8 +9,13 @@ static int ubifs_crypt_get_context(struct inode *inode, void *ctx, size_t len)
 static int ubifs_crypt_set_context(struct inode *inode, const void *ctx,
                                   size_t len, void *fs_data)
 {
+       /*
+        * Creating an encryption context is done unlocked since we
+        * operate on a new inode which is not visible to other users
+        * at this point. So, no need to check whether inode is locked.
+        */
        return ubifs_xattr_set(inode, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT,
-                              ctx, len, 0);
+                              ctx, len, 0, false);
 }
 
 static bool ubifs_crypt_empty_dir(struct inode *inode)
index 566079d..417fe0b 100644 (file)
@@ -143,6 +143,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
        case S_IFBLK:
        case S_IFCHR:
                inode->i_op  = &ubifs_file_inode_operations;
+               encrypted = false;
                break;
        default:
                BUG();
@@ -1061,7 +1062,6 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
        int sz_change;
        int err, devlen = 0;
        struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
-                                       .new_ino_d = ALIGN(devlen, 8),
                                        .dirtied_ino = 1 };
        struct fscrypt_name nm;
 
@@ -1079,6 +1079,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
                devlen = ubifs_encode_dev(dev, rdev);
        }
 
+       req.new_ino_d = ALIGN(devlen, 8);
        err = ubifs_budget_space(c, &req);
        if (err) {
                kfree(dev);
@@ -1396,17 +1397,14 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
 
                dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
                if (!dev) {
-                       ubifs_release_budget(c, &req);
-                       ubifs_release_budget(c, &ino_req);
-                       return -ENOMEM;
+                       err = -ENOMEM;
+                       goto out_release;
                }
 
                err = do_tmpfile(old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE, &whiteout);
                if (err) {
-                       ubifs_release_budget(c, &req);
-                       ubifs_release_budget(c, &ino_req);
                        kfree(dev);
-                       return err;
+                       goto out_release;
                }
 
                whiteout->i_state |= I_LINKABLE;
@@ -1494,12 +1492,10 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
 
                err = ubifs_budget_space(c, &wht_req);
                if (err) {
-                       ubifs_release_budget(c, &req);
-                       ubifs_release_budget(c, &ino_req);
                        kfree(whiteout_ui->data);
                        whiteout_ui->data_len = 0;
                        iput(whiteout);
-                       return err;
+                       goto out_release;
                }
 
                inc_nlink(whiteout);
@@ -1554,6 +1550,7 @@ out_cancel:
                iput(whiteout);
        }
        unlock_4_inodes(old_dir, new_dir, new_inode, whiteout);
+out_release:
        ubifs_release_budget(c, &ino_req);
        ubifs_release_budget(c, &req);
        fscrypt_free_filename(&old_nm);
@@ -1647,6 +1644,21 @@ int ubifs_getattr(const struct path *path, struct kstat *stat,
        struct ubifs_inode *ui = ubifs_inode(inode);
 
        mutex_lock(&ui->ui_mutex);
+
+       if (ui->flags & UBIFS_APPEND_FL)
+               stat->attributes |= STATX_ATTR_APPEND;
+       if (ui->flags & UBIFS_COMPR_FL)
+               stat->attributes |= STATX_ATTR_COMPRESSED;
+       if (ui->flags & UBIFS_CRYPT_FL)
+               stat->attributes |= STATX_ATTR_ENCRYPTED;
+       if (ui->flags & UBIFS_IMMUTABLE_FL)
+               stat->attributes |= STATX_ATTR_IMMUTABLE;
+
+       stat->attributes_mask |= (STATX_ATTR_APPEND |
+                               STATX_ATTR_COMPRESSED |
+                               STATX_ATTR_ENCRYPTED |
+                               STATX_ATTR_IMMUTABLE);
+
        generic_fillattr(inode, stat);
        stat->blksize = UBIFS_BLOCK_SIZE;
        stat->size = ui->ui_size;
index 2cda3d6..8cad0b1 100644 (file)
@@ -735,6 +735,7 @@ static int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu,
        int err, page_idx, page_cnt, ret = 0, n = 0;
        int allocate = bu->buf ? 0 : 1;
        loff_t isize;
+       gfp_t ra_gfp_mask = readahead_gfp_mask(mapping) & ~__GFP_FS;
 
        err = ubifs_tnc_get_bu_keys(c, bu);
        if (err)
@@ -796,8 +797,7 @@ static int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu,
 
                if (page_offset > end_index)
                        break;
-               page = find_or_create_page(mapping, page_offset,
-                                          GFP_NOFS | __GFP_COLD);
+               page = find_or_create_page(mapping, page_offset, ra_gfp_mask);
                if (!page)
                        break;
                if (!PageUptodate(page))
@@ -1284,6 +1284,14 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
        if (err)
                return err;
 
+       if (ubifs_crypt_is_encrypted(inode) && (attr->ia_valid & ATTR_SIZE)) {
+               err = fscrypt_get_encryption_info(inode);
+               if (err)
+                       return err;
+               if (!fscrypt_has_encryption_key(inode))
+                       return -ENOKEY;
+       }
+
        if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size < inode->i_size)
                /* Truncation to a smaller size */
                err = do_truncation(c, inode, attr);
@@ -1607,15 +1615,6 @@ static const struct vm_operations_struct ubifs_file_vm_ops = {
 static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
        int err;
-       struct inode *inode = file->f_mapping->host;
-
-       if (ubifs_crypt_is_encrypted(inode)) {
-               err = fscrypt_get_encryption_info(inode);
-               if (err)
-                       return -EACCES;
-               if (!fscrypt_has_encryption_key(inode))
-                       return -ENOKEY;
-       }
 
        err = generic_file_mmap(file, vma);
        if (err)
@@ -1698,12 +1697,6 @@ static const char *ubifs_get_link(struct dentry *dentry,
 
        pstr.name[pstr.len] = '\0';
 
-       // XXX this probably won't happen anymore...
-       if (pstr.name[0] == '\0') {
-               fscrypt_fname_free_buffer(&pstr);
-               return ERR_PTR(-ENOENT);
-       }
-
        set_delayed_call(done, kfree_link, pstr.name);
        return pstr.name;
 }
index 294519b..04c4ec6 100644 (file)
@@ -549,8 +549,6 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
        struct ubifs_ino_node *ino;
        union ubifs_key dent_key, ino_key;
 
-       //dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu",
-       //      inode->i_ino, nm->len, nm->name, ui->data_len, dir->i_ino);
        ubifs_assert(mutex_is_locked(&host_ui->ui_mutex));
 
        dlen = UBIFS_DENT_NODE_SZ + fname_len(nm) + 1;
@@ -574,7 +572,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
        /* Make sure to also account for extended attributes */
        len += host_ui->data_len;
 
-       dent = kmalloc(len, GFP_NOFS);
+       dent = kzalloc(len, GFP_NOFS);
        if (!dent)
                return -ENOMEM;
 
@@ -585,7 +583,10 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
 
        if (!xent) {
                dent->ch.node_type = UBIFS_DENT_NODE;
-               dent_key_init(c, &dent_key, dir->i_ino, nm);
+               if (nm->hash)
+                       dent_key_init_hash(c, &dent_key, dir->i_ino, nm->hash);
+               else
+                       dent_key_init(c, &dent_key, dir->i_ino, nm);
        } else {
                dent->ch.node_type = UBIFS_XENT_NODE;
                xent_key_init(c, &dent_key, dir->i_ino, nm);
@@ -629,7 +630,10 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
        kfree(dent);
 
        if (deletion) {
-               err = ubifs_tnc_remove_nm(c, &dent_key, nm);
+               if (nm->hash)
+                       err = ubifs_tnc_remove_dh(c, &dent_key, nm->minor_hash);
+               else
+                       err = ubifs_tnc_remove_nm(c, &dent_key, nm);
                if (err)
                        goto out_ro;
                err = ubifs_add_dirt(c, lnum, dlen);
@@ -950,9 +954,6 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
        int twoparents = (fst_dir != snd_dir);
        void *p;
 
-       //dbg_jnl("dent '%pd' in dir ino %lu between dent '%pd' in dir ino %lu",
-       //      fst_dentry, fst_dir->i_ino, snd_dentry, snd_dir->i_ino);
-
        ubifs_assert(ubifs_inode(fst_dir)->data_len == 0);
        ubifs_assert(ubifs_inode(snd_dir)->data_len == 0);
        ubifs_assert(mutex_is_locked(&ubifs_inode(fst_dir)->ui_mutex));
@@ -967,7 +968,7 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
        if (twoparents)
                len += plen;
 
-       dent1 = kmalloc(len, GFP_NOFS);
+       dent1 = kzalloc(len, GFP_NOFS);
        if (!dent1)
                return -ENOMEM;
 
@@ -984,6 +985,7 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
        dent1->nlen = cpu_to_le16(fname_len(snd_nm));
        memcpy(dent1->name, fname_name(snd_nm), fname_len(snd_nm));
        dent1->name[fname_len(snd_nm)] = '\0';
+       set_dent_cookie(c, dent1);
        zero_dent_node_unused(dent1);
        ubifs_prep_grp_node(c, dent1, dlen1, 0);
 
@@ -996,6 +998,7 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
        dent2->nlen = cpu_to_le16(fname_len(fst_nm));
        memcpy(dent2->name, fname_name(fst_nm), fname_len(fst_nm));
        dent2->name[fname_len(fst_nm)] = '\0';
+       set_dent_cookie(c, dent2);
        zero_dent_node_unused(dent2);
        ubifs_prep_grp_node(c, dent2, dlen2, 0);
 
@@ -1094,8 +1097,6 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
        int move = (old_dir != new_dir);
        struct ubifs_inode *uninitialized_var(new_ui);
 
-       //dbg_jnl("dent '%pd' in dir ino %lu to dent '%pd' in dir ino %lu",
-       //      old_dentry, old_dir->i_ino, new_dentry, new_dir->i_ino);
        ubifs_assert(ubifs_inode(old_dir)->data_len == 0);
        ubifs_assert(ubifs_inode(new_dir)->data_len == 0);
        ubifs_assert(mutex_is_locked(&ubifs_inode(old_dir)->ui_mutex));
@@ -1117,7 +1118,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
        len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8);
        if (move)
                len += plen;
-       dent = kmalloc(len, GFP_NOFS);
+       dent = kzalloc(len, GFP_NOFS);
        if (!dent)
                return -ENOMEM;
 
@@ -1298,7 +1299,9 @@ static int truncate_data_node(const struct ubifs_info *c, const struct inode *in
                        goto out;
        }
 
-       if (compr_type != UBIFS_COMPR_NONE) {
+       if (compr_type == UBIFS_COMPR_NONE) {
+               out_len = *new_len;
+       } else {
                err = ubifs_decompress(c, &dn->data, dlen, buf, &out_len, compr_type);
                if (err)
                        goto out;
@@ -1485,9 +1488,6 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
        int sync = IS_DIRSYNC(host);
        struct ubifs_inode *host_ui = ubifs_inode(host);
 
-       //dbg_jnl("host %lu, xattr ino %lu, name '%s', data len %d",
-       //      host->i_ino, inode->i_ino, nm->name,
-       //      ubifs_inode(inode)->data_len);
        ubifs_assert(inode->i_nlink == 0);
        ubifs_assert(mutex_is_locked(&host_ui->ui_mutex));
 
@@ -1500,7 +1500,7 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
        hlen = host_ui->data_len + UBIFS_INO_NODE_SZ;
        len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8);
 
-       xent = kmalloc(len, GFP_NOFS);
+       xent = kzalloc(len, GFP_NOFS);
        if (!xent)
                return -ENOMEM;
 
@@ -1607,7 +1607,7 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
        aligned_len1 = ALIGN(len1, 8);
        aligned_len = aligned_len1 + ALIGN(len2, 8);
 
-       ino = kmalloc(aligned_len, GFP_NOFS);
+       ino = kzalloc(aligned_len, GFP_NOFS);
        if (!ino)
                return -ENOMEM;
 
index 7547be5..b1f7c0c 100644 (file)
@@ -162,6 +162,7 @@ static inline void dent_key_init(const struct ubifs_info *c,
        uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
 
        ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+       ubifs_assert(!nm->hash && !nm->minor_hash);
        key->u32[0] = inum;
        key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
 }
index cf4cc99..bffadbb 100644 (file)
@@ -45,7 +45,7 @@
 #define UBIFS_KMALLOC_OK (128*1024)
 
 /* Slab cache for UBIFS inodes */
-struct kmem_cache *ubifs_inode_slab;
+static struct kmem_cache *ubifs_inode_slab;
 
 /* UBIFS TNC shrinker description */
 static struct shrinker ubifs_shrinker_info = {
@@ -446,6 +446,8 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root)
                           ubifs_compr_name(c->mount_opts.compr_type));
        }
 
+       seq_printf(s, ",ubi=%d,vol=%d", c->vi.ubi_num, c->vi.vol_id);
+
        return 0;
 }
 
@@ -931,6 +933,7 @@ enum {
        Opt_chk_data_crc,
        Opt_no_chk_data_crc,
        Opt_override_compr,
+       Opt_ignore,
        Opt_err,
 };
 
@@ -942,6 +945,8 @@ static const match_table_t tokens = {
        {Opt_chk_data_crc, "chk_data_crc"},
        {Opt_no_chk_data_crc, "no_chk_data_crc"},
        {Opt_override_compr, "compr=%s"},
+       {Opt_ignore, "ubi=%s"},
+       {Opt_ignore, "vol=%s"},
        {Opt_err, NULL},
 };
 
@@ -1042,6 +1047,8 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
                        c->default_compr = c->mount_opts.compr_type;
                        break;
                }
+               case Opt_ignore:
+                       break;
                default:
                {
                        unsigned long flag;
@@ -1869,8 +1876,10 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
                bu_init(c);
        else {
                dbg_gen("disable bulk-read");
+               mutex_lock(&c->bu_mutex);
                kfree(c->bu.buf);
                c->bu.buf = NULL;
+               mutex_unlock(&c->bu_mutex);
        }
 
        ubifs_assert(c->lst.taken_empty_lebs > 0);
index 709aa09..0a213dc 100644 (file)
@@ -1812,7 +1812,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
        int found, n, err;
        struct ubifs_znode *znode;
 
-       //dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
+       dbg_tnck(key, "key ");
        mutex_lock(&c->tnc_mutex);
        found = ubifs_lookup_level0(c, key, &znode, &n);
        if (!found) {
@@ -1880,48 +1880,65 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
        return do_lookup_nm(c, key, node, nm);
 }
 
-static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
-                       struct ubifs_dent_node *dent, uint32_t cookie)
+static int search_dh_cookie(struct ubifs_info *c, const union ubifs_key *key,
+                           struct ubifs_dent_node *dent, uint32_t cookie,
+                           struct ubifs_znode **zn, int *n)
 {
-       int n, err, type = key_type(c, key);
-       struct ubifs_znode *znode;
+       int err;
+       struct ubifs_znode *znode = *zn;
        struct ubifs_zbranch *zbr;
-       union ubifs_key *dkey, start_key;
-
-       ubifs_assert(is_hash_key(c, key));
-
-       lowest_dent_key(c, &start_key, key_inum(c, key));
-
-       mutex_lock(&c->tnc_mutex);
-       err = ubifs_lookup_level0(c, &start_key, &znode, &n);
-       if (unlikely(err < 0))
-               goto out_unlock;
+       union ubifs_key *dkey;
 
        for (;;) {
                if (!err) {
-                       err = tnc_next(c, &znode, &n);
+                       err = tnc_next(c, &znode, n);
                        if (err)
-                               goto out_unlock;
+                               goto out;
                }
 
-               zbr = &znode->zbranch[n];
+               zbr = &znode->zbranch[*n];
                dkey = &zbr->key;
 
                if (key_inum(c, dkey) != key_inum(c, key) ||
-                   key_type(c, dkey) != type) {
+                   key_type(c, dkey) != key_type(c, key)) {
                        err = -ENOENT;
-                       goto out_unlock;
+                       goto out;
                }
 
                err = tnc_read_hashed_node(c, zbr, dent);
                if (err)
-                       goto out_unlock;
+                       goto out;
 
                if (key_hash(c, key) == key_hash(c, dkey) &&
-                   le32_to_cpu(dent->cookie) == cookie)
-                       goto out_unlock;
+                   le32_to_cpu(dent->cookie) == cookie) {
+                       *zn = znode;
+                       goto out;
+               }
        }
 
+out:
+
+       return err;
+}
+
+static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
+                       struct ubifs_dent_node *dent, uint32_t cookie)
+{
+       int n, err;
+       struct ubifs_znode *znode;
+       union ubifs_key start_key;
+
+       ubifs_assert(is_hash_key(c, key));
+
+       lowest_dent_key(c, &start_key, key_inum(c, key));
+
+       mutex_lock(&c->tnc_mutex);
+       err = ubifs_lookup_level0(c, &start_key, &znode, &n);
+       if (unlikely(err < 0))
+               goto out_unlock;
+
+       err = search_dh_cookie(c, key, dent, cookie, &znode, &n);
+
 out_unlock:
        mutex_unlock(&c->tnc_mutex);
        return err;
@@ -2393,8 +2410,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       //dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
-       //       lnum, offs, nm->len, nm->name);
+       dbg_tnck(key, "LEB %d:%d, key ", lnum, offs);
        found = lookup_level0_dirty(c, key, &znode, &n);
        if (found < 0) {
                err = found;
@@ -2628,7 +2644,7 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       //dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
+       dbg_tnck(key, "key ");
        err = lookup_level0_dirty(c, key, &znode, &n);
        if (err < 0)
                goto out_unlock;
@@ -2663,6 +2679,74 @@ out_unlock:
 }
 
 /**
+ * ubifs_tnc_remove_dh - remove an index entry for a "double hashed" node.
+ * @c: UBIFS file-system description object
+ * @key: key of node
+ * @cookie: node cookie for collision resolution
+ *
+ * Returns %0 on success or negative error code on failure.
+ */
+int ubifs_tnc_remove_dh(struct ubifs_info *c, const union ubifs_key *key,
+                       uint32_t cookie)
+{
+       int n, err;
+       struct ubifs_znode *znode;
+       struct ubifs_dent_node *dent;
+       struct ubifs_zbranch *zbr;
+
+       if (!c->double_hash)
+               return -EOPNOTSUPP;
+
+       mutex_lock(&c->tnc_mutex);
+       err = lookup_level0_dirty(c, key, &znode, &n);
+       if (err <= 0)
+               goto out_unlock;
+
+       zbr = &znode->zbranch[n];
+       dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
+       if (!dent) {
+               err = -ENOMEM;
+               goto out_unlock;
+       }
+
+       err = tnc_read_hashed_node(c, zbr, dent);
+       if (err)
+               goto out_free;
+
+       /* If the cookie does not match, we're facing a hash collision. */
+       if (le32_to_cpu(dent->cookie) != cookie) {
+               union ubifs_key start_key;
+
+               lowest_dent_key(c, &start_key, key_inum(c, key));
+
+               err = ubifs_lookup_level0(c, &start_key, &znode, &n);
+               if (unlikely(err < 0))
+                       goto out_free;
+
+               err = search_dh_cookie(c, key, dent, cookie, &znode, &n);
+               if (err)
+                       goto out_free;
+       }
+
+       if (znode->cnext || !ubifs_zn_dirty(znode)) {
+               znode = dirty_cow_bottom_up(c, znode);
+               if (IS_ERR(znode)) {
+                       err = PTR_ERR(znode);
+                       goto out_free;
+               }
+       }
+       err = tnc_delete(c, znode, n);
+
+out_free:
+       kfree(dent);
+out_unlock:
+       if (!err)
+               err = dbg_check_tnc(c, 0);
+       mutex_unlock(&c->tnc_mutex);
+       return err;
+}
+
+/**
  * key_in_range - determine if a key falls within a range of keys.
  * @c: UBIFS file-system description object
  * @key: key to check
@@ -2802,6 +2886,8 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
                dbg_tnc("xent '%s', ino %lu", xent->name,
                        (unsigned long)xattr_inum);
 
+               ubifs_evict_xattr_inode(c, xattr_inum);
+
                fname_name(&nm) = xent->name;
                fname_len(&nm) = le16_to_cpu(xent->nlen);
                err = ubifs_tnc_remove_nm(c, &key1, &nm);
@@ -2863,7 +2949,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
        struct ubifs_zbranch *zbr;
        union ubifs_key *dkey;
 
-       //dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
+       dbg_tnck(key, "key ");
        ubifs_assert(is_hash_key(c, key));
 
        mutex_lock(&c->tnc_mutex);
index 51157da..aa31f60 100644 (file)
@@ -57,6 +57,8 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
                        ubifs_dump_znode(c, znode);
                        if (zbr->znode)
                                ubifs_dump_znode(c, zbr->znode);
+
+                       return -EINVAL;
                }
        }
        ubifs_prepare_node(c, idx, len, 0);
@@ -859,6 +861,8 @@ static int write_index(struct ubifs_info *c)
                                ubifs_dump_znode(c, znode);
                                if (zbr->znode)
                                        ubifs_dump_znode(c, zbr->znode);
+
+                               return -EINVAL;
                        }
                }
                len = ubifs_idx_node_sz(c, znode->child_cnt);
index 298b4d8..cd43651 100644 (file)
@@ -1451,7 +1451,6 @@ struct ubifs_info {
 extern struct list_head ubifs_infos;
 extern spinlock_t ubifs_infos_lock;
 extern atomic_long_t ubifs_clean_zn_cnt;
-extern struct kmem_cache *ubifs_inode_slab;
 extern const struct super_operations ubifs_super_operations;
 extern const struct address_space_operations ubifs_file_address_operations;
 extern const struct file_operations ubifs_file_operations;
@@ -1590,6 +1589,8 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
 int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key);
 int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
                        const struct fscrypt_name *nm);
+int ubifs_tnc_remove_dh(struct ubifs_info *c, const union ubifs_key *key,
+                       uint32_t cookie);
 int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
                           union ubifs_key *to_key);
 int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum);
@@ -1754,9 +1755,10 @@ int ubifs_check_dir_empty(struct inode *dir);
 extern const struct xattr_handler *ubifs_xattr_handlers[];
 ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
-                   size_t size, int flags);
+                   size_t size, int flags, bool check_lock);
 ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
                        size_t size);
+void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum);
 
 #ifdef CONFIG_UBIFS_FS_SECURITY
 extern int ubifs_init_security(struct inode *dentry, struct inode *inode,
index 6c9e62c..c13eae8 100644 (file)
@@ -280,7 +280,7 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
 }
 
 int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
-                   size_t size, int flags)
+                   size_t size, int flags, bool check_lock)
 {
        struct inode *inode;
        struct ubifs_info *c = host->i_sb->s_fs_info;
@@ -289,12 +289,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
        union ubifs_key key;
        int err;
 
-       /*
-        * Creating an encryption context is done unlocked since we
-        * operate on a new inode which is not visible to other users
-        * at this point.
-        */
-       if (strcmp(name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) != 0)
+       if (check_lock)
                ubifs_assert(inode_is_locked(host));
 
        if (size > UBIFS_MAX_INO_DATA)
@@ -513,6 +508,28 @@ out_cancel:
        return err;
 }
 
+/**
+ * ubifs_evict_xattr_inode - Evict an xattr inode.
+ * @c: UBIFS file-system description object
+ * @xattr_inum: xattr inode number
+ *
+ * When an inode that hosts xattrs is being removed we have to make sure
+ * that cached inodes of the xattrs also get removed from the inode cache
+ * otherwise we'd waste memory. This function looks up an inode from the
+ * inode cache and clears the link counter such that iput() will evict
+ * the inode.
+ */
+void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum)
+{
+       struct inode *inode;
+
+       inode = ilookup(c->vfs_sb, xattr_inum);
+       if (inode) {
+               clear_nlink(inode);
+               iput(inode);
+       }
+}
+
 static int ubifs_xattr_remove(struct inode *host, const char *name)
 {
        struct inode *inode;
@@ -576,8 +593,12 @@ static int init_xattrs(struct inode *inode, const struct xattr *xattr_array,
                }
                strcpy(name, XATTR_SECURITY_PREFIX);
                strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
+               /*
+                * creating a new inode without holding the inode rwsem,
+                * no need to check whether inode is locked.
+                */
                err = ubifs_xattr_set(inode, name, xattr->value,
-                                     xattr->value_len, 0);
+                                     xattr->value_len, 0, false);
                kfree(name);
                if (err < 0)
                        break;
@@ -624,7 +645,7 @@ static int xattr_set(const struct xattr_handler *handler,
        name = xattr_full_name(handler, name);
 
        if (value)
-               return ubifs_xattr_set(inode, name, value, size, flags);
+               return ubifs_xattr_set(inode, name, value, size, flags, true);
        else
                return ubifs_xattr_remove(inode, name);
 }
index f5eb2d5..356c2bf 100644 (file)
@@ -43,10 +43,15 @@ static void __udf_adinicb_readpage(struct page *page)
        struct inode *inode = page->mapping->host;
        char *kaddr;
        struct udf_inode_info *iinfo = UDF_I(inode);
+       loff_t isize = i_size_read(inode);
 
+       /*
+        * We have to be careful here as truncate can change i_size under us.
+        * So just sample it once and use the same value everywhere.
+        */
        kaddr = kmap_atomic(page);
-       memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, inode->i_size);
-       memset(kaddr + inode->i_size, 0, PAGE_SIZE - inode->i_size);
+       memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, isize);
+       memset(kaddr + isize, 0, PAGE_SIZE - isize);
        flush_dcache_page(page);
        SetPageUptodate(page);
        kunmap_atomic(kaddr);
@@ -71,7 +76,8 @@ static int udf_adinicb_writepage(struct page *page,
        BUG_ON(!PageLocked(page));
 
        kaddr = kmap_atomic(page);
-       memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr, inode->i_size);
+       memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr,
+               i_size_read(inode));
        SetPageUptodate(page);
        kunmap_atomic(kaddr);
        mark_inode_dirty(inode);
index 98c510e..18fdb9d 100644 (file)
@@ -1222,8 +1222,8 @@ int udf_setsize(struct inode *inode, loff_t newsize)
                        return err;
                }
 set_size:
-               truncate_setsize(inode, newsize);
                up_write(&iinfo->i_data_sem);
+               truncate_setsize(inode, newsize);
        } else {
                if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
                        down_write(&iinfo->i_data_sem);
@@ -1240,9 +1240,9 @@ set_size:
                                          udf_get_block);
                if (err)
                        return err;
+               truncate_setsize(inode, newsize);
                down_write(&iinfo->i_data_sem);
                udf_clear_extent_cache(inode);
-               truncate_setsize(inode, newsize);
                udf_truncate_extents(inode);
                up_write(&iinfo->i_data_sem);
        }
index 14b4bc1..462ac2e 100644 (file)
@@ -73,8 +73,6 @@
 #define VDS_POS_TERMINATING_DESC       6
 #define VDS_POS_LENGTH                 7
 
-#define UDF_DEFAULT_BLOCKSIZE 2048
-
 #define VSD_FIRST_SECTOR_OFFSET                32768
 #define VSD_MAX_SECTOR_OFFSET          0x800000
 
index 77c331f..14626b3 100644 (file)
 
 #include <linux/types.h>
 #include <linux/kernel.h>
-
-#define EPOCH_YEAR 1970
-
-#ifndef __isleap
-/* Nonzero if YEAR is a leap year (every 4 years,
-   except every 100th isn't, and every 400th is).  */
-#define        __isleap(year)  \
-  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
-#endif
-
-/* How many days come before each month (0-12).  */
-static const unsigned short int __mon_yday[2][13] = {
-       /* Normal years.  */
-       {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
-       /* Leap years.  */
-       {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
-};
-
-#define MAX_YEAR_SECONDS       69
-#define SPD                    0x15180 /*3600*24 */
-#define SPY(y, l, s)           (SPD * (365 * y + l) + s)
-
-static time_t year_seconds[MAX_YEAR_SECONDS] = {
-/*1970*/ SPY(0,   0, 0), SPY(1,   0, 0), SPY(2,   0, 0), SPY(3,   1, 0),
-/*1974*/ SPY(4,   1, 0), SPY(5,   1, 0), SPY(6,   1, 0), SPY(7,   2, 0),
-/*1978*/ SPY(8,   2, 0), SPY(9,   2, 0), SPY(10,  2, 0), SPY(11,  3, 0),
-/*1982*/ SPY(12,  3, 0), SPY(13,  3, 0), SPY(14,  3, 0), SPY(15,  4, 0),
-/*1986*/ SPY(16,  4, 0), SPY(17,  4, 0), SPY(18,  4, 0), SPY(19,  5, 0),
-/*1990*/ SPY(20,  5, 0), SPY(21,  5, 0), SPY(22,  5, 0), SPY(23,  6, 0),
-/*1994*/ SPY(24,  6, 0), SPY(25,  6, 0), SPY(26,  6, 0), SPY(27,  7, 0),
-/*1998*/ SPY(28,  7, 0), SPY(29,  7, 0), SPY(30,  7, 0), SPY(31,  8, 0),
-/*2002*/ SPY(32,  8, 0), SPY(33,  8, 0), SPY(34,  8, 0), SPY(35,  9, 0),
-/*2006*/ SPY(36,  9, 0), SPY(37,  9, 0), SPY(38,  9, 0), SPY(39, 10, 0),
-/*2010*/ SPY(40, 10, 0), SPY(41, 10, 0), SPY(42, 10, 0), SPY(43, 11, 0),
-/*2014*/ SPY(44, 11, 0), SPY(45, 11, 0), SPY(46, 11, 0), SPY(47, 12, 0),
-/*2018*/ SPY(48, 12, 0), SPY(49, 12, 0), SPY(50, 12, 0), SPY(51, 13, 0),
-/*2022*/ SPY(52, 13, 0), SPY(53, 13, 0), SPY(54, 13, 0), SPY(55, 14, 0),
-/*2026*/ SPY(56, 14, 0), SPY(57, 14, 0), SPY(58, 14, 0), SPY(59, 15, 0),
-/*2030*/ SPY(60, 15, 0), SPY(61, 15, 0), SPY(62, 15, 0), SPY(63, 16, 0),
-/*2034*/ SPY(64, 16, 0), SPY(65, 16, 0), SPY(66, 16, 0), SPY(67, 17, 0),
-/*2038*/ SPY(68, 17, 0)
-};
-
-#define SECS_PER_HOUR  (60 * 60)
-#define SECS_PER_DAY   (SECS_PER_HOUR * 24)
+#include <linux/time.h>
 
 struct timespec *
 udf_disk_stamp_to_time(struct timespec *dest, struct timestamp src)
 {
-       int yday;
        u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone);
        u16 year = le16_to_cpu(src.year);
        uint8_t type = typeAndTimezone >> 12;
@@ -102,15 +57,9 @@ udf_disk_stamp_to_time(struct timespec *dest, struct timestamp src)
        } else
                offset = 0;
 
-       if ((year < EPOCH_YEAR) ||
-           (year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) {
-               return NULL;
-       }
-       dest->tv_sec = year_seconds[year - EPOCH_YEAR];
+       dest->tv_sec = mktime64(year, src.month, src.day, src.hour, src.minute,
+                       src.second);
        dest->tv_sec -= offset * 60;
-
-       yday = ((__mon_yday[__isleap(year)][src.month - 1]) + src.day - 1);
-       dest->tv_sec += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second;
        dest->tv_nsec = 1000 * (src.centiseconds * 10000 +
                        src.hundredsOfMicroseconds * 100 + src.microseconds);
        return dest;
@@ -119,9 +68,9 @@ udf_disk_stamp_to_time(struct timespec *dest, struct timestamp src)
 struct timestamp *
 udf_time_to_disk_stamp(struct timestamp *dest, struct timespec ts)
 {
-       long int days, rem, y;
-       const unsigned short int *ip;
+       long seconds;
        int16_t offset;
+       struct tm tm;
 
        offset = -sys_tz.tz_minuteswest;
 
@@ -130,35 +79,14 @@ udf_time_to_disk_stamp(struct timestamp *dest, struct timespec ts)
 
        dest->typeAndTimezone = cpu_to_le16(0x1000 | (offset & 0x0FFF));
 
-       ts.tv_sec += offset * 60;
-       days = ts.tv_sec / SECS_PER_DAY;
-       rem = ts.tv_sec % SECS_PER_DAY;
-       dest->hour = rem / SECS_PER_HOUR;
-       rem %= SECS_PER_HOUR;
-       dest->minute = rem / 60;
-       dest->second = rem % 60;
-       y = 1970;
-
-#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
-#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
-
-       while (days < 0 || days >= (__isleap(y) ? 366 : 365)) {
-               long int yg = y + days / 365 - (days % 365 < 0);
-
-               /* Adjust DAYS and Y to match the guessed year.  */
-               days -= ((yg - y) * 365
-                        + LEAPS_THRU_END_OF(yg - 1)
-                        - LEAPS_THRU_END_OF(y - 1));
-               y = yg;
-       }
-       dest->year = cpu_to_le16(y);
-       ip = __mon_yday[__isleap(y)];
-       for (y = 11; days < (long int)ip[y]; --y)
-               continue;
-       days -= ip[y];
-       dest->month = y + 1;
-       dest->day = days + 1;
-
+       seconds = ts.tv_sec + offset * 60;
+       time64_to_tm(seconds, 0, &tm);
+       dest->year = cpu_to_le16(tm.tm_year + 1900);
+       dest->month = tm.tm_mon + 1;
+       dest->day = tm.tm_mday;
+       dest->hour = tm.tm_hour;
+       dest->minute = tm.tm_min;
+       dest->second = tm.tm_sec;
        dest->centiseconds = ts.tv_nsec / 10000000;
        dest->hundredsOfMicroseconds = (ts.tv_nsec / 1000 -
                                        dest->centiseconds * 10000) / 100;
index d6ea520..4d85992 100644 (file)
@@ -54,6 +54,16 @@ kmem_flags_convert(xfs_km_flags_t flags)
                        lflags &= ~__GFP_FS;
        }
 
+       /*
+        * Default page/slab allocator behavior is to retry for ever
+        * for small allocations. We can override this behavior by using
+        * __GFP_RETRY_MAYFAIL which will tell the allocator to retry as long
+        * as it is feasible but rather fail than retry forever for all
+        * request sizes.
+        */
+       if (flags & KM_MAYFAIL)
+               lflags |= __GFP_RETRY_MAYFAIL;
+
        if (flags & KM_ZERO)
                lflags |= __GFP_ZERO;
 
index ef8a1c7..de7b9bd 100644 (file)
@@ -114,12 +114,14 @@ xfs_inode_hasattr(
  * Overall external interface routines.
  *========================================================================*/
 
-/* Retrieve an extended attribute and its value.  Must have iolock. */
+/* Retrieve an extended attribute and its value.  Must have ilock. */
 int
 xfs_attr_get_ilocked(
        struct xfs_inode        *ip,
        struct xfs_da_args      *args)
 {
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
+
        if (!xfs_inode_hasattr(ip))
                return -ENOATTR;
        else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
index 0a98807..c09c16b 100644 (file)
@@ -5435,6 +5435,7 @@ __xfs_bunmapi(
        xfs_fsblock_t           sum;
        xfs_filblks_t           len = *rlen;    /* length to unmap in file */
        xfs_fileoff_t           max_len;
+       xfs_agnumber_t          prev_agno = NULLAGNUMBER, agno;
 
        trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_);
 
@@ -5534,6 +5535,17 @@ __xfs_bunmapi(
                 */
                del = got;
                wasdel = isnullstartblock(del.br_startblock);
+
+               /*
+                * Make sure we don't touch multiple AGF headers out of order
+                * in a single transaction, as that could cause AB-BA deadlocks.
+                */
+               if (!wasdel) {
+                       agno = XFS_FSB_TO_AGNO(mp, del.br_startblock);
+                       if (prev_agno != NULLAGNUMBER && prev_agno > agno)
+                               break;
+                       prev_agno = agno;
+               }
                if (got.br_startoff < start) {
                        del.br_startoff = start;
                        del.br_blockcount -= start - got.br_startoff;
@@ -6499,6 +6511,15 @@ xfs_bmap_finish_one(
        xfs_fsblock_t                   firstfsb;
        int                             error = 0;
 
+       /*
+        * firstfsb is tied to the transaction lifetime and is used to
+        * ensure correct AG locking order and schedule work item
+        * continuations.  XFS_BUI_MAX_FAST_EXTENTS (== 1) restricts us
+        * to only making one bmap call per transaction, so it should
+        * be safe to have it as a local variable here.
+        */
+       firstfsb = NULLFSBLOCK;
+
        trace_xfs_bmap_deferred(tp->t_mountp,
                        XFS_FSB_TO_AGNO(tp->t_mountp, startblock), type,
                        XFS_FSB_TO_AGBNO(tp->t_mountp, startblock),
index 4da85ff..e0bcc4a 100644 (file)
@@ -728,7 +728,8 @@ xfs_btree_firstrec(
         * Get the block pointer for this level.
         */
        block = xfs_btree_get_block(cur, level, &bp);
-       xfs_btree_check_block(cur, block, level, bp);
+       if (xfs_btree_check_block(cur, block, level, bp))
+               return 0;
        /*
         * It's empty, there is no such record.
         */
@@ -757,7 +758,8 @@ xfs_btree_lastrec(
         * Get the block pointer for this level.
         */
        block = xfs_btree_get_block(cur, level, &bp);
-       xfs_btree_check_block(cur, block, level, bp);
+       if (xfs_btree_check_block(cur, block, level, bp))
+               return 0;
        /*
         * It's empty, there is no such record.
         */
index d478065..8727a43 100644 (file)
@@ -136,6 +136,8 @@ __xfs_dir3_data_check(
                 */
                if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
                        XFS_WANT_CORRUPTED_RETURN(mp, lastfree == 0);
+                       XFS_WANT_CORRUPTED_RETURN(mp, endp >=
+                                       p + be16_to_cpu(dup->length));
                        XFS_WANT_CORRUPTED_RETURN(mp,
                                be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) ==
                                               (char *)dup - (char *)hdr);
@@ -164,6 +166,8 @@ __xfs_dir3_data_check(
                XFS_WANT_CORRUPTED_RETURN(mp, dep->namelen != 0);
                XFS_WANT_CORRUPTED_RETURN(mp,
                        !xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)));
+               XFS_WANT_CORRUPTED_RETURN(mp, endp >=
+                               p + ops->data_entsize(dep->namelen));
                XFS_WANT_CORRUPTED_RETURN(mp,
                        be16_to_cpu(*ops->data_entry_tag_p(dep)) ==
                                               (char *)dep - (char *)hdr);
index 2834574..d69c772 100644 (file)
@@ -136,8 +136,6 @@ typedef uint16_t    xfs_qwarncnt_t;
  */
 #define XFS_QMOPT_INHERIT      0x1000000
 
-#define XFS_QMOPT_NOLOCK       0x2000000 /* don't ilock during dqget */
-
 /*
  * flags to xfs_trans_mod_dquot.
  */
index 900ea23..45b1c3b 100644 (file)
@@ -1638,6 +1638,10 @@ xfs_refcount_recover_cow_leftovers(
        error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
        if (error)
                goto out_trans;
+       if (!agbp) {
+               error = -ENOMEM;
+               goto out_trans;
+       }
        cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
 
        /* Find all the leftover CoW staging extents. */
index 545eca5..7740c8a 100644 (file)
@@ -463,6 +463,8 @@ xfs_attr_list_int_ilocked(
 {
        struct xfs_inode                *dp = context->dp;
 
+       ASSERT(xfs_isilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
+
        /*
         * Decide on what work routines to call based on the inode size.
         */
index f89f7b5..fd2ef8c 100644 (file)
@@ -472,23 +472,18 @@ xfs_qm_dqtobp(
        struct xfs_mount        *mp = dqp->q_mount;
        xfs_dqid_t              id = be32_to_cpu(dqp->q_core.d_id);
        struct xfs_trans        *tp = (tpp ? *tpp : NULL);
-       uint                    lock_mode = 0;
+       uint                    lock_mode;
 
        quotip = xfs_quota_inode(dqp->q_mount, dqp->dq_flags);
        dqp->q_fileoffset = (xfs_fileoff_t)id / mp->m_quotainfo->qi_dqperchunk;
 
-       ASSERT(!(flags & XFS_QMOPT_NOLOCK) ||
-               xfs_isilocked(quotip, XFS_ILOCK_SHARED) ||
-               xfs_isilocked(quotip, XFS_ILOCK_EXCL));
-       if (!(flags & XFS_QMOPT_NOLOCK))
-               lock_mode = xfs_ilock_data_map_shared(quotip);
+       lock_mode = xfs_ilock_data_map_shared(quotip);
        if (!xfs_this_quota_on(dqp->q_mount, dqp->dq_flags)) {
                /*
                 * Return if this type of quotas is turned off while we
                 * didn't have the quota inode lock.
                 */
-               if (lock_mode)
-                       xfs_iunlock(quotip, lock_mode);
+               xfs_iunlock(quotip, lock_mode);
                return -ESRCH;
        }
 
@@ -498,8 +493,7 @@ xfs_qm_dqtobp(
        error = xfs_bmapi_read(quotip, dqp->q_fileoffset,
                               XFS_DQUOT_CLUSTER_SIZE_FSB, &map, &nmaps, 0);
 
-       if (lock_mode)
-               xfs_iunlock(quotip, lock_mode);
+       xfs_iunlock(quotip, lock_mode);
        if (error)
                return error;
 
index 6ce948c..15751dc 100644 (file)
@@ -111,6 +111,9 @@ restart:
                        skipped = 0;
                        break;
                }
+               /* we're done if id overflows back to zero */
+               if (!next_index)
+                       break;
        }
 
        if (skipped) {
index ab2270a..f45fbf0 100644 (file)
@@ -170,6 +170,8 @@ xfs_reflink_find_shared(
        error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
        if (error)
                return error;
+       if (!agbp)
+               return -ENOMEM;
 
        cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
 
@@ -329,7 +331,7 @@ xfs_reflink_convert_cow_extent(
        xfs_filblks_t                   count_fsb,
        struct xfs_defer_ops            *dfops)
 {
-       xfs_fsblock_t                   first_block;
+       xfs_fsblock_t                   first_block = NULLFSBLOCK;
        int                             nimaps = 1;
 
        if (imap->br_state == XFS_EXT_NORM)
index 12cd9cf..23a50d7 100644 (file)
@@ -61,6 +61,8 @@ xfs_readlink_bmap_ilocked(
        int                     fsblocks = 0;
        int                     offset;
 
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
+
        fsblocks = xfs_symlink_blocks(mp, pathlen);
        error = xfs_bmapi_read(ip, 0, fsblocks, mval, &nmaps, 0);
        if (error)
index d4b7294..1e3a74f 100644 (file)
@@ -3,6 +3,7 @@
 
 #ifdef CONFIG_ACPI_NUMA
 #include <linux/kernel.h>
+#include <linux/numa.h>
 
 /* Proximity bitmap length */
 #if MAX_NUMNODES > 256
diff --git a/include/asm-generic/uaccess-unaligned.h b/include/asm-generic/uaccess-unaligned.h
deleted file mode 100644 (file)
index 67deb89..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __ASM_GENERIC_UACCESS_UNALIGNED_H
-#define __ASM_GENERIC_UACCESS_UNALIGNED_H
-
-/*
- * This macro should be used instead of __get_user() when accessing
- * values at locations that are not known to be aligned.
- */
-#define __get_user_unaligned(x, ptr)                                   \
-({                                                                     \
-       __typeof__ (*(ptr)) __x;                                        \
-       __copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0;    \
-       (x) = __x;                                                      \
-})
-
-
-/*
- * This macro should be used instead of __put_user() when accessing
- * values at locations that are not known to be aligned.
- */
-#define __put_user_unaligned(x, ptr)                                   \
-({                                                                     \
-       __typeof__ (*(ptr)) __x = (x);                                  \
-       __copy_to_user((ptr), &__x, sizeof(*(ptr))) ? -EFAULT : 0;      \
-})
-
-#endif /* __ASM_GENERIC_UACCESS_UNALIGNED_H */
index 4c8d4c8..182f832 100644 (file)
@@ -22,56 +22,56 @@ struct dw_hdmi;
  * 48bit bus.
  *
  * +----------------------+----------------------------------+------------------------------+
- * + Format Name          + Format Code                      + Encodings                    +
+ * | Format Name          | Format Code                      | Encodings                    |
  * +----------------------+----------------------------------+------------------------------+
- * + RGB 4:4:4 8bit       + ``MEDIA_BUS_FMT_RGB888_1X24``    + ``V4L2_YCBCR_ENC_DEFAULT``   +
+ * | RGB 4:4:4 8bit       | ``MEDIA_BUS_FMT_RGB888_1X24``    | ``V4L2_YCBCR_ENC_DEFAULT``   |
  * +----------------------+----------------------------------+------------------------------+
- * + RGB 4:4:4 10bits     + ``MEDIA_BUS_FMT_RGB101010_1X30`` + ``V4L2_YCBCR_ENC_DEFAULT``   +
+ * | RGB 4:4:4 10bits     | ``MEDIA_BUS_FMT_RGB101010_1X30`` | ``V4L2_YCBCR_ENC_DEFAULT``   |
  * +----------------------+----------------------------------+------------------------------+
- * + RGB 4:4:4 12bits     + ``MEDIA_BUS_FMT_RGB121212_1X36`` + ``V4L2_YCBCR_ENC_DEFAULT``   +
+ * | RGB 4:4:4 12bits     | ``MEDIA_BUS_FMT_RGB121212_1X36`` | ``V4L2_YCBCR_ENC_DEFAULT``   |
  * +----------------------+----------------------------------+------------------------------+
- * + RGB 4:4:4 16bits     + ``MEDIA_BUS_FMT_RGB161616_1X48`` + ``V4L2_YCBCR_ENC_DEFAULT``   +
+ * | RGB 4:4:4 16bits     | ``MEDIA_BUS_FMT_RGB161616_1X48`` | ``V4L2_YCBCR_ENC_DEFAULT``   |
  * +----------------------+----------------------------------+------------------------------+
- * + YCbCr 4:4:4 8bit     + ``MEDIA_BUS_FMT_YUV8_1X24``      + ``V4L2_YCBCR_ENC_601``       +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_709``    +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_XV601``  +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_XV709``  +
+ * | YCbCr 4:4:4 8bit     | ``MEDIA_BUS_FMT_YUV8_1X24``      | ``V4L2_YCBCR_ENC_601``       |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_709``    |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_XV601``  |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_XV709``  |
  * +----------------------+----------------------------------+------------------------------+
- * + YCbCr 4:4:4 10bits   + ``MEDIA_BUS_FMT_YUV10_1X30``     + ``V4L2_YCBCR_ENC_601``       +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_709``    +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_XV601``  +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_XV709``  +
+ * | YCbCr 4:4:4 10bits   | ``MEDIA_BUS_FMT_YUV10_1X30``     | ``V4L2_YCBCR_ENC_601``       |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_709``    |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_XV601``  |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_XV709``  |
  * +----------------------+----------------------------------+------------------------------+
- * + YCbCr 4:4:4 12bits   + ``MEDIA_BUS_FMT_YUV12_1X36``     + ``V4L2_YCBCR_ENC_601``       +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_709``    +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_XV601``  +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_XV709``  +
+ * | YCbCr 4:4:4 12bits   | ``MEDIA_BUS_FMT_YUV12_1X36``     | ``V4L2_YCBCR_ENC_601``       |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_709``    |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_XV601``  |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_XV709``  |
  * +----------------------+----------------------------------+------------------------------+
- * + YCbCr 4:4:4 16bits   + ``MEDIA_BUS_FMT_YUV16_1X48``     + ``V4L2_YCBCR_ENC_601``       +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_709``    +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_XV601``  +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_XV709``  +
+ * | YCbCr 4:4:4 16bits   | ``MEDIA_BUS_FMT_YUV16_1X48``     | ``V4L2_YCBCR_ENC_601``       |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_709``    |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_XV601``  |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_XV709``  |
  * +----------------------+----------------------------------+------------------------------+
- * + YCbCr 4:2:2 8bit     + ``MEDIA_BUS_FMT_UYVY8_1X16``     + ``V4L2_YCBCR_ENC_601``       +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_709``    +
+ * | YCbCr 4:2:2 8bit     | ``MEDIA_BUS_FMT_UYVY8_1X16``     | ``V4L2_YCBCR_ENC_601``       |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_709``    |
  * +----------------------+----------------------------------+------------------------------+
- * + YCbCr 4:2:2 10bits   + ``MEDIA_BUS_FMT_UYVY10_1X20``    + ``V4L2_YCBCR_ENC_601``       +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_709``    +
+ * | YCbCr 4:2:2 10bits   | ``MEDIA_BUS_FMT_UYVY10_1X20``    | ``V4L2_YCBCR_ENC_601``       |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_709``    |
  * +----------------------+----------------------------------+------------------------------+
- * + YCbCr 4:2:2 12bits   + ``MEDIA_BUS_FMT_UYVY12_1X24``    + ``V4L2_YCBCR_ENC_601``       +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_709``    +
+ * | YCbCr 4:2:2 12bits   | ``MEDIA_BUS_FMT_UYVY12_1X24``    | ``V4L2_YCBCR_ENC_601``       |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_709``    |
  * +----------------------+----------------------------------+------------------------------+
- * + YCbCr 4:2:0 8bit     + ``MEDIA_BUS_FMT_UYYVYY8_0_5X24`` + ``V4L2_YCBCR_ENC_601``       +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_709``    +
+ * | YCbCr 4:2:0 8bit     | ``MEDIA_BUS_FMT_UYYVYY8_0_5X24`` | ``V4L2_YCBCR_ENC_601``       |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_709``    |
  * +----------------------+----------------------------------+------------------------------+
- * + YCbCr 4:2:0 10bits   + ``MEDIA_BUS_FMT_UYYVYY10_0_5X30``+ ``V4L2_YCBCR_ENC_601``       +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_709``    +
+ * | YCbCr 4:2:0 10bits   | ``MEDIA_BUS_FMT_UYYVYY10_0_5X30``| ``V4L2_YCBCR_ENC_601``       |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_709``    |
  * +----------------------+----------------------------------+------------------------------+
- * + YCbCr 4:2:0 12bits   + ``MEDIA_BUS_FMT_UYYVYY12_0_5X36``+ ``V4L2_YCBCR_ENC_601``       +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_709``    +
+ * | YCbCr 4:2:0 12bits   | ``MEDIA_BUS_FMT_UYYVYY12_0_5X36``| ``V4L2_YCBCR_ENC_601``       |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_709``    |
  * +----------------------+----------------------------------+------------------------------+
- * + YCbCr 4:2:0 16bits   + ``MEDIA_BUS_FMT_UYYVYY16_0_5X48``+ ``V4L2_YCBCR_ENC_601``       +
- * +                      +                                  + or ``V4L2_YCBCR_ENC_709``    +
+ * | YCbCr 4:2:0 16bits   | ``MEDIA_BUS_FMT_UYYVYY16_0_5X48``| ``V4L2_YCBCR_ENC_601``       |
+ * |                      |                                  | or ``V4L2_YCBCR_ENC_709``    |
  * +----------------------+----------------------------------+------------------------------+
  */
 
diff --git a/include/dt-bindings/clock/boston-clock.h b/include/dt-bindings/clock/boston-clock.h
new file mode 100644 (file)
index 0000000..a6f0098
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2016 Imagination Technologies
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_BOSTON_CLOCK_H__
+#define __DT_BINDINGS_CLOCK_BOSTON_CLOCK_H__
+
+#define BOSTON_CLK_INPUT 0
+#define BOSTON_CLK_SYS 1
+#define BOSTON_CLK_CPU 2
+
+#endif /* __DT_BINDINGS_CLOCK_BOSTON_CLOCK_H__ */
index 334165c..854e1bd 100644 (file)
@@ -69,34 +69,14 @@ static inline void __add_wb_stat(struct bdi_writeback *wb,
        percpu_counter_add_batch(&wb->stat[item], amount, WB_STAT_BATCH);
 }
 
-static inline void __inc_wb_stat(struct bdi_writeback *wb,
-                                enum wb_stat_item item)
-{
-       __add_wb_stat(wb, item, 1);
-}
-
 static inline void inc_wb_stat(struct bdi_writeback *wb, enum wb_stat_item item)
 {
-       unsigned long flags;
-
-       local_irq_save(flags);
-       __inc_wb_stat(wb, item);
-       local_irq_restore(flags);
-}
-
-static inline void __dec_wb_stat(struct bdi_writeback *wb,
-                                enum wb_stat_item item)
-{
-       __add_wb_stat(wb, item, -1);
+       __add_wb_stat(wb, item, 1);
 }
 
 static inline void dec_wb_stat(struct bdi_writeback *wb, enum wb_stat_item item)
 {
-       unsigned long flags;
-
-       local_irq_save(flags);
-       __dec_wb_stat(wb, item);
-       local_irq_restore(flags);
+       __add_wb_stat(wb, item, -1);
 }
 
 static inline s64 wb_stat(struct bdi_writeback *wb, enum wb_stat_item item)
index 05488da..3ae9013 100644 (file)
@@ -46,7 +46,7 @@ struct linux_binprm {
        unsigned interp_flags;
        unsigned interp_data;
        unsigned long loader, exec;
-};
+} __randomize_layout;
 
 #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
 #define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT)
@@ -81,7 +81,7 @@ struct linux_binfmt {
        int (*load_shlib)(struct file *);
        int (*core_dump)(struct coredump_params *cprm);
        unsigned long min_coredump;     /* minimal dump size */
-};
+} __randomize_layout;
 
 extern void __register_binfmt(struct linux_binfmt *fmt, int insert);
 
index 360c082..d41d40a 100644 (file)
@@ -85,7 +85,7 @@ int __cgroup_bpf_run_filter_sock_ops(struct sock *sk,
        int __ret = 0;                                                         \
        if (cgroup_bpf_enabled && (sock_ops)->sk) {            \
                typeof(sk) __sk = sk_to_full_sk((sock_ops)->sk);               \
-               if (sk_fullsock(__sk))                                         \
+               if (__sk && sk_fullsock(__sk))                                 \
                        __ret = __cgroup_bpf_run_filter_sock_ops(__sk,         \
                                                                 sock_ops,     \
                                                         BPF_CGROUP_SOCK_OPS); \
index 621076f..8e5d31f 100644 (file)
@@ -43,6 +43,7 @@ struct bpf_reg_state {
        u32 min_align;
        u32 aux_off;
        u32 aux_off_align;
+       bool value_from_signed;
 };
 
 enum bpf_stack_slot_type {
index 408bc09..cb28eb2 100644 (file)
@@ -17,7 +17,7 @@ struct cdev {
        struct list_head list;
        dev_t dev;
        unsigned int count;
-};
+} __randomize_layout;
 
 void cdev_init(struct cdev *, const struct file_operations *);
 
index f0f6c53..040dd10 100644 (file)
 #define CEPH_FEATURE_INCARNATION_2 (1ull<<57) // CEPH_FEATURE_SERVER_JEWEL
 
 #define DEFINE_CEPH_FEATURE(bit, incarnation, name)                    \
-       const static uint64_t CEPH_FEATURE_##name = (1ULL<<bit);                \
-       const static uint64_t CEPH_FEATUREMASK_##name =                 \
+       static const uint64_t CEPH_FEATURE_##name = (1ULL<<bit);                \
+       static const uint64_t CEPH_FEATUREMASK_##name =                 \
                (1ULL<<bit | CEPH_FEATURE_INCARNATION_##incarnation);
 
 /* this bit is ignored but still advertised by release *when* */
 #define DEFINE_CEPH_FEATURE_DEPRECATED(bit, incarnation, name, when) \
-       const static uint64_t DEPRECATED_CEPH_FEATURE_##name = (1ULL<<bit); \
-       const static uint64_t DEPRECATED_CEPH_FEATUREMASK_##name =              \
+       static const uint64_t DEPRECATED_CEPH_FEATURE_##name = (1ULL<<bit); \
+       static const uint64_t DEPRECATED_CEPH_FEATUREMASK_##name =              \
                (1ULL<<bit | CEPH_FEATURE_INCARNATION_##incarnation);
 
 /*
index 91bd464..12c96d9 100644 (file)
@@ -657,6 +657,28 @@ static inline void clk_disable_unprepare(struct clk *clk)
        clk_unprepare(clk);
 }
 
+static inline int clk_bulk_prepare_enable(int num_clks,
+                                         struct clk_bulk_data *clks)
+{
+       int ret;
+
+       ret = clk_bulk_prepare(num_clks, clks);
+       if (ret)
+               return ret;
+       ret = clk_bulk_enable(num_clks, clks);
+       if (ret)
+               clk_bulk_unprepare(num_clks, clks);
+
+       return ret;
+}
+
+static inline void clk_bulk_disable_unprepare(int num_clks,
+                                             struct clk_bulk_data *clks)
+{
+       clk_bulk_disable(num_clks, clks);
+       clk_bulk_unprepare(num_clks, clks);
+}
+
 #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
 struct clk *of_clk_get(struct device_node *np, int index);
 struct clk *of_clk_get_by_name(struct device_node *np, const char *name);
index cd4bbe8..bdb80c4 100644 (file)
 #endif /* GCC_VERSION >= 40500 */
 
 #if GCC_VERSION >= 40600
+
 /*
  * When used with Link Time Optimization, gcc can optimize away C functions or
  * variables which are referenced only from assembly code.  __visible tells the
  * this.
  */
 #define __visible      __attribute__((externally_visible))
-#endif
+
+/*
+ * RANDSTRUCT_PLUGIN wants to use an anonymous struct, but it is only
+ * possible since GCC 4.6. To provide as much build testing coverage
+ * as possible, this is used for all GCC 4.6+ builds, and not just on
+ * RANDSTRUCT_PLUGIN builds.
+ */
+#define randomized_struct_fields_start struct {
+#define randomized_struct_fields_end   } __randomize_layout;
+
+#endif /* GCC_VERSION >= 40600 */
 
 
 #if GCC_VERSION >= 40900 && !defined(__CHECKER__)
index 219f82f..eca8ad7 100644 (file)
@@ -452,6 +452,11 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
 # define __no_randomize_layout
 #endif
 
+#ifndef randomized_struct_fields_start
+# define randomized_struct_fields_start
+# define randomized_struct_fields_end
+#endif
+
 /*
  * Tell gcc if a function is cold. The compiler will assume any path
  * directly leading to the call is unlikely.
index c156f50..d4292eb 100644 (file)
 #include <linux/thermal.h>
 #include <linux/cpumask.h>
 
+struct cpufreq_policy;
+
 typedef int (*get_static_t)(cpumask_t *cpumask, int interval,
                            unsigned long voltage, u32 *power);
 
 #ifdef CONFIG_CPU_THERMAL
 /**
  * cpufreq_cooling_register - function to create cpufreq cooling device.
- * @clip_cpus: cpumask of cpus where the frequency constraints will happen
+ * @policy: cpufreq policy.
  */
 struct thermal_cooling_device *
-cpufreq_cooling_register(const struct cpumask *clip_cpus);
+cpufreq_cooling_register(struct cpufreq_policy *policy);
 
 struct thermal_cooling_device *
-cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
+cpufreq_power_cooling_register(struct cpufreq_policy *policy,
                               u32 capacitance, get_static_t plat_static_func);
 
 /**
  * of_cpufreq_cooling_register - create cpufreq cooling device based on DT.
  * @np: a valid struct device_node to the cooling device device tree node.
- * @clip_cpus: cpumask of cpus where the frequency constraints will happen
+ * @policy: cpufreq policy.
  */
 #ifdef CONFIG_THERMAL_OF
 struct thermal_cooling_device *
 of_cpufreq_cooling_register(struct device_node *np,
-                           const struct cpumask *clip_cpus);
+                           struct cpufreq_policy *policy);
 
 struct thermal_cooling_device *
 of_cpufreq_power_cooling_register(struct device_node *np,
-                                 const struct cpumask *clip_cpus,
+                                 struct cpufreq_policy *policy,
                                  u32 capacitance,
                                  get_static_t plat_static_func);
 #else
 static inline struct thermal_cooling_device *
 of_cpufreq_cooling_register(struct device_node *np,
-                           const struct cpumask *clip_cpus)
+                           struct cpufreq_policy *policy)
 {
        return ERR_PTR(-ENOSYS);
 }
 
 static inline struct thermal_cooling_device *
 of_cpufreq_power_cooling_register(struct device_node *np,
-                                 const struct cpumask *clip_cpus,
+                                 struct cpufreq_policy *policy,
                                  u32 capacitance,
                                  get_static_t plat_static_func)
 {
@@ -82,15 +84,14 @@ of_cpufreq_power_cooling_register(struct device_node *np,
  */
 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
 
-unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq);
 #else /* !CONFIG_CPU_THERMAL */
 static inline struct thermal_cooling_device *
-cpufreq_cooling_register(const struct cpumask *clip_cpus)
+cpufreq_cooling_register(struct cpufreq_policy *policy)
 {
        return ERR_PTR(-ENOSYS);
 }
 static inline struct thermal_cooling_device *
-cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
+cpufreq_power_cooling_register(struct cpufreq_policy *policy,
                               u32 capacitance, get_static_t plat_static_func)
 {
        return NULL;
@@ -98,14 +99,14 @@ cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
 
 static inline struct thermal_cooling_device *
 of_cpufreq_cooling_register(struct device_node *np,
-                           const struct cpumask *clip_cpus)
+                           struct cpufreq_policy *policy)
 {
        return ERR_PTR(-ENOSYS);
 }
 
 static inline struct thermal_cooling_device *
 of_cpufreq_power_cooling_register(struct device_node *np,
-                                 const struct cpumask *clip_cpus,
+                                 struct cpufreq_policy *policy,
                                  u32 capacitance,
                                  get_static_t plat_static_func)
 {
@@ -117,11 +118,6 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 {
        return;
 }
-static inline
-unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
-{
-       return THERMAL_CSTATE_INVALID;
-}
 #endif /* CONFIG_CPU_THERMAL */
 
 #endif /* __CPU_COOLING_H__ */
index 905117b..f10a9b3 100644 (file)
@@ -862,6 +862,20 @@ static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
                return -EINVAL;
        }
 }
+
+static inline int cpufreq_table_count_valid_entries(const struct cpufreq_policy *policy)
+{
+       struct cpufreq_frequency_table *pos;
+       int count = 0;
+
+       if (unlikely(!policy->freq_table))
+               return 0;
+
+       cpufreq_for_each_valid_entry(pos, policy->freq_table)
+               count++;
+
+       return count;
+}
 #else
 static inline int cpufreq_boost_trigger_state(int state)
 {
index 4090a42..2df2118 100644 (file)
@@ -19,7 +19,7 @@
                                     CRASH_CORE_NOTE_NAME_BYTES +       \
                                     CRASH_CORE_NOTE_DESC_BYTES)
 
-#define VMCOREINFO_BYTES          (4096)
+#define VMCOREINFO_BYTES          PAGE_SIZE
 #define VMCOREINFO_NOTE_NAME      "VMCOREINFO"
 #define VMCOREINFO_NOTE_NAME_BYTES ALIGN(sizeof(VMCOREINFO_NOTE_NAME), 4)
 #define VMCOREINFO_NOTE_SIZE      ((CRASH_CORE_NOTE_HEAD_BYTES * 2) +  \
@@ -28,6 +28,7 @@
 
 typedef u32 note_buf_t[CRASH_CORE_NOTE_BYTES/4];
 
+void crash_update_vmcoreinfo_safecopy(void *ptr);
 void crash_save_vmcoreinfo(void);
 void arch_crash_save_vmcoreinfo(void);
 __printf(1, 2)
@@ -56,9 +57,7 @@ phys_addr_t paddr_vmcoreinfo_note(void);
 #define VMCOREINFO_CONFIG(name) \
        vmcoreinfo_append_str("CONFIG_%s=y\n", #name)
 
-extern u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4];
-extern size_t vmcoreinfo_size;
-extern size_t vmcoreinfo_max_size;
+extern u32 *vmcoreinfo_note;
 
 Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type,
                          void *data, size_t data_len);
index c728d51..099058e 100644 (file)
@@ -31,7 +31,7 @@ struct group_info {
        atomic_t        usage;
        int             ngroups;
        kgid_t          gid[0];
-};
+} __randomize_layout;
 
 /**
  * get_group_info - Get a reference to a group info structure
@@ -145,7 +145,7 @@ struct cred {
        struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
        struct group_info *group_info;  /* supplementary groups for euid/fsgid */
        struct rcu_head rcu;            /* RCU deletion hook */
-};
+} __randomize_layout;
 
 extern void __put_cred(struct cred *);
 extern void exit_creds(struct task_struct *);
index 7948118..df97b7a 100644 (file)
@@ -87,6 +87,7 @@ size_t dax_copy_from_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr,
 void dax_flush(struct dax_device *dax_dev, pgoff_t pgoff, void *addr,
                size_t size);
 void dax_write_cache(struct dax_device *dax_dev, bool wc);
+bool dax_write_cache_enabled(struct dax_device *dax_dev);
 
 /*
  * We use lowest available bit in exceptional entry for locking, one bit for
index 025727b..aae1cdb 100644 (file)
@@ -55,6 +55,11 @@ struct qstr {
 
 #define QSTR_INIT(n,l) { { { .len = l } }, .name = n }
 
+extern const char empty_string[];
+extern const struct qstr empty_name;
+extern const char slash_string[];
+extern const struct qstr slash_name;
+
 struct dentry_stat_t {
        long nr_dentry;
        long nr_unused;
@@ -113,7 +118,7 @@ struct dentry {
                struct hlist_bl_node d_in_lookup_hash;  /* only for in-lookup ones */
                struct rcu_head d_rcu;
        } d_u;
-};
+} __randomize_layout;
 
 /*
  * dentry->d_lock spinlock nesting subclasses:
@@ -592,8 +597,8 @@ static inline struct inode *d_real_inode(const struct dentry *dentry)
 }
 
 struct name_snapshot {
-       const char *name;
-       char inline_name[DNAME_INLINE_LEN];
+       const unsigned char *name;
+       unsigned char inline_name[DNAME_INLINE_LEN];
 };
 void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *);
 void release_dentry_name_snapshot(struct name_snapshot *);
index a5195a7..0a186c4 100644 (file)
@@ -55,6 +55,7 @@ struct dma_fence_cb;
  * of the time.
  *
  * DMA_FENCE_FLAG_SIGNALED_BIT - fence is already signaled
+ * DMA_FENCE_FLAG_TIMESTAMP_BIT - timestamp recorded for fence signaling
  * DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT - enable_signaling might have been called
  * DMA_FENCE_FLAG_USER_BITS - start of the unused bits, can be used by the
  * implementer of the fence for its own purposes. Can be used in different
@@ -84,6 +85,7 @@ struct dma_fence {
 
 enum dma_fence_flag_bits {
        DMA_FENCE_FLAG_SIGNALED_BIT,
+       DMA_FENCE_FLAG_TIMESTAMP_BIT,
        DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
        DMA_FENCE_FLAG_USER_BITS, /* must always be last member */
 };
index 843ab86..03c0196 100644 (file)
@@ -157,16 +157,40 @@ static inline int is_device_dma_capable(struct device *dev)
  * These three functions are only for dma allocator.
  * Don't use them in device drivers.
  */
-int dma_alloc_from_coherent(struct device *dev, ssize_t size,
+int dma_alloc_from_dev_coherent(struct device *dev, ssize_t size,
                                       dma_addr_t *dma_handle, void **ret);
-int dma_release_from_coherent(struct device *dev, int order, void *vaddr);
+int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr);
 
-int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
+int dma_mmap_from_dev_coherent(struct device *dev, struct vm_area_struct *vma,
                            void *cpu_addr, size_t size, int *ret);
+
+void *dma_alloc_from_global_coherent(ssize_t size, dma_addr_t *dma_handle);
+int dma_release_from_global_coherent(int order, void *vaddr);
+int dma_mmap_from_global_coherent(struct vm_area_struct *vma, void *cpu_addr,
+                                 size_t size, int *ret);
+
 #else
-#define dma_alloc_from_coherent(dev, size, handle, ret) (0)
-#define dma_release_from_coherent(dev, order, vaddr) (0)
-#define dma_mmap_from_coherent(dev, vma, vaddr, order, ret) (0)
+#define dma_alloc_from_dev_coherent(dev, size, handle, ret) (0)
+#define dma_release_from_dev_coherent(dev, order, vaddr) (0)
+#define dma_mmap_from_dev_coherent(dev, vma, vaddr, order, ret) (0)
+
+static inline void *dma_alloc_from_global_coherent(ssize_t size,
+                                                  dma_addr_t *dma_handle)
+{
+       return NULL;
+}
+
+static inline int dma_release_from_global_coherent(int order, void *vaddr)
+{
+       return 0;
+}
+
+static inline int dma_mmap_from_global_coherent(struct vm_area_struct *vma,
+                                               void *cpu_addr, size_t size,
+                                               int *ret)
+{
+       return 0;
+}
 #endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */
 
 #ifdef CONFIG_HAS_DMA
@@ -481,7 +505,7 @@ static inline void *dma_alloc_attrs(struct device *dev, size_t size,
 
        BUG_ON(!ops);
 
-       if (dma_alloc_from_coherent(dev, size, dma_handle, &cpu_addr))
+       if (dma_alloc_from_dev_coherent(dev, size, dma_handle, &cpu_addr))
                return cpu_addr;
 
        if (!arch_dma_alloc_attrs(&dev, &flag))
@@ -503,7 +527,7 @@ static inline void dma_free_attrs(struct device *dev, size_t size,
        BUG_ON(!ops);
        WARN_ON(irqs_disabled());
 
-       if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
+       if (dma_release_from_dev_coherent(dev, get_order(size), cpu_addr))
                return;
 
        if (!ops->free || !cpu_addr)
index 83cc986..afdbb70 100644 (file)
@@ -374,5 +374,9 @@ struct ethtool_ops {
                                      struct ethtool_link_ksettings *);
        int     (*set_link_ksettings)(struct net_device *,
                                      const struct ethtool_link_ksettings *);
+       int     (*get_fecparam)(struct net_device *,
+                                     struct ethtool_fecparam *);
+       int     (*set_fecparam)(struct net_device *,
+                                     struct ethtool_fecparam *);
 };
 #endif /* _LINUX_ETHTOOL_H */
index 6daf6d4..2f14ac7 100644 (file)
@@ -14,6 +14,7 @@
 #define _LINUX_EVENTPOLL_H
 
 #include <uapi/linux/eventpoll.h>
+#include <uapi/linux/kcmp.h>
 
 
 /* Forward declarations to avoid compiler errors */
@@ -22,6 +23,10 @@ struct file;
 
 #ifdef CONFIG_EPOLL
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+struct file *get_epoll_tfile_raw_ptr(struct file *file, int tfd, unsigned long toff);
+#endif
+
 /* Used to initialize the epoll bits inside the "struct file" */
 static inline void eventpoll_init_file(struct file *file)
 {
index 2c1eb15..7d542df 100644 (file)
@@ -9,8 +9,8 @@
 #ifndef _LINUX_FLAT_H
 #define _LINUX_FLAT_H
 
-#include <asm/flat.h>
 #include <uapi/linux/flat.h>
+#include <asm/flat.h>
 
 /*
  * While it would be nice to keep this header clean,  users of older
index 976aaa1..6e1fd5d 100644 (file)
@@ -296,7 +296,7 @@ struct kiocb {
        void                    *private;
        int                     ki_flags;
        enum rw_hint            ki_hint;
-};
+} __randomize_layout;
 
 static inline bool is_sync_kiocb(struct kiocb *kiocb)
 {
@@ -404,7 +404,7 @@ struct address_space {
        struct list_head        private_list;   /* ditto */
        void                    *private_data;  /* ditto */
        errseq_t                wb_err;
-} __attribute__((aligned(sizeof(long))));
+} __attribute__((aligned(sizeof(long)))) __randomize_layout;
        /*
         * On most architectures that alignment is already the case; but
         * must be enforced here for CRIS, to let the least significant bit
@@ -447,7 +447,7 @@ struct block_device {
        int                     bd_fsfreeze_count;
        /* Mutex for freeze */
        struct mutex            bd_fsfreeze_mutex;
-};
+} __randomize_layout;
 
 /*
  * Radix-tree tags, for tagging dirty and writeback pages within the pagecache
@@ -666,7 +666,7 @@ struct inode {
 #endif
 
        void                    *i_private; /* fs or device private pointer */
-};
+} __randomize_layout;
 
 static inline unsigned int i_blocksize(const struct inode *node)
 {
@@ -883,7 +883,8 @@ struct file {
 #endif /* #ifdef CONFIG_EPOLL */
        struct address_space    *f_mapping;
        errseq_t                f_wb_err;
-} __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
+} __randomize_layout
+  __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
 
 struct file_handle {
        __u32 handle_bytes;
@@ -1020,7 +1021,7 @@ struct file_lock {
                        int state;              /* state of grant or error if -ve */
                } afs;
        } fl_u;
-};
+} __randomize_layout;
 
 struct file_lock_context {
        spinlock_t              flc_lock;
@@ -1364,11 +1365,6 @@ struct super_block {
         */
        char *s_subtype;
 
-       /*
-        * Saved mount options for lazy filesystems using
-        * generic_show_options()
-        */
-       char __rcu *s_options;
        const struct dentry_operations *s_d_op; /* default d_op for dentries */
 
        /*
@@ -1417,7 +1413,7 @@ struct super_block {
 
        spinlock_t              s_inode_wblist_lock;
        struct list_head        s_inodes_wb;    /* writeback inodes */
-};
+} __randomize_layout;
 
 /* Helper functions so that in most cases filesystems will
  * not need to deal directly with kuid_t and kgid_t and can
@@ -1703,7 +1699,7 @@ struct file_operations {
                        u64);
        ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
                        u64);
-};
+} __randomize_layout;
 
 struct inode_operations {
        struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
@@ -3046,7 +3042,7 @@ extern int generic_block_fiemap(struct inode *inode,
                                struct fiemap_extent_info *fieinfo, u64 start,
                                u64 len, get_block_t *get_block);
 
-extern void get_filesystem(struct file_system_type *fs);
+extern struct file_system_type *get_filesystem(struct file_system_type *fs);
 extern void put_filesystem(struct file_system_type *fs);
 extern struct file_system_type *get_fs_type(const char *name);
 extern struct super_block *get_super(struct block_device *);
@@ -3123,10 +3119,6 @@ extern void setattr_copy(struct inode *inode, const struct iattr *attr);
 
 extern int file_update_time(struct file *file);
 
-extern int generic_show_options(struct seq_file *m, struct dentry *root);
-extern void save_mount_options(struct super_block *sb, char *options);
-extern void replace_mount_options(struct super_block *sb, char *options);
-
 static inline bool io_is_direct(struct file *filp)
 {
        return (filp->f_flags & O_DIRECT) || IS_DAX(filp->f_mapping->host);
index 0efc3e6..7a02624 100644 (file)
@@ -12,7 +12,7 @@ struct fs_struct {
        int umask;
        int in_exec;
        struct path root, pwd;
-};
+} __randomize_layout;
 
 extern struct kmem_cache *fs_cachep;
 
index 5857390..6383115 100644 (file)
@@ -145,8 +145,8 @@ enum {
 #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 ftrace_hash __rcu        *notrace_hash;
+       struct ftrace_hash __rcu        *filter_hash;
        struct mutex                    regex_lock;
 };
 
@@ -168,7 +168,7 @@ static inline void ftrace_free_init_mem(void) { }
  */
 struct ftrace_ops {
        ftrace_func_t                   func;
-       struct ftrace_ops               *next;
+       struct ftrace_ops __rcu         *next;
        unsigned long                   flags;
        void                            *private;
        ftrace_func_t                   saved_func;
index 9ab3754..50893a1 100644 (file)
@@ -99,6 +99,10 @@ struct fwnode_operations {
        (fwnode ? (fwnode_has_op(fwnode, op) ?                          \
                   (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : -ENXIO) : \
         -EINVAL)
+#define fwnode_call_bool_op(fwnode, op, ...)                           \
+       (fwnode ? (fwnode_has_op(fwnode, op) ?                          \
+                  (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : false) : \
+        false)
 #define fwnode_call_ptr_op(fwnode, op, ...)            \
        (fwnode_has_op(fwnode, op) ?                    \
         (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : NULL)
index 4c6656f..bcfb9f7 100644 (file)
@@ -25,7 +25,7 @@ struct vm_area_struct;
 #define ___GFP_FS              0x80u
 #define ___GFP_COLD            0x100u
 #define ___GFP_NOWARN          0x200u
-#define ___GFP_REPEAT          0x400u
+#define ___GFP_RETRY_MAYFAIL   0x400u
 #define ___GFP_NOFAIL          0x800u
 #define ___GFP_NORETRY         0x1000u
 #define ___GFP_MEMALLOC                0x2000u
@@ -136,26 +136,56 @@ struct vm_area_struct;
  *
  * __GFP_RECLAIM is shorthand to allow/forbid both direct and kswapd reclaim.
  *
- * __GFP_REPEAT: Try hard to allocate the memory, but the allocation attempt
- *   _might_ fail.  This depends upon the particular VM implementation.
+ * The default allocator behavior depends on the request size. We have a concept
+ * of so called costly allocations (with order > PAGE_ALLOC_COSTLY_ORDER).
+ * !costly allocations are too essential to fail so they are implicitly
+ * non-failing by default (with some exceptions like OOM victims might fail so
+ * the caller still has to check for failures) while costly requests try to be
+ * not disruptive and back off even without invoking the OOM killer.
+ * The following three modifiers might be used to override some of these
+ * implicit rules
+ *
+ * __GFP_NORETRY: The VM implementation will try only very lightweight
+ *   memory direct reclaim to get some memory under memory pressure (thus
+ *   it can sleep). It will avoid disruptive actions like OOM killer. The
+ *   caller must handle the failure which is quite likely to happen under
+ *   heavy memory pressure. The flag is suitable when failure can easily be
+ *   handled at small cost, such as reduced throughput
+ *
+ * __GFP_RETRY_MAYFAIL: The VM implementation will retry memory reclaim
+ *   procedures that have previously failed if there is some indication
+ *   that progress has been made else where.  It can wait for other
+ *   tasks to attempt high level approaches to freeing memory such as
+ *   compaction (which removes fragmentation) and page-out.
+ *   There is still a definite limit to the number of retries, but it is
+ *   a larger limit than with __GFP_NORETRY.
+ *   Allocations with this flag may fail, but only when there is
+ *   genuinely little unused memory. While these allocations do not
+ *   directly trigger the OOM killer, their failure indicates that
+ *   the system is likely to need to use the OOM killer soon.  The
+ *   caller must handle failure, but can reasonably do so by failing
+ *   a higher-level request, or completing it only in a much less
+ *   efficient manner.
+ *   If the allocation does fail, and the caller is in a position to
+ *   free some non-essential memory, doing so could benefit the system
+ *   as a whole.
  *
  * __GFP_NOFAIL: The VM implementation _must_ retry infinitely: the caller
- *   cannot handle allocation failures. New users should be evaluated carefully
- *   (and the flag should be used only when there is no reasonable failure
- *   policy) but it is definitely preferable to use the flag rather than
- *   opencode endless loop around allocator.
- *
- * __GFP_NORETRY: The VM implementation must not retry indefinitely and will
- *   return NULL when direct reclaim and memory compaction have failed to allow
- *   the allocation to succeed.  The OOM killer is not called with the current
- *   implementation.
+ *   cannot handle allocation failures. The allocation could block
+ *   indefinitely but will never return with failure. Testing for
+ *   failure is pointless.
+ *   New users should be evaluated carefully (and the flag should be
+ *   used only when there is no reasonable failure policy) but it is
+ *   definitely preferable to use the flag rather than opencode endless
+ *   loop around allocator.
+ *   Using this flag for costly allocations is _highly_ discouraged.
  */
 #define __GFP_IO       ((__force gfp_t)___GFP_IO)
 #define __GFP_FS       ((__force gfp_t)___GFP_FS)
 #define __GFP_DIRECT_RECLAIM   ((__force gfp_t)___GFP_DIRECT_RECLAIM) /* Caller can reclaim */
 #define __GFP_KSWAPD_RECLAIM   ((__force gfp_t)___GFP_KSWAPD_RECLAIM) /* kswapd can wake */
 #define __GFP_RECLAIM ((__force gfp_t)(___GFP_DIRECT_RECLAIM|___GFP_KSWAPD_RECLAIM))
-#define __GFP_REPEAT   ((__force gfp_t)___GFP_REPEAT)
+#define __GFP_RETRY_MAYFAIL    ((__force gfp_t)___GFP_RETRY_MAYFAIL)
 #define __GFP_NOFAIL   ((__force gfp_t)___GFP_NOFAIL)
 #define __GFP_NORETRY  ((__force gfp_t)___GFP_NORETRY)
 
index 8d9fe13..0ed8e41 100644 (file)
@@ -268,6 +268,9 @@ struct hugetlbfs_sb_info {
        spinlock_t      stat_lock;
        struct hstate *hstate;
        struct hugepage_subpool *spool;
+       kuid_t  uid;
+       kgid_t  gid;
+       umode_t mode;
 };
 
 static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb)
index 71fd92d..fadd579 100644 (file)
@@ -20,6 +20,9 @@ struct kern_ipc_perm {
        umode_t         mode;
        unsigned long   seq;
        void            *security;
-} ____cacheline_aligned_in_smp;
+
+       struct rcu_head rcu;
+       atomic_t refcount;
+} ____cacheline_aligned_in_smp __randomize_layout;
 
 #endif /* _LINUX_IPC_H */
index 848e579..65327ee 100644 (file)
@@ -61,7 +61,7 @@ struct ipc_namespace {
        struct ucounts *ucounts;
 
        struct ns_common ns;
-};
+} __randomize_layout;
 
 extern struct ipc_namespace init_ipc_ns;
 extern spinlock_t mq_lock;
index e1b4429..474d6bb 100644 (file)
@@ -128,6 +128,7 @@ struct inet6_skb_parm {
 #define IP6SKB_FRAGMENTED      16
 #define IP6SKB_HOPBYHOP        32
 #define IP6SKB_L3SLAVE         64
+#define IP6SKB_JUMBOGRAM      128
 };
 
 #if defined(CONFIG_NET_L3_MASTER_DEV)
@@ -152,6 +153,11 @@ static inline int inet6_iif(const struct sk_buff *skb)
        return l3_slave ? skb->skb_iif : IP6CB(skb)->iif;
 }
 
+static inline bool inet6_is_jumbogram(const struct sk_buff *skb)
+{
+       return !!(IP6CB(skb)->flags & IP6SKB_JUMBOGRAM);
+}
+
 /* can not be used in TCP layer after tcp_v6_fill_cb */
 static inline bool inet6_exact_dif_match(struct net *net, struct sk_buff *skb)
 {
index 00db35b..d2d5437 100644 (file)
@@ -388,7 +388,12 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
  * @irq_mask_ack:      ack and mask an interrupt source
  * @irq_unmask:                unmask an interrupt source
  * @irq_eoi:           end of interrupt
- * @irq_set_affinity:  set the CPU affinity on SMP machines
+ * @irq_set_affinity:  Set the CPU affinity on SMP machines. If the force
+ *                     argument is true, it tells the driver to
+ *                     unconditionally apply the affinity setting. Sanity
+ *                     checks against the supplied affinity mask are not
+ *                     required. This is used for CPU hotplug where the
+ *                     target CPU is not yet set in the cpu_online_mask.
  * @irq_retrigger:     resend an IRQ to the CPU
  * @irq_set_type:      set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ
  * @irq_set_wake:      enable/disable power-management wake-on of an IRQ
index 348c6f4..8037850 100644 (file)
@@ -85,19 +85,18 @@ static inline u32 jhash(const void *key, u32 length, u32 initval)
                k += 12;
        }
        /* Last block: affect all 32 bits of (c) */
-       /* All the case statements fall through */
        switch (length) {
-       case 12: c += (u32)k[11]<<24;
-       case 11: c += (u32)k[10]<<16;
-       case 10: c += (u32)k[9]<<8;
-       case 9:  c += k[8];
-       case 8:  b += (u32)k[7]<<24;
-       case 7:  b += (u32)k[6]<<16;
-       case 6:  b += (u32)k[5]<<8;
-       case 5:  b += k[4];
-       case 4:  a += (u32)k[3]<<24;
-       case 3:  a += (u32)k[2]<<16;
-       case 2:  a += (u32)k[1]<<8;
+       case 12: c += (u32)k[11]<<24;   /* fall through */
+       case 11: c += (u32)k[10]<<16;   /* fall through */
+       case 10: c += (u32)k[9]<<8;     /* fall through */
+       case 9:  c += k[8];             /* fall through */
+       case 8:  b += (u32)k[7]<<24;    /* fall through */
+       case 7:  b += (u32)k[6]<<16;    /* fall through */
+       case 6:  b += (u32)k[5]<<8;     /* fall through */
+       case 5:  b += k[4];             /* fall through */
+       case 4:  a += (u32)k[3]<<24;    /* fall through */
+       case 3:  a += (u32)k[2]<<16;    /* fall through */
+       case 2:  a += (u32)k[1]<<8;     /* fall through */
        case 1:  a += k[0];
                 __jhash_final(a, b, c);
        case 0: /* Nothing left to add */
@@ -131,10 +130,10 @@ static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
                k += 3;
        }
 
-       /* Handle the last 3 u32's: all the case statements fall through */
+       /* Handle the last 3 u32's */
        switch (length) {
-       case 3: c += k[2];
-       case 2: b += k[1];
+       case 3: c += k[2];      /* fall through */
+       case 2: b += k[1];      /* fall through */
        case 1: a += k[0];
                __jhash_final(a, b, c);
        case 0: /* Nothing left to add */
index 1c91f26..bd6d96c 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/log2.h>
 #include <linux/typecheck.h>
 #include <linux/printk.h>
+#include <linux/build_bug.h>
 #include <asm/byteorder.h>
 #include <uapi/linux/kernel.h>
 
@@ -854,9 +855,12 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
  * @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) );})
+#define container_of(ptr, type, member) ({                             \
+       void *__mptr = (void *)(ptr);                                   \
+       BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&   \
+                        !__same_type(*(ptr), void),                    \
+                        "pointer type mismatch in container_of()");    \
+       ((type *)(__mptr - offsetof(type, member))); })
 
 /* Rebuild everything on CONFIG_FTRACE_MCOUNT_RECORD */
 #ifdef CONFIG_FTRACE_MCOUNT_RECORD
index 6588841..dd056fa 100644 (file)
@@ -172,6 +172,7 @@ struct kimage {
        unsigned long start;
        struct page *control_code_page;
        struct page *swap_page;
+       void *vmcoreinfo_data_copy; /* locates in the crash memory */
 
        unsigned long nr_segments;
        struct kexec_segment segment[KEXEC_SEGMENT_MAX];
@@ -241,6 +242,7 @@ extern void crash_kexec(struct pt_regs *);
 int kexec_should_crash(struct task_struct *);
 int kexec_crash_loaded(void);
 void crash_save_cpu(struct pt_regs *regs, int cpu);
+extern int kimage_crash_copy_vmcoreinfo(struct kimage *image);
 
 extern struct kimage *kexec_image;
 extern struct kimage *kexec_crash_image;
index 8496cf6..9520fc3 100644 (file)
@@ -45,7 +45,7 @@ struct key_preparsed_payload {
        size_t          datalen;        /* Raw datalen */
        size_t          quotalen;       /* Quota length for proposed payload */
        time_t          expiry;         /* Expiry time of key */
-};
+} __randomize_layout;
 
 typedef int (*request_key_actor_t)(struct key_construction *key,
                                   const char *op, void *aux);
@@ -158,7 +158,7 @@ struct key_type {
        /* internal fields */
        struct list_head        link;           /* link in types list */
        struct lock_class_key   lock_class;     /* key->sem lock class */
-};
+} __randomize_layout;
 
 extern struct key_type key_type_keyring;
 
index c4e441e..655082c 100644 (file)
@@ -64,7 +64,7 @@ struct subprocess_info {
        int (*init)(struct subprocess_info *info, struct cred *new);
        void (*cleanup)(struct subprocess_info *info);
        void *data;
-};
+} __randomize_layout;
 
 extern int
 call_usermodehelper(const char *path, char **argv, char **envp, int wait);
index eeab34b..4d800c7 100644 (file)
@@ -172,7 +172,7 @@ struct kset {
        spinlock_t list_lock;
        struct kobject kobj;
        const struct kset_uevent_ops *uevent_ops;
-};
+} __randomize_layout;
 
 extern void kset_init(struct kset *kset);
 extern int __must_check kset_register(struct kset *kset);
index 0b50e7b..890b706 100644 (file)
@@ -234,7 +234,7 @@ struct kvm_vcpu {
 
        int guest_fpu_loaded, guest_xcr0_loaded;
        struct swait_queue_head wq;
-       struct pid *pid;
+       struct pid __rcu *pid;
        int sigset_active;
        sigset_t sigset;
        struct kvm_vcpu_stat stat;
@@ -390,7 +390,7 @@ struct kvm {
        spinlock_t mmu_lock;
        struct mutex slots_lock;
        struct mm_struct *mm; /* userspace tied to this vm */
-       struct kvm_memslots *memslots[KVM_ADDRESS_SPACE_NUM];
+       struct kvm_memslots __rcu *memslots[KVM_ADDRESS_SPACE_NUM];
        struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
 
        /*
@@ -404,7 +404,7 @@ struct kvm {
        int last_boosted_vcpu;
        struct list_head vm_list;
        struct mutex lock;
-       struct kvm_io_bus *buses[KVM_NR_BUSES];
+       struct kvm_io_bus __rcu *buses[KVM_NR_BUSES];
 #ifdef CONFIG_HAVE_KVM_EVENTFD
        struct {
                spinlock_t        lock;
@@ -445,6 +445,7 @@ struct kvm {
        struct kvm_stat_data **debugfs_stat_data;
        struct srcu_struct srcu;
        struct srcu_struct irq_srcu;
+       pid_t userspace_pid;
 };
 
 #define kvm_err(fmt, ...) \
@@ -473,6 +474,12 @@ struct kvm {
 #define vcpu_err(vcpu, fmt, ...)                                       \
        kvm_err("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__)
 
+static inline struct kvm_io_bus *kvm_get_bus(struct kvm *kvm, enum kvm_bus idx)
+{
+       return srcu_dereference_check(kvm->buses[idx], &kvm->srcu,
+                                     lockdep_is_held(&kvm->slots_lock));
+}
+
 static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)
 {
        /* Pairs with smp_wmb() in kvm_vm_ioctl_create_vcpu, in case
@@ -562,9 +569,8 @@ void kvm_put_kvm(struct kvm *kvm);
 
 static inline struct kvm_memslots *__kvm_memslots(struct kvm *kvm, int as_id)
 {
-       return rcu_dereference_check(kvm->memslots[as_id],
-                       srcu_read_lock_held(&kvm->srcu)
-                       || lockdep_is_held(&kvm->slots_lock));
+       return srcu_dereference_check(kvm->memslots[as_id], &kvm->srcu,
+                       lockdep_is_held(&kvm->slots_lock));
 }
 
 static inline struct kvm_memslots *kvm_memslots(struct kvm *kvm)
index 55de3da..931c32f 100644 (file)
@@ -435,7 +435,7 @@ enum {
        ATA_HORKAGE_NOLPM       = (1 << 20),    /* don't use LPM */
        ATA_HORKAGE_WD_BROKEN_LPM = (1 << 21),  /* some WDs have broken LPM */
        ATA_HORKAGE_ZERO_AFTER_TRIM = (1 << 22),/* guarantees zero after trim */
-       ATA_HORKAGE_NO_NCQ_LOG  = (1 << 23),    /* don't use NCQ for log read */
+       ATA_HORKAGE_NO_DMA_LOG  = (1 << 23),    /* don't use DMA for log read */
        ATA_HORKAGE_NOTRIM      = (1 << 24),    /* don't use TRIM */
        ATA_HORKAGE_MAX_SEC_1024 = (1 << 25),   /* Limit max sects to 1024 */
 
index d117381..1957635 100644 (file)
@@ -93,6 +93,23 @@ static inline void init_llist_head(struct llist_head *list)
        container_of(ptr, type, member)
 
 /**
+ * member_address_is_nonnull - check whether the member address is not NULL
+ * @ptr:       the object pointer (struct type * that contains the llist_node)
+ * @member:    the name of the llist_node within the struct.
+ *
+ * This macro is conceptually the same as
+ *     &ptr->member != NULL
+ * but it works around the fact that compilers can decide that taking a member
+ * address is never a NULL pointer.
+ *
+ * Real objects that start at a high address and have a member at NULL are
+ * unlikely to exist, but such pointers may be returned e.g. by the
+ * container_of() macro.
+ */
+#define member_address_is_nonnull(ptr, member) \
+       ((uintptr_t)(ptr) + offsetof(typeof(*(ptr)), member) != 0)
+
+/**
  * llist_for_each - iterate over some deleted entries of a lock-less list
  * @pos:       the &struct llist_node to use as a loop cursor
  * @node:      the first entry of deleted list entries
@@ -145,7 +162,7 @@ static inline void init_llist_head(struct llist_head *list)
  */
 #define llist_for_each_entry(pos, node, member)                                \
        for ((pos) = llist_entry((node), typeof(*(pos)), member);       \
-            &(pos)->member != NULL;                                    \
+            member_address_is_nonnull(pos, member);                    \
             (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))
 
 /**
@@ -167,7 +184,7 @@ static inline void init_llist_head(struct llist_head *list)
  */
 #define llist_for_each_entry_safe(pos, n, node, member)                               \
        for (pos = llist_entry((node), typeof(*pos), member);                  \
-            &pos->member != NULL &&                                           \
+            member_address_is_nonnull(pos, member) &&                         \
                (n = llist_entry(pos->member.next, typeof(*n), member), true); \
             pos = n)
 
index 41f7b6a..3eca677 100644 (file)
@@ -192,9 +192,9 @@ struct nlm_block {
  * Global variables
  */
 extern const struct rpc_program        nlm_program;
-extern struct svc_procedure    nlmsvc_procedures[];
+extern const struct svc_procedure nlmsvc_procedures[];
 #ifdef CONFIG_LOCKD_V4
-extern struct svc_procedure    nlmsvc_procedures4[];
+extern const struct svc_procedure nlmsvc_procedures4[];
 #endif
 extern int                     nlmsvc_grace_period;
 extern unsigned long           nlmsvc_timeout;
index d39ed1c..7acbecc 100644 (file)
@@ -95,19 +95,19 @@ struct nlm_reboot {
  */
 #define NLMSVC_XDRSIZE         sizeof(struct nlm_args)
 
-int    nlmsvc_decode_testargs(struct svc_rqst *, __be32 *, struct nlm_args *);
-int    nlmsvc_encode_testres(struct svc_rqst *, __be32 *, struct nlm_res *);
-int    nlmsvc_decode_lockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
-int    nlmsvc_decode_cancargs(struct svc_rqst *, __be32 *, struct nlm_args *);
-int    nlmsvc_decode_unlockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
-int    nlmsvc_encode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
-int    nlmsvc_decode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
-int    nlmsvc_encode_void(struct svc_rqst *, __be32 *, void *);
-int    nlmsvc_decode_void(struct svc_rqst *, __be32 *, void *);
-int    nlmsvc_decode_shareargs(struct svc_rqst *, __be32 *, struct nlm_args *);
-int    nlmsvc_encode_shareres(struct svc_rqst *, __be32 *, struct nlm_res *);
-int    nlmsvc_decode_notify(struct svc_rqst *, __be32 *, struct nlm_args *);
-int    nlmsvc_decode_reboot(struct svc_rqst *, __be32 *, struct nlm_reboot *);
+int    nlmsvc_decode_testargs(struct svc_rqst *, __be32 *);
+int    nlmsvc_encode_testres(struct svc_rqst *, __be32 *);
+int    nlmsvc_decode_lockargs(struct svc_rqst *, __be32 *);
+int    nlmsvc_decode_cancargs(struct svc_rqst *, __be32 *);
+int    nlmsvc_decode_unlockargs(struct svc_rqst *, __be32 *);
+int    nlmsvc_encode_res(struct svc_rqst *, __be32 *);
+int    nlmsvc_decode_res(struct svc_rqst *, __be32 *);
+int    nlmsvc_encode_void(struct svc_rqst *, __be32 *);
+int    nlmsvc_decode_void(struct svc_rqst *, __be32 *);
+int    nlmsvc_decode_shareargs(struct svc_rqst *, __be32 *);
+int    nlmsvc_encode_shareres(struct svc_rqst *, __be32 *);
+int    nlmsvc_decode_notify(struct svc_rqst *, __be32 *);
+int    nlmsvc_decode_reboot(struct svc_rqst *, __be32 *);
 /*
 int    nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *);
 int    nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
index e58c88b..bf16456 100644 (file)
 
 
 
-int    nlm4svc_decode_testargs(struct svc_rqst *, __be32 *, struct nlm_args *);
-int    nlm4svc_encode_testres(struct svc_rqst *, __be32 *, struct nlm_res *);
-int    nlm4svc_decode_lockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
-int    nlm4svc_decode_cancargs(struct svc_rqst *, __be32 *, struct nlm_args *);
-int    nlm4svc_decode_unlockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
-int    nlm4svc_encode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
-int    nlm4svc_decode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
-int    nlm4svc_encode_void(struct svc_rqst *, __be32 *, void *);
-int    nlm4svc_decode_void(struct svc_rqst *, __be32 *, void *);
-int    nlm4svc_decode_shareargs(struct svc_rqst *, __be32 *, struct nlm_args *);
-int    nlm4svc_encode_shareres(struct svc_rqst *, __be32 *, struct nlm_res *);
-int    nlm4svc_decode_notify(struct svc_rqst *, __be32 *, struct nlm_args *);
-int    nlm4svc_decode_reboot(struct svc_rqst *, __be32 *, struct nlm_reboot *);
+int    nlm4svc_decode_testargs(struct svc_rqst *, __be32 *);
+int    nlm4svc_encode_testres(struct svc_rqst *, __be32 *);
+int    nlm4svc_decode_lockargs(struct svc_rqst *, __be32 *);
+int    nlm4svc_decode_cancargs(struct svc_rqst *, __be32 *);
+int    nlm4svc_decode_unlockargs(struct svc_rqst *, __be32 *);
+int    nlm4svc_encode_res(struct svc_rqst *, __be32 *);
+int    nlm4svc_decode_res(struct svc_rqst *, __be32 *);
+int    nlm4svc_encode_void(struct svc_rqst *, __be32 *);
+int    nlm4svc_decode_void(struct svc_rqst *, __be32 *);
+int    nlm4svc_decode_shareargs(struct svc_rqst *, __be32 *);
+int    nlm4svc_encode_shareres(struct svc_rqst *, __be32 *);
+int    nlm4svc_decode_notify(struct svc_rqst *, __be32 *);
+int    nlm4svc_decode_reboot(struct svc_rqst *, __be32 *);
 /*
 int    nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *);
 int    nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
index 7a86925..3a90feb 100644 (file)
@@ -1912,7 +1912,7 @@ struct security_hook_heads {
        struct list_head audit_rule_match;
        struct list_head audit_rule_free;
 #endif /* CONFIG_AUDIT */
-};
+} __randomize_layout;
 
 /*
  * Security module hook list structure.
@@ -1923,7 +1923,7 @@ struct security_hook_list {
        struct list_head                *head;
        union security_list_options     hook;
        char                            *lsm;
-};
+} __randomize_layout;
 
 /*
  * Initializing a security_hook_list structure takes
index 4634da5..3e0d405 100644 (file)
@@ -34,7 +34,7 @@ extern char *migrate_reason_names[MR_TYPES];
 static inline struct page *new_page_nodemask(struct page *page,
                                int preferred_nid, nodemask_t *nodemask)
 {
-       gfp_t gfp_mask = GFP_USER | __GFP_MOVABLE;
+       gfp_t gfp_mask = GFP_USER | __GFP_MOVABLE | __GFP_RETRY_MAYFAIL;
 
        if (PageHuge(page))
                return alloc_huge_page_nodemask(page_hstate(compound_head(page)),
index d5bed08..aad5d81 100644 (file)
@@ -1068,7 +1068,7 @@ static inline int mlx4_is_eth(struct mlx4_dev *dev, int port)
 }
 
 int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
-                  struct mlx4_buf *buf, gfp_t gfp);
+                  struct mlx4_buf *buf);
 void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf);
 static inline void *mlx4_buf_offset(struct mlx4_buf *buf, int offset)
 {
@@ -1105,10 +1105,9 @@ int mlx4_mw_enable(struct mlx4_dev *dev, struct mlx4_mw *mw);
 int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
                   int start_index, int npages, u64 *page_list);
 int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
-                      struct mlx4_buf *buf, gfp_t gfp);
+                      struct mlx4_buf *buf);
 
-int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order,
-                 gfp_t gfp);
+int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order);
 void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db);
 
 int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
@@ -1124,8 +1123,7 @@ int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align,
                          int *base, u8 flags);
 void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt);
 
-int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp,
-                 gfp_t gfp);
+int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp);
 void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp);
 
 int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcdn,
index 87869c0..3030121 100644 (file)
@@ -7749,8 +7749,10 @@ struct mlx5_ifc_pcam_reg_bits {
 };
 
 struct mlx5_ifc_mcam_enhanced_features_bits {
-       u8         reserved_at_0[0x7f];
+       u8         reserved_at_0[0x7d];
 
+       u8         mtpps_enh_out_per_adj[0x1];
+       u8         mtpps_fs[0x1];
        u8         pcie_performance_group[0x1];
 };
 
@@ -8159,7 +8161,8 @@ struct mlx5_ifc_mtpps_reg_bits {
        u8         reserved_at_78[0x4];
        u8         cap_pin_4_mode[0x4];
 
-       u8         reserved_at_80[0x80];
+       u8         field_select[0x20];
+       u8         reserved_at_a0[0x60];
 
        u8         enable[0x1];
        u8         reserved_at_101[0xb];
@@ -8174,8 +8177,9 @@ struct mlx5_ifc_mtpps_reg_bits {
 
        u8         out_pulse_duration[0x10];
        u8         out_periodic_adjustment[0x10];
+       u8         enhanced_out_periodic_adjustment[0x20];
 
-       u8         reserved_at_1a0[0x60];
+       u8         reserved_at_1c0[0x20];
 };
 
 struct mlx5_ifc_mtppse_reg_bits {
index 45cdb27..ff15181 100644 (file)
@@ -342,7 +342,7 @@ struct vm_area_struct {
        struct mempolicy *vm_policy;    /* NUMA policy for the VMA */
 #endif
        struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
-};
+} __randomize_layout;
 
 struct core_thread {
        struct task_struct *task;
@@ -500,7 +500,7 @@ struct mm_struct {
        atomic_long_t hugetlb_usage;
 #endif
        struct work_struct async_put_work;
-};
+} __randomize_layout;
 
 extern struct mm_struct init_mm;
 
index 8eb9a1e..e7bdd54 100644 (file)
@@ -45,7 +45,7 @@ struct module_kobject {
        struct kobject *drivers_dir;
        struct module_param_attrs *mp;
        struct completion *kobj_completion;
-};
+} __randomize_layout;
 
 struct module_attribute {
        struct attribute attr;
@@ -475,7 +475,7 @@ struct module {
        ctor_fn_t *ctors;
        unsigned int num_ctors;
 #endif
-} ____cacheline_aligned;
+} ____cacheline_aligned __randomize_layout;
 #ifndef MODULE_ARCH_INIT
 #define MODULE_ARCH_INIT {}
 #endif
index 8e0352a..1ce85e6 100644 (file)
@@ -67,7 +67,7 @@ struct vfsmount {
        struct dentry *mnt_root;        /* root of the mounted tree */
        struct super_block *mnt_sb;     /* pointer to superblock */
        int mnt_flags;
-};
+} __randomize_layout;
 
 struct file; /* forward dec */
 struct path;
index f3f302f..a001305 100644 (file)
@@ -29,7 +29,7 @@ struct msg_queue {
        struct list_head q_messages;
        struct list_head q_receivers;
        struct list_head q_senders;
-};
+} __randomize_layout;
 
 /* Helper routines for sys_msgsnd and sys_msgrcv */
 extern long do_msgsnd(int msqid, long mtype, void __user *mtext,
index de0d889..892148c 100644 (file)
@@ -107,6 +107,8 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
 #define NAND_STATUS_READY      0x40
 #define NAND_STATUS_WP         0x80
 
+#define NAND_DATA_IFACE_CHECK_ONLY     -1
+
 /*
  * Constants for ECC_MODES
  */
@@ -116,6 +118,7 @@ typedef enum {
        NAND_ECC_HW,
        NAND_ECC_HW_SYNDROME,
        NAND_ECC_HW_OOB_FIRST,
+       NAND_ECC_ON_DIE,
 } nand_ecc_modes_t;
 
 enum nand_ecc_algo {
@@ -257,6 +260,8 @@ struct nand_chip;
 
 /* Vendor-specific feature address (Micron) */
 #define ONFI_FEATURE_ADDR_READ_RETRY   0x89
+#define ONFI_FEATURE_ON_DIE_ECC                0x90
+#define   ONFI_FEATURE_ON_DIE_ECC_EN   BIT(3)
 
 /* ONFI subfeature parameters length */
 #define ONFI_SUBFEATURE_PARAM_LEN      4
@@ -477,6 +482,44 @@ static inline void nand_hw_control_init(struct nand_hw_control *nfc)
 }
 
 /**
+ * struct nand_ecc_step_info - ECC step information of ECC engine
+ * @stepsize: data bytes per ECC step
+ * @strengths: array of supported strengths
+ * @nstrengths: number of supported strengths
+ */
+struct nand_ecc_step_info {
+       int stepsize;
+       const int *strengths;
+       int nstrengths;
+};
+
+/**
+ * struct nand_ecc_caps - capability of ECC engine
+ * @stepinfos: array of ECC step information
+ * @nstepinfos: number of ECC step information
+ * @calc_ecc_bytes: driver's hook to calculate ECC bytes per step
+ */
+struct nand_ecc_caps {
+       const struct nand_ecc_step_info *stepinfos;
+       int nstepinfos;
+       int (*calc_ecc_bytes)(int step_size, int strength);
+};
+
+/* a shorthand to generate struct nand_ecc_caps with only one ECC stepsize */
+#define NAND_ECC_CAPS_SINGLE(__name, __calc, __step, ...)      \
+static const int __name##_strengths[] = { __VA_ARGS__ };       \
+static const struct nand_ecc_step_info __name##_stepinfo = {   \
+       .stepsize = __step,                                     \
+       .strengths = __name##_strengths,                        \
+       .nstrengths = ARRAY_SIZE(__name##_strengths),           \
+};                                                             \
+static const struct nand_ecc_caps __name = {                   \
+       .stepinfos = &__name##_stepinfo,                        \
+       .nstepinfos = 1,                                        \
+       .calc_ecc_bytes = __calc,                               \
+}
+
+/**
  * struct nand_ecc_ctrl - Control structure for ECC
  * @mode:      ECC mode
  * @algo:      ECC algorithm
@@ -815,7 +858,10 @@ struct nand_manufacturer_ops {
  * @read_retries:      [INTERN] the number of read retry modes supported
  * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
  * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
- * @setup_data_interface: [OPTIONAL] setup the data interface and timing
+ * @setup_data_interface: [OPTIONAL] setup the data interface and timing. If
+ *                       chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this
+ *                       means the configuration should not be applied but
+ *                       only checked.
  * @bbt:               [INTERN] bad block table pointer
  * @bbt_td:            [REPLACEABLE] bad block table descriptor for flash
  *                     lookup.
@@ -826,9 +872,6 @@ struct nand_manufacturer_ops {
  *                     structure which is shared among multiple independent
  *                     devices.
  * @priv:              [OPTIONAL] pointer to private chip data
- * @errstat:           [OPTIONAL] hardware specific function to perform
- *                     additional error status checks (determine if errors are
- *                     correctable).
  * @manufacturer:      [INTERN] Contains manufacturer information
  */
 
@@ -852,16 +895,13 @@ struct nand_chip {
        int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
        int (*erase)(struct mtd_info *mtd, int page);
        int (*scan_bbt)(struct mtd_info *mtd);
-       int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
-                       int status, int page);
        int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,
                        int feature_addr, uint8_t *subfeature_para);
        int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
                        int feature_addr, uint8_t *subfeature_para);
        int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
-       int (*setup_data_interface)(struct mtd_info *mtd,
-                                   const struct nand_data_interface *conf,
-                                   bool check_only);
+       int (*setup_data_interface)(struct mtd_info *mtd, int chipnr,
+                                   const struct nand_data_interface *conf);
 
 
        int chip_delay;
@@ -1244,6 +1284,15 @@ int nand_check_erased_ecc_chunk(void *data, int datalen,
                                void *extraoob, int extraooblen,
                                int threshold);
 
+int nand_check_ecc_caps(struct nand_chip *chip,
+                       const struct nand_ecc_caps *caps, int oobavail);
+
+int nand_match_ecc_req(struct nand_chip *chip,
+                      const struct nand_ecc_caps *caps,  int oobavail);
+
+int nand_maximize_ecc(struct nand_chip *chip,
+                     const struct nand_ecc_caps *caps, int oobavail);
+
 /* Default write_oob implementation */
 int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
 
@@ -1258,6 +1307,19 @@ int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
 int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
                           int page);
 
+/* Stub used by drivers that do not support GET/SET FEATURES operations */
+int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd,
+                                      struct nand_chip *chip, int addr,
+                                      u8 *subfeature_param);
+
+/* Default read_page_raw implementation */
+int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                      uint8_t *buf, int oob_required, int page);
+
+/* Default write_page_raw implementation */
+int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                       const uint8_t *buf, int oob_required, int page);
+
 /* Reset and initialize a NAND device */
 int nand_reset(struct nand_chip *chip, int chipnr);
 
index 06df1e0..c4beb70 100644 (file)
  *
  * For each partition, these fields are available:
  * name: string that will be used to label the partition's MTD device.
+ * types: some partitions can be containers using specific format to describe
+ *     embedded subpartitions / volumes. E.g. many home routers use "firmware"
+ *     partition that contains at least kernel and rootfs. In such case an
+ *     extra parser is needed that will detect these dynamic partitions and
+ *     report them to the MTD subsystem. If set this property stores an array
+ *     of parser names to use when looking for subpartitions.
  * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition
  *     will extend to the end of the master MTD device.
  * offset: absolute starting position within the master MTD device; if
@@ -38,6 +44,7 @@
 
 struct mtd_partition {
        const char *name;               /* identifier string */
+       const char *const *types;       /* names of parsers to use if any */
        uint64_t size;                  /* partition size */
        uint64_t offset;                /* offset within the master MTD space */
        uint32_t mask_flags;            /* master MTD flags to mask out for this partition */
index f2a7180..55faa2f 100644 (file)
 #define SPINOR_OP_BE_32K_4B    0x5c    /* Erase 32KiB block */
 #define SPINOR_OP_SE_4B                0xdc    /* Sector erase (usually 64KiB) */
 
+/* Double Transfer Rate opcodes - defined in JEDEC JESD216B. */
+#define SPINOR_OP_READ_1_1_1_DTR       0x0d
+#define SPINOR_OP_READ_1_2_2_DTR       0xbd
+#define SPINOR_OP_READ_1_4_4_DTR       0xed
+
+#define SPINOR_OP_READ_1_1_1_DTR_4B    0x0e
+#define SPINOR_OP_READ_1_2_2_DTR_4B    0xbe
+#define SPINOR_OP_READ_1_4_4_DTR_4B    0xee
+
 /* Used for SST flashes only. */
 #define SPINOR_OP_BP           0x02    /* Byte program */
 #define SPINOR_OP_WRDI         0x04    /* Write disable */
 /* Configuration Register bits. */
 #define CR_QUAD_EN_SPAN                BIT(1)  /* Spansion Quad I/O */
 
-enum read_mode {
-       SPI_NOR_NORMAL = 0,
-       SPI_NOR_FAST,
-       SPI_NOR_DUAL,
-       SPI_NOR_QUAD,
+/* Supported SPI protocols */
+#define SNOR_PROTO_INST_MASK   GENMASK(23, 16)
+#define SNOR_PROTO_INST_SHIFT  16
+#define SNOR_PROTO_INST(_nbits)        \
+       ((((unsigned long)(_nbits)) << SNOR_PROTO_INST_SHIFT) & \
+        SNOR_PROTO_INST_MASK)
+
+#define SNOR_PROTO_ADDR_MASK   GENMASK(15, 8)
+#define SNOR_PROTO_ADDR_SHIFT  8
+#define SNOR_PROTO_ADDR(_nbits)        \
+       ((((unsigned long)(_nbits)) << SNOR_PROTO_ADDR_SHIFT) & \
+        SNOR_PROTO_ADDR_MASK)
+
+#define SNOR_PROTO_DATA_MASK   GENMASK(7, 0)
+#define SNOR_PROTO_DATA_SHIFT  0
+#define SNOR_PROTO_DATA(_nbits)        \
+       ((((unsigned long)(_nbits)) << SNOR_PROTO_DATA_SHIFT) & \
+        SNOR_PROTO_DATA_MASK)
+
+#define SNOR_PROTO_IS_DTR      BIT(24) /* Double Transfer Rate */
+
+#define SNOR_PROTO_STR(_inst_nbits, _addr_nbits, _data_nbits)  \
+       (SNOR_PROTO_INST(_inst_nbits) |                         \
+        SNOR_PROTO_ADDR(_addr_nbits) |                         \
+        SNOR_PROTO_DATA(_data_nbits))
+#define SNOR_PROTO_DTR(_inst_nbits, _addr_nbits, _data_nbits)  \
+       (SNOR_PROTO_IS_DTR |                                    \
+        SNOR_PROTO_STR(_inst_nbits, _addr_nbits, _data_nbits))
+
+enum spi_nor_protocol {
+       SNOR_PROTO_1_1_1 = SNOR_PROTO_STR(1, 1, 1),
+       SNOR_PROTO_1_1_2 = SNOR_PROTO_STR(1, 1, 2),
+       SNOR_PROTO_1_1_4 = SNOR_PROTO_STR(1, 1, 4),
+       SNOR_PROTO_1_1_8 = SNOR_PROTO_STR(1, 1, 8),
+       SNOR_PROTO_1_2_2 = SNOR_PROTO_STR(1, 2, 2),
+       SNOR_PROTO_1_4_4 = SNOR_PROTO_STR(1, 4, 4),
+       SNOR_PROTO_1_8_8 = SNOR_PROTO_STR(1, 8, 8),
+       SNOR_PROTO_2_2_2 = SNOR_PROTO_STR(2, 2, 2),
+       SNOR_PROTO_4_4_4 = SNOR_PROTO_STR(4, 4, 4),
+       SNOR_PROTO_8_8_8 = SNOR_PROTO_STR(8, 8, 8),
+
+       SNOR_PROTO_1_1_1_DTR = SNOR_PROTO_DTR(1, 1, 1),
+       SNOR_PROTO_1_2_2_DTR = SNOR_PROTO_DTR(1, 2, 2),
+       SNOR_PROTO_1_4_4_DTR = SNOR_PROTO_DTR(1, 4, 4),
+       SNOR_PROTO_1_8_8_DTR = SNOR_PROTO_DTR(1, 8, 8),
 };
 
+static inline bool spi_nor_protocol_is_dtr(enum spi_nor_protocol proto)
+{
+       return !!(proto & SNOR_PROTO_IS_DTR);
+}
+
+static inline u8 spi_nor_get_protocol_inst_nbits(enum spi_nor_protocol proto)
+{
+       return ((unsigned long)(proto & SNOR_PROTO_INST_MASK)) >>
+               SNOR_PROTO_INST_SHIFT;
+}
+
+static inline u8 spi_nor_get_protocol_addr_nbits(enum spi_nor_protocol proto)
+{
+       return ((unsigned long)(proto & SNOR_PROTO_ADDR_MASK)) >>
+               SNOR_PROTO_ADDR_SHIFT;
+}
+
+static inline u8 spi_nor_get_protocol_data_nbits(enum spi_nor_protocol proto)
+{
+       return ((unsigned long)(proto & SNOR_PROTO_DATA_MASK)) >>
+               SNOR_PROTO_DATA_SHIFT;
+}
+
+static inline u8 spi_nor_get_protocol_width(enum spi_nor_protocol proto)
+{
+       return spi_nor_get_protocol_data_nbits(proto);
+}
+
 #define SPI_NOR_MAX_CMD_SIZE   8
 enum spi_nor_ops {
        SPI_NOR_OPS_READ = 0,
@@ -154,9 +231,11 @@ enum spi_nor_option_flags {
  * @read_opcode:       the read opcode
  * @read_dummy:                the dummy needed by the read operation
  * @program_opcode:    the program opcode
- * @flash_read:                the mode of the read
  * @sst_write_second:  used by the SST write operation
  * @flags:             flag options for the current SPI-NOR (SNOR_F_*)
+ * @read_proto:                the SPI protocol for read operations
+ * @write_proto:       the SPI protocol for write operations
+ * @reg_proto          the SPI protocol for read_reg/write_reg/erase operations
  * @cmd_buf:           used by the write_reg
  * @prepare:           [OPTIONAL] do some preparations for the
  *                     read/write/erase/lock/unlock operations
@@ -185,7 +264,9 @@ struct spi_nor {
        u8                      read_opcode;
        u8                      read_dummy;
        u8                      program_opcode;
-       enum read_mode          flash_read;
+       enum spi_nor_protocol   read_proto;
+       enum spi_nor_protocol   write_proto;
+       enum spi_nor_protocol   reg_proto;
        bool                    sst_write_second;
        u32                     flags;
        u8                      cmd_buf[SPI_NOR_MAX_CMD_SIZE];
@@ -220,10 +301,71 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
 }
 
 /**
+ * struct spi_nor_hwcaps - Structure for describing the hardware capabilies
+ * supported by the SPI controller (bus master).
+ * @mask:              the bitmask listing all the supported hw capabilies
+ */
+struct spi_nor_hwcaps {
+       u32     mask;
+};
+
+/*
+ *(Fast) Read capabilities.
+ * MUST be ordered by priority: the higher bit position, the higher priority.
+ * As a matter of performances, it is relevant to use Octo SPI protocols first,
+ * then Quad SPI protocols before Dual SPI protocols, Fast Read and lastly
+ * (Slow) Read.
+ */
+#define SNOR_HWCAPS_READ_MASK          GENMASK(14, 0)
+#define SNOR_HWCAPS_READ               BIT(0)
+#define SNOR_HWCAPS_READ_FAST          BIT(1)
+#define SNOR_HWCAPS_READ_1_1_1_DTR     BIT(2)
+
+#define SNOR_HWCAPS_READ_DUAL          GENMASK(6, 3)
+#define SNOR_HWCAPS_READ_1_1_2         BIT(3)
+#define SNOR_HWCAPS_READ_1_2_2         BIT(4)
+#define SNOR_HWCAPS_READ_2_2_2         BIT(5)
+#define SNOR_HWCAPS_READ_1_2_2_DTR     BIT(6)
+
+#define SNOR_HWCAPS_READ_QUAD          GENMASK(10, 7)
+#define SNOR_HWCAPS_READ_1_1_4         BIT(7)
+#define SNOR_HWCAPS_READ_1_4_4         BIT(8)
+#define SNOR_HWCAPS_READ_4_4_4         BIT(9)
+#define SNOR_HWCAPS_READ_1_4_4_DTR     BIT(10)
+
+#define SNOR_HWCPAS_READ_OCTO          GENMASK(14, 11)
+#define SNOR_HWCAPS_READ_1_1_8         BIT(11)
+#define SNOR_HWCAPS_READ_1_8_8         BIT(12)
+#define SNOR_HWCAPS_READ_8_8_8         BIT(13)
+#define SNOR_HWCAPS_READ_1_8_8_DTR     BIT(14)
+
+/*
+ * Page Program capabilities.
+ * MUST be ordered by priority: the higher bit position, the higher priority.
+ * Like (Fast) Read capabilities, Octo/Quad SPI protocols are preferred to the
+ * legacy SPI 1-1-1 protocol.
+ * Note that Dual Page Programs are not supported because there is no existing
+ * JEDEC/SFDP standard to define them. Also at this moment no SPI flash memory
+ * implements such commands.
+ */
+#define SNOR_HWCAPS_PP_MASK    GENMASK(22, 16)
+#define SNOR_HWCAPS_PP         BIT(16)
+
+#define SNOR_HWCAPS_PP_QUAD    GENMASK(19, 17)
+#define SNOR_HWCAPS_PP_1_1_4   BIT(17)
+#define SNOR_HWCAPS_PP_1_4_4   BIT(18)
+#define SNOR_HWCAPS_PP_4_4_4   BIT(19)
+
+#define SNOR_HWCAPS_PP_OCTO    GENMASK(22, 20)
+#define SNOR_HWCAPS_PP_1_1_8   BIT(20)
+#define SNOR_HWCAPS_PP_1_8_8   BIT(21)
+#define SNOR_HWCAPS_PP_8_8_8   BIT(22)
+
+/**
  * spi_nor_scan() - scan the SPI NOR
  * @nor:       the spi_nor structure
  * @name:      the chip type name
- * @mode:      the read mode supported by the driver
+ * @hwcaps:    the hardware capabilities supported by the controller driver
  *
  * The drivers can use this fuction to scan the SPI NOR.
  * In the scanning, it will try to get all the necessary information to
@@ -233,6 +375,7 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
  *
  * Return: 0 for success, others for failure.
  */
-int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode);
+int spi_nor_scan(struct spi_nor *nor, const char *name,
+                const struct spi_nor_hwcaps *hwcaps);
 
 #endif
index abcfa46..b5c15b3 100644 (file)
@@ -190,8 +190,16 @@ struct proto_ops {
                                       struct pipe_inode_info *pipe, size_t len, unsigned int flags);
        int             (*set_peek_off)(struct sock *sk, int val);
        int             (*peek_len)(struct socket *sock);
+
+       /* The following functions are called internally by kernel with
+        * sock lock already held.
+        */
        int             (*read_sock)(struct sock *sk, read_descriptor_t *desc,
                                     sk_read_actor_t recv_actor);
+       int             (*sendpage_locked)(struct sock *sk, struct page *page,
+                                          int offset, size_t size, int flags);
+       int             (*sendmsg_locked)(struct sock *sk, struct msghdr *msg,
+                                         size_t size);
 };
 
 #define DECLARE_SOCKADDR(type, dst, src)       \
@@ -274,9 +282,13 @@ do {                                                                       \
 
 #define net_get_random_once(buf, nbytes)                       \
        get_random_once((buf), (nbytes))
+#define net_get_random_once_wait(buf, nbytes)                  \
+       get_random_once_wait((buf), (nbytes))
 
 int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
                   size_t num, size_t len);
+int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg,
+                         struct kvec *vec, size_t num, size_t len);
 int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
                   size_t num, size_t len, int flags);
 
@@ -295,6 +307,8 @@ int kernel_setsockopt(struct socket *sock, int level, int optname, char *optval,
                      unsigned int optlen);
 int kernel_sendpage(struct socket *sock, struct page *page, int offset,
                    size_t size, int flags);
+int kernel_sendpage_locked(struct sock *sk, struct page *page, int offset,
+                          size_t size, int flags);
 int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
 int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how);
 
index ebd2736..dc8b489 100644 (file)
@@ -75,6 +75,7 @@ enum {
        NETIF_F_HW_TC_BIT,              /* Offload TC infrastructure */
        NETIF_F_HW_ESP_BIT,             /* Hardware ESP transformation offload */
        NETIF_F_HW_ESP_TX_CSUM_BIT,     /* ESP with TX checksum offload */
+       NETIF_F_RX_UDP_TUNNEL_PORT_BIT, /* Offload of RX port for UDP tunnels */
 
        /*
         * Add your fresh new feature above and remember to update
@@ -138,6 +139,7 @@ enum {
 #define NETIF_F_HW_TC          __NETIF_F(HW_TC)
 #define NETIF_F_HW_ESP         __NETIF_F(HW_ESP)
 #define NETIF_F_HW_ESP_TX_CSUM __NETIF_F(HW_ESP_TX_CSUM)
+#define        NETIF_F_RX_UDP_TUNNEL_PORT  __NETIF_F(RX_UDP_TUNNEL_PORT)
 
 #define for_each_netdev_feature(mask_addr, bit)        \
        for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT)
index 614642e..3a3cdc1 100644 (file)
@@ -2317,6 +2317,7 @@ struct netdev_lag_lower_state_info {
 #define NETDEV_PRECHANGEUPPER  0x001A
 #define NETDEV_CHANGELOWERSTATE        0x001B
 #define NETDEV_UDP_TUNNEL_PUSH_INFO    0x001C
+#define NETDEV_UDP_TUNNEL_DROP_INFO    0x001D
 #define NETDEV_CHANGE_TX_QUEUE_LEN     0x001E
 
 int register_netdevice_notifier(struct notifier_block *nb);
index a4b97be..22f0810 100644 (file)
@@ -61,8 +61,6 @@ typedef unsigned int nf_hookfn(void *priv,
                               struct sk_buff *skb,
                               const struct nf_hook_state *state);
 struct nf_hook_ops {
-       struct list_head        list;
-
        /* User fills in from here down. */
        nf_hookfn               *hook;
        struct net_device       *dev;
@@ -160,13 +158,6 @@ int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg,
 void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg,
                             unsigned int n);
 
-int nf_register_hook(struct nf_hook_ops *reg);
-void nf_unregister_hook(struct nf_hook_ops *reg);
-int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n);
-void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n);
-int _nf_register_hooks(struct nf_hook_ops *reg, unsigned int n);
-void _nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n);
-
 /* Functions to register get/setsockopt ranges (non-inclusive).  You
    need to check permissions yourself! */
 int nf_register_sockopt(struct nf_sockopt_ops *reg);
index 1b1ca04..47239c3 100644 (file)
@@ -479,6 +479,7 @@ enum {
        NFSPROC4_CLNT_ACCESS,
        NFSPROC4_CLNT_GETATTR,
        NFSPROC4_CLNT_LOOKUP,
+       NFSPROC4_CLNT_LOOKUPP,
        NFSPROC4_CLNT_LOOKUP_ROOT,
        NFSPROC4_CLNT_REMOVE,
        NFSPROC4_CLNT_RENAME,
index bb0eb2c..5cc91d6 100644 (file)
@@ -51,7 +51,7 @@ struct nfs_access_entry {
        struct list_head        lru;
        unsigned long           jiffies;
        struct rpc_cred *       cred;
-       int                     mask;
+       __u32                   mask;
        struct rcu_head         rcu_head;
 };
 
@@ -332,6 +332,7 @@ extern void nfs_zap_caches(struct inode *);
 extern void nfs_invalidate_atime(struct inode *);
 extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
                                struct nfs_fattr *, struct nfs4_label *);
+struct inode *nfs_ilookup(struct super_block *sb, struct nfs_fattr *, struct nfs_fh *);
 extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
index e418a10..74c4466 100644 (file)
@@ -42,6 +42,7 @@ struct nfs_client {
 #define NFS_CS_MIGRATION       2               /* - transparent state migr */
 #define NFS_CS_INFINITE_SLOTS  3               /* - don't limit TCP slots */
 #define NFS_CS_NO_RETRANS_TIMEOUT      4       /* - Disable retransmit timeouts */
+#define NFS_CS_TSM_POSSIBLE    5               /* - Maybe state migration */
        struct sockaddr_storage cl_addr;        /* server identifier */
        size_t                  cl_addrlen;
        char *                  cl_hostname;    /* hostname of server */
@@ -210,6 +211,7 @@ struct nfs_server {
        unsigned long           mig_status;
 #define NFS_MIG_IN_TRANSITION          (1)
 #define NFS_MIG_FAILED                 (2)
+#define NFS_MIG_TSM_POSSIBLE           (3)
 
        void (*destroy)(struct nfs_server *);
 
index 247cc3d..d67b67a 100644 (file)
@@ -33,6 +33,8 @@ enum {
        PG_UPTODATE,            /* page group sync bit in read path */
        PG_WB_END,              /* page group sync bit in write path */
        PG_REMOVE,              /* page group sync bit in write path */
+       PG_CONTENDED1,          /* Is someone waiting for a lock? */
+       PG_CONTENDED2,          /* Is someone waiting for a lock? */
 };
 
 struct nfs_inode;
@@ -93,8 +95,8 @@ struct nfs_pageio_descriptor {
        const struct rpc_call_ops *pg_rpc_callops;
        const struct nfs_pgio_completion_ops *pg_completion_ops;
        struct pnfs_layout_segment *pg_lseg;
+       struct nfs_io_completion *pg_io_completion;
        struct nfs_direct_req   *pg_dreq;
-       void                    *pg_layout_private;
        unsigned int            pg_bsize;       /* default bsize for mirrors */
 
        u32                     pg_mirror_count;
index b28c834..ca3bcc4 100644 (file)
@@ -878,7 +878,7 @@ struct nfs3_readdirargs {
        struct nfs_fh *         fh;
        __u64                   cookie;
        __be32                  verf[2];
-       int                     plus;
+       bool                    plus;
        unsigned int            count;
        struct page **          pages;
 };
@@ -909,7 +909,7 @@ struct nfs3_linkres {
 struct nfs3_readdirres {
        struct nfs_fattr *      dir_attr;
        __be32 *                verf;
-       int                     plus;
+       bool                    plus;
 };
 
 struct nfs3_getaclres {
@@ -1012,7 +1012,6 @@ struct nfs4_link_res {
        struct nfs_fattr *              dir_attr;
 };
 
-
 struct nfs4_lookup_arg {
        struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           dir_fh;
@@ -1028,6 +1027,20 @@ struct nfs4_lookup_res {
        struct nfs4_label               *label;
 };
 
+struct nfs4_lookupp_arg {
+       struct nfs4_sequence_args       seq_args;
+       const struct nfs_fh             *fh;
+       const u32                       *bitmask;
+};
+
+struct nfs4_lookupp_res {
+       struct nfs4_sequence_res        seq_res;
+       const struct nfs_server         *server;
+       struct nfs_fattr                *fattr;
+       struct nfs_fh                   *fh;
+       struct nfs4_label               *label;
+};
+
 struct nfs4_lookup_root_arg {
        struct nfs4_sequence_args       seq_args;
        const u32 *                     bitmask;
@@ -1053,7 +1066,7 @@ struct nfs4_readdir_arg {
        struct page **                  pages;  /* zero-copy data */
        unsigned int                    pgbase; /* zero-copy data */
        const u32 *                     bitmask;
-       int                             plus;
+       bool                            plus;
 };
 
 struct nfs4_readdir_res {
@@ -1422,6 +1435,7 @@ enum {
        NFS_IOHDR_STAT,
 };
 
+struct nfs_io_completion;
 struct nfs_pgio_header {
        struct inode            *inode;
        struct rpc_cred         *cred;
@@ -1435,8 +1449,8 @@ struct nfs_pgio_header {
        void (*release) (struct nfs_pgio_header *hdr);
        const struct nfs_pgio_completion_ops *completion_ops;
        const struct nfs_rw_ops *rw_ops;
+       struct nfs_io_completion *io_completion;
        struct nfs_direct_req   *dreq;
-       void                    *layout_private;
        spinlock_t              lock;
        /* fields protected by lock */
        int                     pnfs_error;
@@ -1533,6 +1547,7 @@ struct nfs_renamedata {
        struct nfs_fattr        new_fattr;
        void (*complete)(struct rpc_task *, struct nfs_renamedata *);
        long timeout;
+       bool cancelled;
 };
 
 struct nfs_access_entry;
@@ -1567,6 +1582,8 @@ struct nfs_rpc_ops {
        int     (*lookup)  (struct inode *, const struct qstr *,
                            struct nfs_fh *, struct nfs_fattr *,
                            struct nfs4_label *);
+       int     (*lookupp) (struct inode *, struct nfs_fh *,
+                           struct nfs_fattr *, struct nfs4_label *);
        int     (*access)  (struct inode *, struct nfs_access_entry *);
        int     (*readlink)(struct inode *, struct page *, unsigned int,
                            unsigned int);
@@ -1585,7 +1602,7 @@ struct nfs_rpc_ops {
        int     (*mkdir)   (struct inode *, struct dentry *, struct iattr *);
        int     (*rmdir)   (struct inode *, const struct qstr *);
        int     (*readdir) (struct dentry *, struct rpc_cred *,
-                           u64, struct page **, unsigned int, int);
+                           u64, struct page **, unsigned int, bool);
        int     (*mknod)   (struct inode *, struct dentry *, struct iattr *,
                            dev_t);
        int     (*statfs)  (struct nfs_server *, struct nfs_fh *,
@@ -1595,7 +1612,7 @@ struct nfs_rpc_ops {
        int     (*pathconf) (struct nfs_server *, struct nfs_fh *,
                             struct nfs_pathconf *);
        int     (*set_capabilities)(struct nfs_server *, struct nfs_fh *);
-       int     (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int);
+       int     (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, bool);
        int     (*pgio_rpc_prepare)(struct rpc_task *,
                                    struct nfs_pgio_header *);
        void    (*read_setup)(struct nfs_pgio_header *, struct rpc_message *);
index aa3cd08..8aa01fd 100644 (file)
@@ -6,18 +6,26 @@
 
 #include <linux/sched.h>
 #include <asm/irq.h>
+#if defined(CONFIG_HAVE_NMI_WATCHDOG)
+#include <asm/nmi.h>
+#endif
 
 #ifdef CONFIG_LOCKUP_DETECTOR
+void lockup_detector_init(void);
+#else
+static inline void lockup_detector_init(void)
+{
+}
+#endif
+
+#ifdef CONFIG_SOFTLOCKUP_DETECTOR
 extern void touch_softlockup_watchdog_sched(void);
 extern void touch_softlockup_watchdog(void);
 extern void touch_softlockup_watchdog_sync(void);
 extern void touch_all_softlockup_watchdogs(void);
-extern int proc_dowatchdog_thresh(struct ctl_table *table, int write,
-                                 void __user *buffer,
-                                 size_t *lenp, loff_t *ppos);
 extern unsigned int  softlockup_panic;
-extern unsigned int  hardlockup_panic;
-void lockup_detector_init(void);
+extern int soft_watchdog_enabled;
+extern atomic_t watchdog_park_in_progress;
 #else
 static inline void touch_softlockup_watchdog_sched(void)
 {
@@ -31,9 +39,6 @@ static inline void touch_softlockup_watchdog_sync(void)
 static inline void touch_all_softlockup_watchdogs(void)
 {
 }
-static inline void lockup_detector_init(void)
-{
-}
 #endif
 
 #ifdef CONFIG_DETECT_HUNG_TASK
@@ -61,6 +66,21 @@ static inline void reset_hung_task_detector(void)
 #define NMI_WATCHDOG_ENABLED      (1 << NMI_WATCHDOG_ENABLED_BIT)
 #define SOFT_WATCHDOG_ENABLED     (1 << SOFT_WATCHDOG_ENABLED_BIT)
 
+#if defined(CONFIG_HARDLOCKUP_DETECTOR)
+extern void hardlockup_detector_disable(void);
+extern unsigned int hardlockup_panic;
+#else
+static inline void hardlockup_detector_disable(void) {}
+#endif
+
+#if defined(CONFIG_HARDLOCKUP_DETECTOR_PERF)
+extern void arch_touch_nmi_watchdog(void);
+#else
+#if !defined(CONFIG_HAVE_NMI_WATCHDOG)
+static inline void arch_touch_nmi_watchdog(void) {}
+#endif
+#endif
+
 /**
  * touch_nmi_watchdog - restart NMI watchdog timeout.
  * 
@@ -68,21 +88,11 @@ static inline void reset_hung_task_detector(void)
  * may be used to reset the timeout - for code which intentionally
  * disables interrupts for a long time. This call is stateless.
  */
-#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
-#include <asm/nmi.h>
-extern void touch_nmi_watchdog(void);
-#else
 static inline void touch_nmi_watchdog(void)
 {
+       arch_touch_nmi_watchdog();
        touch_softlockup_watchdog();
 }
-#endif
-
-#if defined(CONFIG_HARDLOCKUP_DETECTOR)
-extern void hardlockup_detector_disable(void);
-#else
-static inline void hardlockup_detector_disable(void) {}
-#endif
 
 /*
  * Create trigger_all_cpu_backtrace() out of the arch-provided
@@ -139,15 +149,18 @@ static inline bool trigger_single_cpu_backtrace(int cpu)
 }
 #endif
 
-#ifdef CONFIG_LOCKUP_DETECTOR
+#ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF
 u64 hw_nmi_get_sample_period(int watchdog_thresh);
+#endif
+
+#ifdef CONFIG_LOCKUP_DETECTOR
 extern int nmi_watchdog_enabled;
-extern int soft_watchdog_enabled;
 extern int watchdog_user_enabled;
 extern int watchdog_thresh;
 extern unsigned long watchdog_enabled;
+extern struct cpumask watchdog_cpumask;
 extern unsigned long *watchdog_cpumask_bits;
-extern atomic_t watchdog_park_in_progress;
+extern int __read_mostly watchdog_suspended;
 #ifdef CONFIG_SMP
 extern int sysctl_softlockup_all_cpu_backtrace;
 extern int sysctl_hardlockup_all_cpu_backtrace;
index de87cea..609e232 100644 (file)
@@ -5,6 +5,7 @@
  *   GPL LICENSE SUMMARY
  *
  *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of version 2 of the GNU General Public License as
@@ -18,6 +19,7 @@
  *   BSD LICENSE
  *
  *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
  *   modification, are permitted provided that the following conditions
@@ -106,6 +108,7 @@ static inline char *ntb_topo_string(enum ntb_topo topo)
  * @NTB_SPEED_GEN1:    Link is trained to gen1 speed.
  * @NTB_SPEED_GEN2:    Link is trained to gen2 speed.
  * @NTB_SPEED_GEN3:    Link is trained to gen3 speed.
+ * @NTB_SPEED_GEN4:    Link is trained to gen4 speed.
  */
 enum ntb_speed {
        NTB_SPEED_AUTO = -1,
@@ -113,6 +116,7 @@ enum ntb_speed {
        NTB_SPEED_GEN1 = 1,
        NTB_SPEED_GEN2 = 2,
        NTB_SPEED_GEN3 = 3,
+       NTB_SPEED_GEN4 = 4
 };
 
 /**
@@ -140,6 +144,20 @@ enum ntb_width {
 };
 
 /**
+ * enum ntb_default_port - NTB default port number
+ * @NTB_PORT_PRI_USD:  Default port of the NTB_TOPO_PRI/NTB_TOPO_B2B_USD
+ *                     topologies
+ * @NTB_PORT_SEC_DSD:  Default port of the NTB_TOPO_SEC/NTB_TOPO_B2B_DSD
+ *                     topologies
+ */
+enum ntb_default_port {
+       NTB_PORT_PRI_USD,
+       NTB_PORT_SEC_DSD
+};
+#define NTB_DEF_PEER_CNT       (1)
+#define NTB_DEF_PEER_IDX       (0)
+
+/**
  * struct ntb_client_ops - ntb client operations
  * @probe:             Notify client of a new device.
  * @remove:            Notify client to remove a device.
@@ -162,10 +180,12 @@ static inline int ntb_client_ops_is_valid(const struct ntb_client_ops *ops)
  * struct ntb_ctx_ops - ntb driver context operations
  * @link_event:                See ntb_link_event().
  * @db_event:          See ntb_db_event().
+ * @msg_event:         See ntb_msg_event().
  */
 struct ntb_ctx_ops {
        void (*link_event)(void *ctx);
        void (*db_event)(void *ctx, int db_vector);
+       void (*msg_event)(void *ctx);
 };
 
 static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
@@ -174,18 +194,27 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
        return
                /* ops->link_event              && */
                /* ops->db_event                && */
+               /* ops->msg_event               && */
                1;
 }
 
 /**
  * struct ntb_ctx_ops - ntb device operations
- * @mw_count:          See ntb_mw_count().
- * @mw_get_range:      See ntb_mw_get_range().
- * @mw_set_trans:      See ntb_mw_set_trans().
- * @mw_clear_trans:    See ntb_mw_clear_trans().
+ * @port_number:       See ntb_port_number().
+ * @peer_port_count:   See ntb_peer_port_count().
+ * @peer_port_number:  See ntb_peer_port_number().
+ * @peer_port_idx:     See ntb_peer_port_idx().
  * @link_is_up:                See ntb_link_is_up().
  * @link_enable:       See ntb_link_enable().
  * @link_disable:      See ntb_link_disable().
+ * @mw_count:          See ntb_mw_count().
+ * @mw_get_align:      See ntb_mw_get_align().
+ * @mw_set_trans:      See ntb_mw_set_trans().
+ * @mw_clear_trans:    See ntb_mw_clear_trans().
+ * @peer_mw_count:     See ntb_peer_mw_count().
+ * @peer_mw_get_addr:  See ntb_peer_mw_get_addr().
+ * @peer_mw_set_trans: See ntb_peer_mw_set_trans().
+ * @peer_mw_clear_trans:See ntb_peer_mw_clear_trans().
  * @db_is_unsafe:      See ntb_db_is_unsafe().
  * @db_valid_mask:     See ntb_db_valid_mask().
  * @db_vector_count:   See ntb_db_vector_count().
@@ -210,22 +239,43 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
  * @peer_spad_addr:    See ntb_peer_spad_addr().
  * @peer_spad_read:    See ntb_peer_spad_read().
  * @peer_spad_write:   See ntb_peer_spad_write().
+ * @msg_count:         See ntb_msg_count().
+ * @msg_inbits:                See ntb_msg_inbits().
+ * @msg_outbits:       See ntb_msg_outbits().
+ * @msg_read_sts:      See ntb_msg_read_sts().
+ * @msg_clear_sts:     See ntb_msg_clear_sts().
+ * @msg_set_mask:      See ntb_msg_set_mask().
+ * @msg_clear_mask:    See ntb_msg_clear_mask().
+ * @msg_read:          See ntb_msg_read().
+ * @msg_write:         See ntb_msg_write().
  */
 struct ntb_dev_ops {
-       int (*mw_count)(struct ntb_dev *ntb);
-       int (*mw_get_range)(struct ntb_dev *ntb, int idx,
-                           phys_addr_t *base, resource_size_t *size,
-                       resource_size_t *align, resource_size_t *align_size);
-       int (*mw_set_trans)(struct ntb_dev *ntb, int idx,
-                           dma_addr_t addr, resource_size_t size);
-       int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);
+       int (*port_number)(struct ntb_dev *ntb);
+       int (*peer_port_count)(struct ntb_dev *ntb);
+       int (*peer_port_number)(struct ntb_dev *ntb, int pidx);
+       int (*peer_port_idx)(struct ntb_dev *ntb, int port);
 
-       int (*link_is_up)(struct ntb_dev *ntb,
+       u64 (*link_is_up)(struct ntb_dev *ntb,
                          enum ntb_speed *speed, enum ntb_width *width);
        int (*link_enable)(struct ntb_dev *ntb,
                           enum ntb_speed max_speed, enum ntb_width max_width);
        int (*link_disable)(struct ntb_dev *ntb);
 
+       int (*mw_count)(struct ntb_dev *ntb, int pidx);
+       int (*mw_get_align)(struct ntb_dev *ntb, int pidx, int widx,
+                           resource_size_t *addr_align,
+                           resource_size_t *size_align,
+                           resource_size_t *size_max);
+       int (*mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
+                           dma_addr_t addr, resource_size_t size);
+       int (*mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
+       int (*peer_mw_count)(struct ntb_dev *ntb);
+       int (*peer_mw_get_addr)(struct ntb_dev *ntb, int widx,
+                               phys_addr_t *base, resource_size_t *size);
+       int (*peer_mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
+                                u64 addr, resource_size_t size);
+       int (*peer_mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
+
        int (*db_is_unsafe)(struct ntb_dev *ntb);
        u64 (*db_valid_mask)(struct ntb_dev *ntb);
        int (*db_vector_count)(struct ntb_dev *ntb);
@@ -252,32 +302,55 @@ struct ntb_dev_ops {
        int (*spad_is_unsafe)(struct ntb_dev *ntb);
        int (*spad_count)(struct ntb_dev *ntb);
 
-       u32 (*spad_read)(struct ntb_dev *ntb, int idx);
-       int (*spad_write)(struct ntb_dev *ntb, int idx, u32 val);
+       u32 (*spad_read)(struct ntb_dev *ntb, int sidx);
+       int (*spad_write)(struct ntb_dev *ntb, int sidx, u32 val);
 
-       int (*peer_spad_addr)(struct ntb_dev *ntb, int idx,
+       int (*peer_spad_addr)(struct ntb_dev *ntb, int pidx, int sidx,
                              phys_addr_t *spad_addr);
-       u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx);
-       int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val);
+       u32 (*peer_spad_read)(struct ntb_dev *ntb, int pidx, int sidx);
+       int (*peer_spad_write)(struct ntb_dev *ntb, int pidx, int sidx,
+                              u32 val);
+
+       int (*msg_count)(struct ntb_dev *ntb);
+       u64 (*msg_inbits)(struct ntb_dev *ntb);
+       u64 (*msg_outbits)(struct ntb_dev *ntb);
+       u64 (*msg_read_sts)(struct ntb_dev *ntb);
+       int (*msg_clear_sts)(struct ntb_dev *ntb, u64 sts_bits);
+       int (*msg_set_mask)(struct ntb_dev *ntb, u64 mask_bits);
+       int (*msg_clear_mask)(struct ntb_dev *ntb, u64 mask_bits);
+       int (*msg_read)(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg);
+       int (*msg_write)(struct ntb_dev *ntb, int midx, int pidx, u32 msg);
 };
 
 static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
 {
        /* commented callbacks are not required: */
        return
-               ops->mw_count                           &&
-               ops->mw_get_range                       &&
-               ops->mw_set_trans                       &&
-               /* ops->mw_clear_trans                  && */
+               /* Port operations are required for multiport devices */
+               !ops->peer_port_count == !ops->port_number      &&
+               !ops->peer_port_number == !ops->port_number     &&
+               !ops->peer_port_idx == !ops->port_number        &&
+
+               /* Link operations are required */
                ops->link_is_up                         &&
                ops->link_enable                        &&
                ops->link_disable                       &&
+
+               /* One or both MW interfaces should be developed */
+               ops->mw_count                           &&
+               ops->mw_get_align                       &&
+               (ops->mw_set_trans                      ||
+                ops->peer_mw_set_trans)                &&
+               /* ops->mw_clear_trans                  && */
+               ops->peer_mw_count                      &&
+               ops->peer_mw_get_addr                   &&
+               /* ops->peer_mw_clear_trans             && */
+
+               /* Doorbell operations are mostly required */
                /* ops->db_is_unsafe                    && */
                ops->db_valid_mask                      &&
-
                /* both set, or both unset */
-               (!ops->db_vector_count == !ops->db_vector_mask) &&
-
+               (!ops->db_vector_count == !ops->db_vector_mask) &&
                ops->db_read                            &&
                /* ops->db_set                          && */
                ops->db_clear                           &&
@@ -291,13 +364,24 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
                /* ops->peer_db_read_mask               && */
                /* ops->peer_db_set_mask                && */
                /* ops->peer_db_clear_mask              && */
-               /* ops->spad_is_unsafe                  && */
-               ops->spad_count                         &&
-               ops->spad_read                          &&
-               ops->spad_write                         &&
-               /* ops->peer_spad_addr                  && */
-               /* ops->peer_spad_read                  && */
-               ops->peer_spad_write                    &&
+
+               /* Scrachpads interface is optional */
+               /* !ops->spad_is_unsafe == !ops->spad_count     && */
+               !ops->spad_read == !ops->spad_count             &&
+               !ops->spad_write == !ops->spad_count            &&
+               /* !ops->peer_spad_addr == !ops->spad_count     && */
+               /* !ops->peer_spad_read == !ops->spad_count     && */
+               !ops->peer_spad_write == !ops->spad_count       &&
+
+               /* Messaging interface is optional */
+               !ops->msg_inbits == !ops->msg_count             &&
+               !ops->msg_outbits == !ops->msg_count            &&
+               !ops->msg_read_sts == !ops->msg_count           &&
+               !ops->msg_clear_sts == !ops->msg_count          &&
+               /* !ops->msg_set_mask == !ops->msg_count        && */
+               /* !ops->msg_clear_mask == !ops->msg_count      && */
+               !ops->msg_read == !ops->msg_count               &&
+               !ops->msg_write == !ops->msg_count              &&
                1;
 }
 
@@ -310,13 +394,12 @@ struct ntb_client {
        struct device_driver            drv;
        const struct ntb_client_ops     ops;
 };
-
 #define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)
 
 /**
  * struct ntb_device - ntb device
  * @dev:               Linux device object.
- * @pdev:              Pci device entry of the ntb.
+ * @pdev:              PCI device entry of the ntb.
  * @topo:              Detected topology of the ntb.
  * @ops:               See &ntb_dev_ops.
  * @ctx:               See &ntb_ctx_ops.
@@ -337,7 +420,6 @@ struct ntb_dev {
        /* block unregister until device is fully released */
        struct completion               released;
 };
-
 #define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)
 
 /**
@@ -434,86 +516,152 @@ void ntb_link_event(struct ntb_dev *ntb);
  * multiple interrupt vectors for doorbells, the vector number indicates which
  * vector received the interrupt.  The vector number is relative to the first
  * vector used for doorbells, starting at zero, and must be less than
- ** ntb_db_vector_count().  The driver may call ntb_db_read() to check which
+ * ntb_db_vector_count().  The driver may call ntb_db_read() to check which
  * doorbell bits need service, and ntb_db_vector_mask() to determine which of
  * those bits are associated with the vector number.
  */
 void ntb_db_event(struct ntb_dev *ntb, int vector);
 
 /**
- * ntb_mw_count() - get the number of memory windows
+ * ntb_msg_event() - notify driver context of a message event
  * @ntb:       NTB device context.
  *
- * Hardware and topology may support a different number of memory windows.
+ * Notify the driver context of a message event.  If hardware supports
+ * message registers, this event indicates, that a new message arrived in
+ * some incoming message register or last sent message couldn't be delivered.
+ * The events can be masked/unmasked by the methods ntb_msg_set_mask() and
+ * ntb_msg_clear_mask().
+ */
+void ntb_msg_event(struct ntb_dev *ntb);
+
+/**
+ * ntb_default_port_number() - get the default local port number
+ * @ntb:       NTB device context.
  *
- * Return: the number of memory windows.
+ * If hardware driver doesn't specify port_number() callback method, the NTB
+ * is considered with just two ports. So this method returns default local
+ * port number in compliance with topology.
+ *
+ * NOTE Don't call this method directly. The ntb_port_number() function should
+ * be used instead.
+ *
+ * Return: the default local port number
+ */
+int ntb_default_port_number(struct ntb_dev *ntb);
+
+/**
+ * ntb_default_port_count() - get the default number of peer device ports
+ * @ntb:       NTB device context.
+ *
+ * By default hardware driver supports just one peer device.
+ *
+ * NOTE Don't call this method directly. The ntb_peer_port_count() function
+ * should be used instead.
+ *
+ * Return: the default number of peer ports
+ */
+int ntb_default_peer_port_count(struct ntb_dev *ntb);
+
+/**
+ * ntb_default_peer_port_number() - get the default peer port by given index
+ * @ntb:       NTB device context.
+ * @idx:       Peer port index (should not differ from zero).
+ *
+ * By default hardware driver supports just one peer device, so this method
+ * shall return the corresponding value from enum ntb_default_port.
+ *
+ * NOTE Don't call this method directly. The ntb_peer_port_number() function
+ * should be used instead.
+ *
+ * Return: the peer device port or negative value indicating an error
+ */
+int ntb_default_peer_port_number(struct ntb_dev *ntb, int pidx);
+
+/**
+ * ntb_default_peer_port_idx() - get the default peer device port index by
+ *                              given port number
+ * @ntb:       NTB device context.
+ * @port:      Peer port number (should be one of enum ntb_default_port).
+ *
+ * By default hardware driver supports just one peer device, so while
+ * specified port-argument indicates peer port from enum ntb_default_port,
+ * the return value shall be zero.
+ *
+ * NOTE Don't call this method directly. The ntb_peer_port_idx() function
+ * should be used instead.
+ *
+ * Return: the peer port index or negative value indicating an error
+ */
+int ntb_default_peer_port_idx(struct ntb_dev *ntb, int port);
+
+/**
+ * ntb_port_number() - get the local port number
+ * @ntb:       NTB device context.
+ *
+ * Hardware must support at least simple two-ports ntb connection
+ *
+ * Return: the local port number
  */
-static inline int ntb_mw_count(struct ntb_dev *ntb)
+static inline int ntb_port_number(struct ntb_dev *ntb)
 {
-       return ntb->ops->mw_count(ntb);
+       if (!ntb->ops->port_number)
+               return ntb_default_port_number(ntb);
+
+       return ntb->ops->port_number(ntb);
 }
 
 /**
- * ntb_mw_get_range() - get the range of a memory window
+ * ntb_peer_port_count() - get the number of peer device ports
  * @ntb:       NTB device context.
- * @idx:       Memory window number.
- * @base:      OUT - the base address for mapping the memory window
- * @size:      OUT - the size for mapping the memory window
- * @align:     OUT - the base alignment for translating the memory window
- * @align_size:        OUT - the size alignment for translating the memory window
  *
- * Get the range of a memory window.  NULL may be given for any output
- * parameter if the value is not needed.  The base and size may be used for
- * mapping the memory window, to access the peer memory.  The alignment and
- * size may be used for translating the memory window, for the peer to access
- * memory on the local system.
+ * Hardware may support an access to memory of several remote domains
+ * over multi-port NTB devices. This method returns the number of peers,
+ * local device can have shared memory with.
  *
- * Return: Zero on success, otherwise an error number.
+ * Return: the number of peer ports
  */
-static inline int ntb_mw_get_range(struct ntb_dev *ntb, int idx,
-                                  phys_addr_t *base, resource_size_t *size,
-               resource_size_t *align, resource_size_t *align_size)
+static inline int ntb_peer_port_count(struct ntb_dev *ntb)
 {
-       return ntb->ops->mw_get_range(ntb, idx, base, size,
-                       align, align_size);
+       if (!ntb->ops->peer_port_count)
+               return ntb_default_peer_port_count(ntb);
+
+       return ntb->ops->peer_port_count(ntb);
 }
 
 /**
- * ntb_mw_set_trans() - set the translation of a memory window
+ * ntb_peer_port_number() - get the peer port by given index
  * @ntb:       NTB device context.
- * @idx:       Memory window number.
- * @addr:      The dma address local memory to expose to the peer.
- * @size:      The size of the local memory to expose to the peer.
+ * @pidx:      Peer port index.
  *
- * Set the translation of a memory window.  The peer may access local memory
- * through the window starting at the address, up to the size.  The address
- * must be aligned to the alignment specified by ntb_mw_get_range().  The size
- * must be aligned to the size alignment specified by ntb_mw_get_range().
+ * Peer ports are continuously enumerated by NTB API logic, so this method
+ * lets to retrieve port real number by its index.
  *
- * Return: Zero on success, otherwise an error number.
+ * Return: the peer device port or negative value indicating an error
  */
-static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
-                                  dma_addr_t addr, resource_size_t size)
+static inline int ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
 {
-       return ntb->ops->mw_set_trans(ntb, idx, addr, size);
+       if (!ntb->ops->peer_port_number)
+               return ntb_default_peer_port_number(ntb, pidx);
+
+       return ntb->ops->peer_port_number(ntb, pidx);
 }
 
 /**
- * ntb_mw_clear_trans() - clear the translation of a memory window
+ * ntb_peer_port_idx() - get the peer device port index by given port number
  * @ntb:       NTB device context.
- * @idx:       Memory window number.
+ * @port:      Peer port number.
  *
- * Clear the translation of a memory window.  The peer may no longer access
- * local memory through the window.
+ * Inverse operation of ntb_peer_port_number(), so one can get port index
+ * by specified port number.
  *
- * Return: Zero on success, otherwise an error number.
+ * Return: the peer port index or negative value indicating an error
  */
-static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
+static inline int ntb_peer_port_idx(struct ntb_dev *ntb, int port)
 {
-       if (!ntb->ops->mw_clear_trans)
-               return ntb->ops->mw_set_trans(ntb, idx, 0, 0);
+       if (!ntb->ops->peer_port_idx)
+               return ntb_default_peer_port_idx(ntb, port);
 
-       return ntb->ops->mw_clear_trans(ntb, idx);
+       return ntb->ops->peer_port_idx(ntb, port);
 }
 
 /**
@@ -526,25 +674,26 @@ static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
  * state once after every link event.  It is safe to query the link state in
  * the context of the link event callback.
  *
- * Return: One if the link is up, zero if the link is down, otherwise a
- *             negative value indicating the error number.
+ * Return: bitfield of indexed ports link state: bit is set/cleared if the
+ *         link is up/down respectively.
  */
-static inline int ntb_link_is_up(struct ntb_dev *ntb,
+static inline u64 ntb_link_is_up(struct ntb_dev *ntb,
                                 enum ntb_speed *speed, enum ntb_width *width)
 {
        return ntb->ops->link_is_up(ntb, speed, width);
 }
 
 /**
- * ntb_link_enable() - enable the link on the secondary side of the ntb
+ * ntb_link_enable() - enable the local port ntb connection
  * @ntb:       NTB device context.
  * @max_speed: The maximum link speed expressed as PCIe generation number.
  * @max_width: The maximum link width expressed as the number of PCIe lanes.
  *
- * Enable the link on the secondary side of the ntb.  This can only be done
- * from the primary side of the ntb in primary or b2b topology.  The ntb device
- * should train the link to its maximum speed and width, or the requested speed
- * and width, whichever is smaller, if supported.
+ * Enable the NTB/PCIe link on the local or remote (for bridge-to-bridge
+ * topology) side of the bridge. If it's supported the ntb device should train
+ * the link to its maximum speed and width, or the requested speed and width,
+ * whichever is smaller. Some hardware doesn't support PCIe link training, so
+ * the last two arguments will be ignored then.
  *
  * Return: Zero on success, otherwise an error number.
  */
@@ -556,14 +705,14 @@ static inline int ntb_link_enable(struct ntb_dev *ntb,
 }
 
 /**
- * ntb_link_disable() - disable the link on the secondary side of the ntb
+ * ntb_link_disable() - disable the local port ntb connection
  * @ntb:       NTB device context.
  *
- * Disable the link on the secondary side of the ntb.  This can only be
- * done from the primary side of the ntb in primary or b2b topology.  The ntb
- * device should disable the link.  Returning from this call must indicate that
- * a barrier has passed, though with no more writes may pass in either
- * direction across the link, except if this call returns an error number.
+ * Disable the link on the local or remote (for b2b topology) of the ntb.
+ * The ntb device should disable the link.  Returning from this call must
+ * indicate that a barrier has passed, though with no more writes may pass in
+ * either direction across the link, except if this call returns an error
+ * number.
  *
  * Return: Zero on success, otherwise an error number.
  */
@@ -573,6 +722,183 @@ static inline int ntb_link_disable(struct ntb_dev *ntb)
 }
 
 /**
+ * ntb_mw_count() - get the number of inbound memory windows, which could
+ *                  be created for a specified peer device
+ * @ntb:       NTB device context.
+ * @pidx:      Port index of peer device.
+ *
+ * Hardware and topology may support a different number of memory windows.
+ * Moreover different peer devices can support different number of memory
+ * windows. Simply speaking this method returns the number of possible inbound
+ * memory windows to share with specified peer device.
+ *
+ * Return: the number of memory windows.
+ */
+static inline int ntb_mw_count(struct ntb_dev *ntb, int pidx)
+{
+       return ntb->ops->mw_count(ntb, pidx);
+}
+
+/**
+ * ntb_mw_get_align() - get the restriction parameters of inbound memory window
+ * @ntb:       NTB device context.
+ * @pidx:      Port index of peer device.
+ * @widx:      Memory window index.
+ * @addr_align:        OUT - the base alignment for translating the memory window
+ * @size_align:        OUT - the size alignment for translating the memory window
+ * @size_max:  OUT - the maximum size of the memory window
+ *
+ * Get the alignments of an inbound memory window with specified index.
+ * NULL may be given for any output parameter if the value is not needed.
+ * The alignment and size parameters may be used for allocation of proper
+ * shared memory.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int widx,
+                                  resource_size_t *addr_align,
+                                  resource_size_t *size_align,
+                                  resource_size_t *size_max)
+{
+       return ntb->ops->mw_get_align(ntb, pidx, widx, addr_align, size_align,
+                                     size_max);
+}
+
+/**
+ * ntb_mw_set_trans() - set the translation of an inbound memory window
+ * @ntb:       NTB device context.
+ * @pidx:      Port index of peer device.
+ * @widx:      Memory window index.
+ * @addr:      The dma address of local memory to expose to the peer.
+ * @size:      The size of the local memory to expose to the peer.
+ *
+ * Set the translation of a memory window.  The peer may access local memory
+ * through the window starting at the address, up to the size.  The address
+ * and size must be aligned in compliance with restrictions of
+ * ntb_mw_get_align(). The region size should not exceed the size_max parameter
+ * of that method.
+ *
+ * This method may not be implemented due to the hardware specific memory
+ * windows interface.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
+                                  dma_addr_t addr, resource_size_t size)
+{
+       if (!ntb->ops->mw_set_trans)
+               return 0;
+
+       return ntb->ops->mw_set_trans(ntb, pidx, widx, addr, size);
+}
+
+/**
+ * ntb_mw_clear_trans() - clear the translation address of an inbound memory
+ *                        window
+ * @ntb:       NTB device context.
+ * @pidx:      Port index of peer device.
+ * @widx:      Memory window index.
+ *
+ * Clear the translation of an inbound memory window.  The peer may no longer
+ * access local memory through the window.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int pidx, int widx)
+{
+       if (!ntb->ops->mw_clear_trans)
+               return ntb_mw_set_trans(ntb, pidx, widx, 0, 0);
+
+       return ntb->ops->mw_clear_trans(ntb, pidx, widx);
+}
+
+/**
+ * ntb_peer_mw_count() - get the number of outbound memory windows, which could
+ *                       be mapped to access a shared memory
+ * @ntb:       NTB device context.
+ *
+ * Hardware and topology may support a different number of memory windows.
+ * This method returns the number of outbound memory windows supported by
+ * local device.
+ *
+ * Return: the number of memory windows.
+ */
+static inline int ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+       return ntb->ops->peer_mw_count(ntb);
+}
+
+/**
+ * ntb_peer_mw_get_addr() - get map address of an outbound memory window
+ * @ntb:       NTB device context.
+ * @widx:      Memory window index (within ntb_peer_mw_count() return value).
+ * @base:      OUT - the base address of mapping region.
+ * @size:      OUT - the size of mapping region.
+ *
+ * Get base and size of memory region to map.  NULL may be given for any output
+ * parameter if the value is not needed.  The base and size may be used for
+ * mapping the memory window, to access the peer memory.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_peer_mw_get_addr(struct ntb_dev *ntb, int widx,
+                                     phys_addr_t *base, resource_size_t *size)
+{
+       return ntb->ops->peer_mw_get_addr(ntb, widx, base, size);
+}
+
+/**
+ * ntb_peer_mw_set_trans() - set a translation address of a memory window
+ *                           retrieved from a peer device
+ * @ntb:       NTB device context.
+ * @pidx:      Port index of peer device the translation address received from.
+ * @widx:      Memory window index.
+ * @addr:      The dma address of the shared memory to access.
+ * @size:      The size of the shared memory to access.
+ *
+ * Set the translation of an outbound memory window.  The local device may
+ * access shared memory allocated by a peer device sent the address.
+ *
+ * This method may not be implemented due to the hardware specific memory
+ * windows interface, so a translation address can be only set on the side,
+ * where shared memory (inbound memory windows) is allocated.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
+                                       u64 addr, resource_size_t size)
+{
+       if (!ntb->ops->peer_mw_set_trans)
+               return 0;
+
+       return ntb->ops->peer_mw_set_trans(ntb, pidx, widx, addr, size);
+}
+
+/**
+ * ntb_peer_mw_clear_trans() - clear the translation address of an outbound
+ *                             memory window
+ * @ntb:       NTB device context.
+ * @pidx:      Port index of peer device.
+ * @widx:      Memory window index.
+ *
+ * Clear the translation of a outbound memory window.  The local device may no
+ * longer access a shared memory through the window.
+ *
+ * This method may not be implemented due to the hardware specific memory
+ * windows interface.
+ *
+ * Return: Zero on success, otherwise an error number.
+ */
+static inline int ntb_peer_mw_clear_trans(struct ntb_dev *ntb, int pidx,
+                                         int widx)
+{
+       if (!ntb->ops->peer_mw_clear_trans)
+               return ntb_peer_mw_set_trans(ntb, pidx, widx, 0, 0);
+
+       return ntb->ops->peer_mw_clear_trans(ntb, pidx, widx);
+}
+
+/**
  * ntb_db_is_unsafe() - check if it is safe to use hardware doorbell
  * @ntb:       NTB device context.
  *
@@ -900,47 +1226,58 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
  * @ntb:       NTB device context.
  *
  * Hardware and topology may support a different number of scratchpads.
+ * Although it must be the same for all ports per NTB device.
  *
  * Return: the number of scratchpads.
  */
 static inline int ntb_spad_count(struct ntb_dev *ntb)
 {
+       if (!ntb->ops->spad_count)
+               return 0;
+
        return ntb->ops->spad_count(ntb);
 }
 
 /**
  * ntb_spad_read() - read the local scratchpad register
  * @ntb:       NTB device context.
- * @idx:       Scratchpad index.
+ * @sidx:      Scratchpad index.
  *
  * Read the local scratchpad register, and return the value.
  *
  * Return: The value of the local scratchpad register.
  */
-static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
+static inline u32 ntb_spad_read(struct ntb_dev *ntb, int sidx)
 {
-       return ntb->ops->spad_read(ntb, idx);
+       if (!ntb->ops->spad_read)
+               return ~(u32)0;
+
+       return ntb->ops->spad_read(ntb, sidx);
 }
 
 /**
  * ntb_spad_write() - write the local scratchpad register
  * @ntb:       NTB device context.
- * @idx:       Scratchpad index.
+ * @sidx:      Scratchpad index.
  * @val:       Scratchpad value.
  *
  * Write the value to the local scratchpad register.
  *
  * Return: Zero on success, otherwise an error number.
  */
-static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
+static inline int ntb_spad_write(struct ntb_dev *ntb, int sidx, u32 val)
 {
-       return ntb->ops->spad_write(ntb, idx, val);
+       if (!ntb->ops->spad_write)
+               return -EINVAL;
+
+       return ntb->ops->spad_write(ntb, sidx, val);
 }
 
 /**
  * ntb_peer_spad_addr() - address of the peer scratchpad register
  * @ntb:       NTB device context.
- * @idx:       Scratchpad index.
+ * @pidx:      Port index of peer device.
+ * @sidx:      Scratchpad index.
  * @spad_addr: OUT - The address of the peer scratchpad register.
  *
  * Return the address of the peer doorbell register.  This may be used, for
@@ -948,45 +1285,213 @@ static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
  *
  * Return: Zero on success, otherwise an error number.
  */
-static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
+static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
                                     phys_addr_t *spad_addr)
 {
        if (!ntb->ops->peer_spad_addr)
                return -EINVAL;
 
-       return ntb->ops->peer_spad_addr(ntb, idx, spad_addr);
+       return ntb->ops->peer_spad_addr(ntb, pidx, sidx, spad_addr);
 }
 
 /**
  * ntb_peer_spad_read() - read the peer scratchpad register
  * @ntb:       NTB device context.
- * @idx:       Scratchpad index.
+ * @pidx:      Port index of peer device.
+ * @sidx:      Scratchpad index.
  *
  * Read the peer scratchpad register, and return the value.
  *
  * Return: The value of the local scratchpad register.
  */
-static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
+static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
 {
        if (!ntb->ops->peer_spad_read)
-               return 0;
+               return ~(u32)0;
 
-       return ntb->ops->peer_spad_read(ntb, idx);
+       return ntb->ops->peer_spad_read(ntb, pidx, sidx);
 }
 
 /**
  * ntb_peer_spad_write() - write the peer scratchpad register
  * @ntb:       NTB device context.
- * @idx:       Scratchpad index.
+ * @pidx:      Port index of peer device.
+ * @sidx:      Scratchpad index.
  * @val:       Scratchpad value.
  *
  * Write the value to the peer scratchpad register.
  *
  * Return: Zero on success, otherwise an error number.
  */
-static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val)
+static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx,
+                                     u32 val)
+{
+       if (!ntb->ops->peer_spad_write)
+               return -EINVAL;
+
+       return ntb->ops->peer_spad_write(ntb, pidx, sidx, val);
+}
+
+/**
+ * ntb_msg_count() - get the number of message registers
+ * @ntb:       NTB device context.
+ *
+ * Hardware may support a different number of message registers.
+ *
+ * Return: the number of message registers.
+ */
+static inline int ntb_msg_count(struct ntb_dev *ntb)
+{
+       if (!ntb->ops->msg_count)
+               return 0;
+
+       return ntb->ops->msg_count(ntb);
+}
+
+/**
+ * ntb_msg_inbits() - get a bitfield of inbound message registers status
+ * @ntb:       NTB device context.
+ *
+ * The method returns the bitfield of status and mask registers, which related
+ * to inbound message registers.
+ *
+ * Return: bitfield of inbound message registers.
+ */
+static inline u64 ntb_msg_inbits(struct ntb_dev *ntb)
 {
-       return ntb->ops->peer_spad_write(ntb, idx, val);
+       if (!ntb->ops->msg_inbits)
+               return 0;
+
+       return ntb->ops->msg_inbits(ntb);
+}
+
+/**
+ * ntb_msg_outbits() - get a bitfield of outbound message registers status
+ * @ntb:       NTB device context.
+ *
+ * The method returns the bitfield of status and mask registers, which related
+ * to outbound message registers.
+ *
+ * Return: bitfield of outbound message registers.
+ */
+static inline u64 ntb_msg_outbits(struct ntb_dev *ntb)
+{
+       if (!ntb->ops->msg_outbits)
+               return 0;
+
+       return ntb->ops->msg_outbits(ntb);
+}
+
+/**
+ * ntb_msg_read_sts() - read the message registers status
+ * @ntb:       NTB device context.
+ *
+ * Read the status of message register. Inbound and outbound message registers
+ * related bits can be filtered by masks retrieved from ntb_msg_inbits() and
+ * ntb_msg_outbits().
+ *
+ * Return: status bits of message registers
+ */
+static inline u64 ntb_msg_read_sts(struct ntb_dev *ntb)
+{
+       if (!ntb->ops->msg_read_sts)
+               return 0;
+
+       return ntb->ops->msg_read_sts(ntb);
+}
+
+/**
+ * ntb_msg_clear_sts() - clear status bits of message registers
+ * @ntb:       NTB device context.
+ * @sts_bits:  Status bits to clear.
+ *
+ * Clear bits in the status register.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_clear_sts(struct ntb_dev *ntb, u64 sts_bits)
+{
+       if (!ntb->ops->msg_clear_sts)
+               return -EINVAL;
+
+       return ntb->ops->msg_clear_sts(ntb, sts_bits);
+}
+
+/**
+ * ntb_msg_set_mask() - set mask of message register status bits
+ * @ntb:       NTB device context.
+ * @mask_bits: Mask bits.
+ *
+ * Mask the message registers status bits from raising the message event.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_set_mask(struct ntb_dev *ntb, u64 mask_bits)
+{
+       if (!ntb->ops->msg_set_mask)
+               return -EINVAL;
+
+       return ntb->ops->msg_set_mask(ntb, mask_bits);
+}
+
+/**
+ * ntb_msg_clear_mask() - clear message registers mask
+ * @ntb:       NTB device context.
+ * @mask_bits: Mask bits to clear.
+ *
+ * Clear bits in the message events mask register.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits)
+{
+       if (!ntb->ops->msg_clear_mask)
+               return -EINVAL;
+
+       return ntb->ops->msg_clear_mask(ntb, mask_bits);
+}
+
+/**
+ * ntb_msg_read() - read message register with specified index
+ * @ntb:       NTB device context.
+ * @midx:      Message register index
+ * @pidx:      OUT - Port index of peer device a message retrieved from
+ * @msg:       OUT - Data
+ *
+ * Read data from the specified message register. Source port index of a
+ * message is retrieved as well.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx,
+                              u32 *msg)
+{
+       if (!ntb->ops->msg_read)
+               return -EINVAL;
+
+       return ntb->ops->msg_read(ntb, midx, pidx, msg);
+}
+
+/**
+ * ntb_msg_write() - write data to the specified message register
+ * @ntb:       NTB device context.
+ * @midx:      Message register index
+ * @pidx:      Port index of peer device a message being sent to
+ * @msg:       Data to send
+ *
+ * Send data to a specified peer device using the defined message register.
+ * Message event can be raised if the midx registers isn't empty while
+ * calling this method and the corresponding interrupt isn't masked.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+static inline int ntb_msg_write(struct ntb_dev *ntb, int midx, int pidx,
+                               u32 msg)
+{
+       if (!ntb->ops->msg_write)
+               return -EINVAL;
+
+       return ntb->ops->msg_write(ntb, midx, pidx, msg);
 }
 
 #endif
index 21c37e3..36cca93 100644 (file)
@@ -334,5 +334,24 @@ struct fcnvme_ls_disconnect_acc {
 #define NVME_FC_LS_TIMEOUT_SEC         2               /* 2 seconds */
 #define NVME_FC_TGTOP_TIMEOUT_SEC      2               /* 2 seconds */
 
+/*
+ * TRADDR string must be of form "nn-<16hexdigits>:pn-<16hexdigits>"
+ * the string is allowed to be specified with or without a "0x" prefix
+ * infront of the <16hexdigits>.  Without is considered the "min" string
+ * and with is considered the "max" string. The hexdigits may be upper
+ * or lower case.
+ */
+#define NVME_FC_TRADDR_NNLEN           3       /* "?n-" */
+#define NVME_FC_TRADDR_OXNNLEN         5       /* "?n-0x" */
+#define NVME_FC_TRADDR_HEXNAMELEN      16
+#define NVME_FC_TRADDR_MINLENGTH       \
+               (2 * (NVME_FC_TRADDR_NNLEN + NVME_FC_TRADDR_HEXNAMELEN) + 1)
+#define NVME_FC_TRADDR_MAXLENGTH       \
+               (2 * (NVME_FC_TRADDR_OXNNLEN + NVME_FC_TRADDR_HEXNAMELEN) + 1)
+#define NVME_FC_TRADDR_MIN_PN_OFFSET   \
+               (NVME_FC_TRADDR_NNLEN + NVME_FC_TRADDR_HEXNAMELEN + 1)
+#define NVME_FC_TRADDR_MAX_PN_OFFSET   \
+               (NVME_FC_TRADDR_OXNNLEN + NVME_FC_TRADDR_HEXNAMELEN + 1)
+
 
 #endif /* _NVME_FC_H */
index 6b8ee9e..25d8225 100644 (file)
@@ -963,14 +963,14 @@ struct nvme_dbbuf {
 };
 
 struct streams_directive_params {
-       __u16   msl;
-       __u16   nssa;
-       __u16   nsso;
+       __le16  msl;
+       __le16  nssa;
+       __le16  nsso;
        __u8    rsvd[10];
-       __u32   sws;
-       __u16   sgs;
-       __u16   nsa;
-       __u16   nso;
+       __le32  sws;
+       __le16  sgs;
+       __le16  nsa;
+       __le16  nso;
        __u8    rsvd2[6];
 };
 
@@ -1006,7 +1006,7 @@ static inline bool nvme_is_write(struct nvme_command *cmd)
         * Why can't we simply have a Fabrics In and Fabrics out command?
         */
        if (unlikely(cmd->common.opcode == nvme_fabrics_command))
-               return cmd->fabrics.opcode & 1;
+               return cmd->fabrics.fctype & 1;
        return cmd->common.opcode & 1;
 }
 
index cd93416..497706f 100644 (file)
@@ -12,6 +12,9 @@
 #ifndef _LINUX_NVMEM_PROVIDER_H
 #define _LINUX_NVMEM_PROVIDER_H
 
+#include <linux/err.h>
+#include <linux/errno.h>
+
 struct nvmem_device;
 struct nvmem_cell_info;
 typedef int (*nvmem_reg_read_t)(void *priv, unsigned int offset,
index 285f12c..9c98aaa 100644 (file)
@@ -53,5 +53,7 @@ void __do_once_done(bool *done, struct static_key *once_key,
 
 #define get_random_once(buf, nbytes)                                        \
        DO_ONCE(get_random_bytes, (buf), (nbytes))
+#define get_random_once_wait(buf, nbytes)                                    \
+       DO_ONCE(get_random_bytes_wait, (buf), (nbytes))                      \
 
 #endif /* _LINUX_ONCE_H */
index d137218..cde895c 100644 (file)
@@ -7,7 +7,7 @@ struct vfsmount;
 struct path {
        struct vfsmount *mnt;
        struct dentry *dentry;
-};
+} __randomize_layout;
 
 extern void path_get(const struct path *);
 extern void path_put(const struct path *);
index 1360dd6..af0f44e 100644 (file)
  *     interrupt and passed the address of the low level handler,
  *     and can be used to implement any platform specific handling
  *     before or after calling it.
+ *
+ * @irq_flags: if non-zero, these flags will be passed to request_irq
+ *             when requesting interrupts for this PMU device.
  */
 struct arm_pmu_platdata {
        irqreturn_t (*handle_irq)(int irq, void *dev,
                                  irq_handler_t pmu_handler);
+       unsigned long irq_flags;
 };
 
 #ifdef CONFIG_ARM_PMU
index 2a9567b..0bb5b21 100644 (file)
@@ -830,7 +830,7 @@ static inline int phy_read_status(struct phy_device *phydev)
        dev_err(&_phydev->mdio.dev, format, ##args)
 
 #define phydev_dbg(_phydev, format, args...)   \
-       dev_dbg(&_phydev->mdio.dev, format, ##args);
+       dev_dbg(&_phydev->mdio.dev, format, ##args)
 
 static inline const char *phydev_name(const struct phy_device *phydev)
 {
index c2a989d..b09136f 100644 (file)
@@ -52,7 +52,7 @@ struct pid_namespace {
        int hide_pid;
        int reboot;     /* group exit code if this pidns was rebooted */
        struct ns_common ns;
-};
+} __randomize_layout;
 
 extern struct pid_namespace init_pid_ns;
 
index 8e981be..0ff1e0d 100644 (file)
@@ -55,9 +55,6 @@ struct omap_hsmmc_platform_data {
        u32 caps;       /* Used for the MMC driver on 2430 and later */
        u32 pm_caps;    /* PM capabilities of the mmc */
 
-       /* use the internal clock */
-       unsigned internal_clock:1;
-
        /* nonremovable e.g. eMMC */
        unsigned nonremovable:1;
 
@@ -73,13 +70,6 @@ struct omap_hsmmc_platform_data {
        int gpio_cd;                    /* gpio (card detect) */
        int gpio_cod;                   /* gpio (cover detect) */
        int gpio_wp;                    /* gpio (write protect) */
-
-       int (*set_power)(struct device *dev, int power_on, int vdd);
-       void (*remux)(struct device *dev, int power_on);
-       /* Call back before enabling / disabling regulators */
-       void (*before_set_reg)(struct device *dev, int power_on, int vdd);
-       /* Call back after enabling / disabling regulators */
-       void (*after_set_reg)(struct device *dev, int power_on, int vdd);
        /* if we have special card, init it using this callback */
        void (*init_card)(struct mmc_card *card);
 
diff --git a/include/linux/platform_data/mdio-bcm-unimac.h b/include/linux/platform_data/mdio-bcm-unimac.h
new file mode 100644 (file)
index 0000000..8a5f9f0
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __MDIO_BCM_UNIMAC_PDATA_H
+#define __MDIO_BCM_UNIMAC_PDATA_H
+
+struct unimac_mdio_pdata {
+       u32 phy_mask;
+       int (*wait_func)(void *data);
+       void *wait_func_data;
+       const char *bus_name;
+};
+
+#define UNIMAC_MDIO_DRV_NAME   "unimac-mdio"
+
+#endif /* __MDIO_BCM_UNIMAC_PDATA_H */
index 7fa1fbe..cc7554a 100644 (file)
@@ -31,7 +31,7 @@ struct s3c2410_hcd_info {
        void            (*report_oc)(struct s3c2410_hcd_info *, int ports);
 };
 
-static void inline s3c2410_usb_report_oc(struct s3c2410_hcd_info *info, int ports)
+static inline void s3c2410_usb_report_oc(struct s3c2410_hcd_info *info, int ports)
 {
        if (info->report_oc != NULL) {
                (info->report_oc)(info, ports);
index 58ab28d..06844b5 100644 (file)
@@ -21,7 +21,7 @@ struct proc_ns_operations {
        int (*install)(struct nsproxy *nsproxy, struct ns_common *ns);
        struct user_namespace *(*owner)(struct ns_common *ns);
        struct ns_common *(*get_parent)(struct ns_common *ns);
-};
+} __randomize_layout;
 
 extern const struct proc_ns_operations netns_operations;
 extern const struct proc_ns_operations utsns_operations;
index 0eef0a2..d60de4a 100644 (file)
@@ -323,6 +323,7 @@ struct qed_eth_ops {
 
        int (*configure_arfs_searcher)(struct qed_dev *cdev,
                                       bool en_searcher);
+       int (*get_coalesce)(struct qed_dev *cdev, u16 *coal, void *handle);
 };
 
 const struct qed_eth_ops *qed_get_eth_ops(void);
index ef39c7f..cc646ca 100644 (file)
@@ -161,6 +161,18 @@ enum qed_nvm_images {
        QED_NVM_IMAGE_FCOE_CFG,
 };
 
+struct qed_link_eee_params {
+       u32 tx_lpi_timer;
+#define QED_EEE_1G_ADV         BIT(0)
+#define QED_EEE_10G_ADV                BIT(1)
+
+       /* Capabilities are represented using QED_EEE_*_ADV values */
+       u8 adv_caps;
+       u8 lp_adv_caps;
+       bool enable;
+       bool tx_lpi_enable;
+};
+
 enum qed_led_mode {
        QED_LED_MODE_OFF,
        QED_LED_MODE_ON,
@@ -172,8 +184,9 @@ enum qed_led_mode {
 
 #define DIRECT_REG_RD(reg_addr) readl((void __iomem *)(reg_addr))
 
-#define QED_COALESCE_MAX 0xFF
+#define QED_COALESCE_MAX 0x1FF
 #define QED_DEFAULT_RX_USECS 12
+#define QED_DEFAULT_TX_USECS 48
 
 /* forward */
 struct qed_dev;
@@ -408,6 +421,7 @@ struct qed_link_params {
 #define QED_LINK_OVERRIDE_SPEED_FORCED_SPEED    BIT(2)
 #define QED_LINK_OVERRIDE_PAUSE_CONFIG          BIT(3)
 #define QED_LINK_OVERRIDE_LOOPBACK_MODE         BIT(4)
+#define QED_LINK_OVERRIDE_EEE_CONFIG            BIT(5)
        u32     override_flags;
        bool    autoneg;
        u32     adv_speeds;
@@ -422,6 +436,7 @@ struct qed_link_params {
 #define QED_LINK_LOOPBACK_EXT                   BIT(3)
 #define QED_LINK_LOOPBACK_MAC                   BIT(4)
        u32     loopback_mode;
+       struct qed_link_eee_params eee;
 };
 
 struct qed_link_output {
@@ -437,6 +452,12 @@ struct qed_link_output {
        u8      port;                   /* In PORT defs */
        bool    autoneg;
        u32     pause_config;
+
+       /* EEE - capability & param */
+       bool eee_supported;
+       bool eee_active;
+       u8 sup_caps;
+       struct qed_link_eee_params eee;
 };
 
 struct qed_probe_params {
@@ -654,16 +675,6 @@ struct qed_common_ops {
                             enum qed_nvm_images type, u8 *buf, u16 len);
 
 /**
- * @brief get_coalesce - Get coalesce parameters in usec
- *
- * @param cdev
- * @param rx_coal - Rx coalesce value in usec
- * @param tx_coal - Tx coalesce value in usec
- *
- */
-       void (*get_coalesce)(struct qed_dev *cdev, u16 *rx_coal, u16 *tx_coal);
-
-/**
  * @brief set_coalesce - Configure Rx coalesce value in usec
  *
  * @param cdev
@@ -674,8 +685,8 @@ struct qed_common_ops {
  *
  * @return 0 on success, error otherwise.
  */
-       int (*set_coalesce)(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal,
-                           u16 qid, u16 sb_id);
+       int (*set_coalesce)(struct qed_dev *cdev,
+                           u16 rx_coal, u16 tx_coal, void *handle);
 
 /**
  * @brief set_led - Configure LED mode
index ed5c383..eafea6a 100644 (file)
@@ -34,6 +34,7 @@ extern void add_input_randomness(unsigned int type, unsigned int code,
 extern void add_interrupt_randomness(int irq, int irq_flags) __latent_entropy;
 
 extern void get_random_bytes(void *buf, int nbytes);
+extern int wait_for_random_bytes(void);
 extern int add_random_ready_callback(struct random_ready_callback *rdy);
 extern void del_random_ready_callback(struct random_ready_callback *rdy);
 extern void get_random_bytes_arch(void *buf, int nbytes);
@@ -57,6 +58,52 @@ static inline unsigned long get_random_long(void)
 #endif
 }
 
+/*
+ * On 64-bit architectures, protect against non-terminated C string overflows
+ * by zeroing out the first byte of the canary; this leaves 56 bits of entropy.
+ */
+#ifdef CONFIG_64BIT
+# ifdef __LITTLE_ENDIAN
+#  define CANARY_MASK 0xffffffffffffff00UL
+# else /* big endian, 64 bits: */
+#  define CANARY_MASK 0x00ffffffffffffffUL
+# endif
+#else /* 32 bits: */
+# define CANARY_MASK 0xffffffffUL
+#endif
+
+static inline unsigned long get_random_canary(void)
+{
+       unsigned long val = get_random_long();
+
+       return val & CANARY_MASK;
+}
+
+/* Calls wait_for_random_bytes() and then calls get_random_bytes(buf, nbytes).
+ * Returns the result of the call to wait_for_random_bytes. */
+static inline int get_random_bytes_wait(void *buf, int nbytes)
+{
+       int ret = wait_for_random_bytes();
+       if (unlikely(ret))
+               return ret;
+       get_random_bytes(buf, nbytes);
+       return 0;
+}
+
+#define declare_get_random_var_wait(var) \
+       static inline int get_random_ ## var ## _wait(var *out) { \
+               int ret = wait_for_random_bytes(); \
+               if (unlikely(ret)) \
+                       return ret; \
+               *out = get_random_ ## var(); \
+               return 0; \
+       }
+declare_get_random_var_wait(u32)
+declare_get_random_var_wait(u64)
+declare_get_random_var_wait(int)
+declare_get_random_var_wait(long)
+#undef declare_get_random_var
+
 unsigned long randomize_page(unsigned long start, unsigned long range);
 
 u32 prandom_u32(void);
index b693ada..0a0f0d1 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/nvmem-provider.h>
 #include <uapi/linux/rtc.h>
 
 extern int rtc_month_days(unsigned int month, unsigned int year);
@@ -32,17 +33,11 @@ static inline time64_t rtc_tm_sub(struct rtc_time *lhs, struct rtc_time *rhs)
        return rtc_tm_to_time64(lhs) - rtc_tm_to_time64(rhs);
 }
 
-/**
- * Deprecated. Use rtc_time64_to_tm().
- */
 static inline void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
 {
        rtc_time64_to_tm(time, tm);
 }
 
-/**
- * Deprecated. Use rtc_tm_to_time64().
- */
 static inline int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
 {
        *time = rtc_tm_to_time64(tm);
@@ -116,7 +111,6 @@ struct rtc_device {
        struct module *owner;
 
        int id;
-       char name[RTC_DEVICE_NAME_SIZE];
 
        const struct rtc_class_ops *ops;
        struct mutex ops_lock;
@@ -143,6 +137,14 @@ struct rtc_device {
        /* Some hardware can't support UIE mode */
        int uie_unsupported;
 
+       bool registered;
+
+       struct nvmem_config *nvmem_config;
+       struct nvmem_device *nvmem;
+       /* Old ABI support */
+       bool nvram_old_abi;
+       struct bin_attribute *nvram;
+
 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
        struct work_struct uie_task;
        struct timer_list uie_timer;
@@ -164,6 +166,8 @@ extern struct rtc_device *devm_rtc_device_register(struct device *dev,
                                        const char *name,
                                        const struct rtc_class_ops *ops,
                                        struct module *owner);
+struct rtc_device *devm_rtc_allocate_device(struct device *dev);
+int __rtc_register_device(struct module *owner, struct rtc_device *rtc);
 extern void rtc_device_unregister(struct rtc_device *rtc);
 extern void devm_rtc_device_unregister(struct device *dev,
                                        struct rtc_device *rtc);
@@ -219,6 +223,9 @@ static inline bool is_leap_year(unsigned int year)
        return (!(year % 4) && (year % 100)) || !(year % 400);
 }
 
+#define rtc_register_device(device) \
+       __rtc_register_device(THIS_MODULE, device)
+
 #ifdef CONFIG_RTC_HCTOSYS_DEVICE
 extern int rtc_hctosys_ret;
 #else
index 20814b7..8337e2d 100644 (file)
@@ -426,7 +426,7 @@ struct sched_rt_entity {
        /* rq "owned" by this entity/group: */
        struct rt_rq                    *my_q;
 #endif
-};
+} __randomize_layout;
 
 struct sched_dl_entity {
        struct rb_node                  rb_node;
@@ -526,6 +526,13 @@ struct task_struct {
 #endif
        /* -1 unrunnable, 0 runnable, >0 stopped: */
        volatile long                   state;
+
+       /*
+        * This begins the randomizable portion of task_struct. Only
+        * scheduling-critical items should be added above here.
+        */
+       randomized_struct_fields_start
+
        void                            *stack;
        atomic_t                        usage;
        /* Per task flags (PF_*), defined further below: */
@@ -974,6 +981,7 @@ struct task_struct {
 
 #ifdef CONFIG_FAULT_INJECTION
        int                             make_it_fail;
+       unsigned int                    fail_nth;
 #endif
        /*
         * When (nr_dirtied >= nr_dirtied_pause), it's time to call
@@ -1078,6 +1086,13 @@ struct task_struct {
        /* Used by LSM modules for access restriction: */
        void                            *security;
 #endif
+
+       /*
+        * New fields for task_struct should be added above here, so that
+        * they are included in the randomized portion of task_struct.
+        */
+       randomized_struct_fields_end
+
        /* CPU-specific state of this task: */
        struct thread_struct            thread;
 
index c06d63b..2a0dd40 100644 (file)
@@ -222,7 +222,7 @@ struct signal_struct {
        struct mutex cred_guard_mutex;  /* guard against foreign influences on
                                         * credential calculations
                                         * (notably. ptrace) */
-};
+} __randomize_layout;
 
 /*
  * Bits in flags field of signal_struct.
index 913474d..ba00716 100644 (file)
@@ -336,19 +336,22 @@ struct sctp_hmac_algo_param {
  *   The INIT ACK chunk is used to acknowledge the initiation of an SCTP
  *   association.
  */
-typedef struct sctp_init_chunk sctp_initack_chunk_t;
+struct sctp_initack_chunk {
+       struct sctp_chunkhdr chunk_hdr;
+       struct sctp_inithdr init_hdr;
+};
 
 /* Section 3.3.3.1 State Cookie (7) */
-typedef struct sctp_cookie_param {
+struct sctp_cookie_param {
        struct sctp_paramhdr p;
        __u8 body[0];
-} sctp_cookie_param_t;
+};
 
 /* Section 3.3.3.1 Unrecognized Parameters (8) */
-typedef struct sctp_unrecognized_param {
+struct sctp_unrecognized_param {
        struct sctp_paramhdr param_hdr;
        struct sctp_paramhdr unrecognized;
-} sctp_unrecognized_param_t;
+};
 
 
 
@@ -360,30 +363,28 @@ typedef struct sctp_unrecognized_param {
  *  subsequences of DATA chunks as represented by their TSNs.
  */
 
-typedef struct sctp_gap_ack_block {
+struct sctp_gap_ack_block {
        __be16 start;
        __be16 end;
-} sctp_gap_ack_block_t;
-
-typedef __be32 sctp_dup_tsn_t;
+};
 
-typedef union {
-       sctp_gap_ack_block_t    gab;
-        sctp_dup_tsn_t         dup;
-} sctp_sack_variable_t;
+union sctp_sack_variable {
+       struct sctp_gap_ack_block gab;
+       __be32 dup;
+};
 
-typedef struct sctp_sackhdr {
+struct sctp_sackhdr {
        __be32 cum_tsn_ack;
        __be32 a_rwnd;
        __be16 num_gap_ack_blocks;
        __be16 num_dup_tsns;
-       sctp_sack_variable_t variable[0];
-} sctp_sackhdr_t;
+       union sctp_sack_variable variable[0];
+};
 
-typedef struct sctp_sack_chunk {
+struct sctp_sack_chunk {
        struct sctp_chunkhdr chunk_hdr;
-       sctp_sackhdr_t sack_hdr;
-} sctp_sack_chunk_t;
+       struct sctp_sackhdr sack_hdr;
+};
 
 
 /* RFC 2960.  Section 3.3.5 Heartbeat Request (HEARTBEAT) (4):
@@ -393,23 +394,23 @@ typedef struct sctp_sack_chunk {
  *  the present association.
  */
 
-typedef struct sctp_heartbeathdr {
+struct sctp_heartbeathdr {
        struct sctp_paramhdr info;
-} sctp_heartbeathdr_t;
+};
 
-typedef struct sctp_heartbeat_chunk {
+struct sctp_heartbeat_chunk {
        struct sctp_chunkhdr chunk_hdr;
-       sctp_heartbeathdr_t hb_hdr;
-} sctp_heartbeat_chunk_t;
+       struct sctp_heartbeathdr hb_hdr;
+};
 
 
 /* For the abort and shutdown ACK we must carry the init tag in the
  * common header. Just the common header is all that is needed with a
  * chunk descriptor.
  */
-typedef struct sctp_abort_chunk {
+struct sctp_abort_chunk {
        struct sctp_chunkhdr uh;
-} sctp_abort_chunk_t;
+};
 
 
 /* For the graceful shutdown we must carry the tag (in common header)
index 9edec92..de2deb8 100644 (file)
@@ -8,11 +8,29 @@
 
 struct task_struct;
 
+/* One semaphore structure for each semaphore in the system. */
+struct sem {
+       int     semval;         /* current value */
+       /*
+        * PID of the process that last modified the semaphore. For
+        * Linux, specifically these are:
+        *  - semop
+        *  - semctl, via SETVAL and SETALL.
+        *  - at task exit when performing undo adjustments (see exit_sem).
+        */
+       int     sempid;
+       spinlock_t      lock;   /* spinlock for fine-grained semtimedop */
+       struct list_head pending_alter; /* pending single-sop operations */
+                                       /* that alter the semaphore */
+       struct list_head pending_const; /* pending single-sop operations */
+                                       /* that do not alter the semaphore*/
+       time_t  sem_otime;      /* candidate for sem_otime */
+} ____cacheline_aligned_in_smp;
+
 /* One sem_array data structure for each set of semaphores in the system. */
 struct sem_array {
        struct kern_ipc_perm    sem_perm;       /* permissions .. see ipc.h */
-       time_t                  sem_ctime;      /* last change time */
-       struct sem              *sem_base;      /* ptr to first semaphore in array */
+       time_t                  sem_ctime;      /* create/last semctl() time */
        struct list_head        pending_alter;  /* pending operations */
                                                /* that alter the array */
        struct list_head        pending_const;  /* pending complex operations */
@@ -21,7 +39,9 @@ struct sem_array {
        int                     sem_nsems;      /* no. of semaphores in array */
        int                     complex_count;  /* pending complex operations */
        unsigned int            use_global_lock;/* >0: global lock required */
-};
+
+       struct sem              sems[];
+} __randomize_layout;
 
 #ifdef CONFIG_SYSVIPC
 
index 04e8818..0fb7061 100644 (file)
@@ -22,7 +22,7 @@ struct shmid_kernel /* private to the kernel */
        /* The task created the shm object.  NULL if the task is dead. */
        struct task_struct      *shm_creator;
        struct list_head        shm_clist;      /* list by creator */
-};
+} __randomize_layout;
 
 /* shm_mode upper byte flags */
 #define        SHM_DEST        01000   /* segment will be destroyed on last detach */
index 4093552..6f9f1b2 100644 (file)
@@ -345,6 +345,42 @@ static inline void skb_frag_size_sub(skb_frag_t *frag, int delta)
        frag->size -= delta;
 }
 
+static inline bool skb_frag_must_loop(struct page *p)
+{
+#if defined(CONFIG_HIGHMEM)
+       if (PageHighMem(p))
+               return true;
+#endif
+       return false;
+}
+
+/**
+ *     skb_frag_foreach_page - loop over pages in a fragment
+ *
+ *     @f:             skb frag to operate on
+ *     @f_off:         offset from start of f->page.p
+ *     @f_len:         length from f_off to loop over
+ *     @p:             (temp var) current page
+ *     @p_off:         (temp var) offset from start of current page,
+ *                                non-zero only on first page.
+ *     @p_len:         (temp var) length in current page,
+ *                                < PAGE_SIZE only on first and last page.
+ *     @copied:        (temp var) length so far, excluding current p_len.
+ *
+ *     A fragment can hold a compound page, in which case per-page
+ *     operations, notably kmap_atomic, must be called for each
+ *     regular page.
+ */
+#define skb_frag_foreach_page(f, f_off, f_len, p, p_off, p_len, copied)        \
+       for (p = skb_frag_page(f) + ((f_off) >> PAGE_SHIFT),            \
+            p_off = (f_off) & (PAGE_SIZE - 1),                         \
+            p_len = skb_frag_must_loop(p) ?                            \
+            min_t(u32, f_len, PAGE_SIZE - p_off) : f_len,              \
+            copied = 0;                                                \
+            copied < f_len;                                            \
+            copied += p_len, p++, p_off = 0,                           \
+            p_len = min_t(u32, f_len - copied, PAGE_SIZE))             \
+
 #define HAVE_HW_TIME_STAMP
 
 /**
@@ -3113,6 +3149,9 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
 int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
                    struct pipe_inode_info *pipe, unsigned int len,
                    unsigned int flags);
+int skb_send_sock_locked(struct sock *sk, struct sk_buff *skb, int offset,
+                        int len);
+int skb_send_sock(struct sock *sk, struct sk_buff *skb, int offset, int len);
 void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
 unsigned int skb_zerocopy_headlen(const struct sk_buff *from);
 int skb_zerocopy(struct sk_buff *to, struct sk_buff *from,
index 04a7f79..41473df 100644 (file)
@@ -471,7 +471,8 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
  *
  * %__GFP_NOWARN - If allocation fails, don't issue any warnings.
  *
- * %__GFP_REPEAT - If allocation fails initially, try once more before failing.
+ * %__GFP_RETRY_MAYFAIL - Try really hard to succeed the allocation but fail
+ *   eventually.
  *
  * There are other flags available as well, but these are not intended
  * for general use, and so are not documented here. For a full list of
index 7439d83..a467e61 100644 (file)
@@ -137,6 +137,7 @@ extern char *kstrdup(const char *s, gfp_t gfp) __malloc;
 extern const char *kstrdup_const(const char *s, gfp_t gfp);
 extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
 extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
+extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp);
 
 extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
 extern void argv_free(char **argv);
@@ -193,4 +194,205 @@ static inline const char *kbasename(const char *path)
        return tail ? tail + 1 : path;
 }
 
+#define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline))
+#define __RENAME(x) __asm__(#x)
+
+void fortify_panic(const char *name) __noreturn __cold;
+void __read_overflow(void) __compiletime_error("detected read beyond size of object passed as 1st parameter");
+void __read_overflow2(void) __compiletime_error("detected read beyond size of object passed as 2nd parameter");
+void __write_overflow(void) __compiletime_error("detected write beyond size of object passed as 1st parameter");
+
+#if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE)
+__FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size)
+{
+       size_t p_size = __builtin_object_size(p, 0);
+       if (__builtin_constant_p(size) && p_size < size)
+               __write_overflow();
+       if (p_size < size)
+               fortify_panic(__func__);
+       return __builtin_strncpy(p, q, size);
+}
+
+__FORTIFY_INLINE char *strcat(char *p, const char *q)
+{
+       size_t p_size = __builtin_object_size(p, 0);
+       if (p_size == (size_t)-1)
+               return __builtin_strcat(p, q);
+       if (strlcat(p, q, p_size) >= p_size)
+               fortify_panic(__func__);
+       return p;
+}
+
+__FORTIFY_INLINE __kernel_size_t strlen(const char *p)
+{
+       __kernel_size_t ret;
+       size_t p_size = __builtin_object_size(p, 0);
+       if (p_size == (size_t)-1)
+               return __builtin_strlen(p);
+       ret = strnlen(p, p_size);
+       if (p_size <= ret)
+               fortify_panic(__func__);
+       return ret;
+}
+
+extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen);
+__FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen)
+{
+       size_t p_size = __builtin_object_size(p, 0);
+       __kernel_size_t ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size);
+       if (p_size <= ret && maxlen != ret)
+               fortify_panic(__func__);
+       return ret;
+}
+
+/* defined after fortified strlen to reuse it */
+extern size_t __real_strlcpy(char *, const char *, size_t) __RENAME(strlcpy);
+__FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size)
+{
+       size_t ret;
+       size_t p_size = __builtin_object_size(p, 0);
+       size_t q_size = __builtin_object_size(q, 0);
+       if (p_size == (size_t)-1 && q_size == (size_t)-1)
+               return __real_strlcpy(p, q, size);
+       ret = strlen(q);
+       if (size) {
+               size_t len = (ret >= size) ? size - 1 : ret;
+               if (__builtin_constant_p(len) && len >= p_size)
+                       __write_overflow();
+               if (len >= p_size)
+                       fortify_panic(__func__);
+               __builtin_memcpy(p, q, len);
+               p[len] = '\0';
+       }
+       return ret;
+}
+
+/* defined after fortified strlen and strnlen to reuse them */
+__FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count)
+{
+       size_t p_len, copy_len;
+       size_t p_size = __builtin_object_size(p, 0);
+       size_t q_size = __builtin_object_size(q, 0);
+       if (p_size == (size_t)-1 && q_size == (size_t)-1)
+               return __builtin_strncat(p, q, count);
+       p_len = strlen(p);
+       copy_len = strnlen(q, count);
+       if (p_size < p_len + copy_len + 1)
+               fortify_panic(__func__);
+       __builtin_memcpy(p + p_len, q, copy_len);
+       p[p_len + copy_len] = '\0';
+       return p;
+}
+
+__FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size)
+{
+       size_t p_size = __builtin_object_size(p, 0);
+       if (__builtin_constant_p(size) && p_size < size)
+               __write_overflow();
+       if (p_size < size)
+               fortify_panic(__func__);
+       return __builtin_memset(p, c, size);
+}
+
+__FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size)
+{
+       size_t p_size = __builtin_object_size(p, 0);
+       size_t q_size = __builtin_object_size(q, 0);
+       if (__builtin_constant_p(size)) {
+               if (p_size < size)
+                       __write_overflow();
+               if (q_size < size)
+                       __read_overflow2();
+       }
+       if (p_size < size || q_size < size)
+               fortify_panic(__func__);
+       return __builtin_memcpy(p, q, size);
+}
+
+__FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size)
+{
+       size_t p_size = __builtin_object_size(p, 0);
+       size_t q_size = __builtin_object_size(q, 0);
+       if (__builtin_constant_p(size)) {
+               if (p_size < size)
+                       __write_overflow();
+               if (q_size < size)
+                       __read_overflow2();
+       }
+       if (p_size < size || q_size < size)
+               fortify_panic(__func__);
+       return __builtin_memmove(p, q, size);
+}
+
+extern void *__real_memscan(void *, int, __kernel_size_t) __RENAME(memscan);
+__FORTIFY_INLINE void *memscan(void *p, int c, __kernel_size_t size)
+{
+       size_t p_size = __builtin_object_size(p, 0);
+       if (__builtin_constant_p(size) && p_size < size)
+               __read_overflow();
+       if (p_size < size)
+               fortify_panic(__func__);
+       return __real_memscan(p, c, size);
+}
+
+__FORTIFY_INLINE int memcmp(const void *p, const void *q, __kernel_size_t size)
+{
+       size_t p_size = __builtin_object_size(p, 0);
+       size_t q_size = __builtin_object_size(q, 0);
+       if (__builtin_constant_p(size)) {
+               if (p_size < size)
+                       __read_overflow();
+               if (q_size < size)
+                       __read_overflow2();
+       }
+       if (p_size < size || q_size < size)
+               fortify_panic(__func__);
+       return __builtin_memcmp(p, q, size);
+}
+
+__FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size)
+{
+       size_t p_size = __builtin_object_size(p, 0);
+       if (__builtin_constant_p(size) && p_size < size)
+               __read_overflow();
+       if (p_size < size)
+               fortify_panic(__func__);
+       return __builtin_memchr(p, c, size);
+}
+
+void *__real_memchr_inv(const void *s, int c, size_t n) __RENAME(memchr_inv);
+__FORTIFY_INLINE void *memchr_inv(const void *p, int c, size_t size)
+{
+       size_t p_size = __builtin_object_size(p, 0);
+       if (__builtin_constant_p(size) && p_size < size)
+               __read_overflow();
+       if (p_size < size)
+               fortify_panic(__func__);
+       return __real_memchr_inv(p, c, size);
+}
+
+extern void *__real_kmemdup(const void *src, size_t len, gfp_t gfp) __RENAME(kmemdup);
+__FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp)
+{
+       size_t p_size = __builtin_object_size(p, 0);
+       if (__builtin_constant_p(size) && p_size < size)
+               __read_overflow();
+       if (p_size < size)
+               fortify_panic(__func__);
+       return __real_kmemdup(p, size, gfp);
+}
+
+/* defined after fortified strlen and memcpy to reuse them */
+__FORTIFY_INLINE char *strcpy(char *p, const char *q)
+{
+       size_t p_size = __builtin_object_size(p, 0);
+       size_t q_size = __builtin_object_size(q, 0);
+       if (p_size == (size_t)-1 && q_size == (size_t)-1)
+               return __builtin_strcpy(p, q);
+       memcpy(p, q, strlen(q) + 1);
+       return p;
+}
+
+#endif
+
 #endif /* _LINUX_STRING_H_ */
index 6095ecb..55ef67b 100644 (file)
@@ -39,7 +39,7 @@ struct rpc_clnt {
        struct list_head        cl_tasks;       /* List of tasks */
        spinlock_t              cl_lock;        /* spinlock */
        struct rpc_xprt __rcu * cl_xprt;        /* transport */
-       struct rpc_procinfo *   cl_procinfo;    /* procedure info */
+       const struct rpc_procinfo *cl_procinfo; /* procedure info */
        u32                     cl_prog,        /* RPC program number */
                                cl_vers,        /* RPC version number */
                                cl_maxproc;     /* max procedure number */
@@ -87,7 +87,8 @@ struct rpc_program {
 struct rpc_version {
        u32                     number;         /* version number */
        unsigned int            nrprocs;        /* number of procs */
-       struct rpc_procinfo *   procs;          /* procedure array */
+       const struct rpc_procinfo *procs;       /* procedure array */
+       unsigned int            *counts;        /* call counts */
 };
 
 /*
@@ -99,7 +100,6 @@ struct rpc_procinfo {
        kxdrdproc_t             p_decode;       /* XDR decode function */
        unsigned int            p_arglen;       /* argument hdr length (u32) */
        unsigned int            p_replen;       /* reply hdr length (u32) */
-       unsigned int            p_count;        /* call count */
        unsigned int            p_timer;        /* Which RTT timer to use */
        u32                     p_statidx;      /* Which procedure to account */
        const char *            p_name;         /* name of procedure */
index 9d7529f..50a99a1 100644 (file)
@@ -22,7 +22,7 @@
  */
 struct rpc_procinfo;
 struct rpc_message {
-       struct rpc_procinfo *   rpc_proc;       /* Procedure information */
+       const struct rpc_procinfo *rpc_proc;    /* Procedure information */
        void *                  rpc_argp;       /* Arguments */
        void *                  rpc_resp;       /* Result */
        struct rpc_cred *       rpc_cred;       /* Credentials */
index 11cef5a..a3f8af9 100644 (file)
@@ -237,7 +237,7 @@ struct svc_rqst {
 
        struct svc_serv *       rq_server;      /* RPC service definition */
        struct svc_pool *       rq_pool;        /* thread pool */
-       struct svc_procedure *  rq_procinfo;    /* procedure info */
+       const struct svc_procedure *rq_procinfo;/* procedure info */
        struct auth_ops *       rq_authop;      /* authentication flavour */
        struct svc_cred         rq_cred;        /* auth info */
        void *                  rq_xprt_ctxt;   /* transport specific context ptr */
@@ -246,7 +246,7 @@ struct svc_rqst {
        size_t                  rq_xprt_hlen;   /* xprt header len */
        struct xdr_buf          rq_arg;
        struct xdr_buf          rq_res;
-       struct page *           rq_pages[RPCSVC_MAXPAGES];
+       struct page             *rq_pages[RPCSVC_MAXPAGES + 1];
        struct page *           *rq_respages;   /* points into rq_pages */
        struct page *           *rq_next_page; /* next reply page to use */
        struct page *           *rq_page_end;  /* one past the last page */
@@ -384,7 +384,7 @@ struct svc_program {
        unsigned int            pg_lovers;      /* lowest version */
        unsigned int            pg_hivers;      /* highest version */
        unsigned int            pg_nvers;       /* number of versions */
-       struct svc_version **   pg_vers;        /* version array */
+       const struct svc_version **pg_vers;     /* version array */
        char *                  pg_name;        /* service name */
        char *                  pg_class;       /* class name: services sharing authentication */
        struct svc_stat *       pg_stats;       /* rpc statistics */
@@ -397,7 +397,8 @@ struct svc_program {
 struct svc_version {
        u32                     vs_vers;        /* version number */
        u32                     vs_nproc;       /* number of procedures */
-       struct svc_procedure *  vs_proc;        /* per-procedure info */
+       const struct svc_procedure *vs_proc;    /* per-procedure info */
+       unsigned int            *vs_count;      /* call counts */
        u32                     vs_xdrsize;     /* xdrsize needed for this version */
 
        /* Don't register with rpcbind */
@@ -419,15 +420,17 @@ struct svc_version {
 /*
  * RPC procedure info
  */
-typedef __be32 (*svc_procfunc)(struct svc_rqst *, void *argp, void *resp);
 struct svc_procedure {
-       svc_procfunc            pc_func;        /* process the request */
-       kxdrproc_t              pc_decode;      /* XDR decode args */
-       kxdrproc_t              pc_encode;      /* XDR encode result */
-       kxdrproc_t              pc_release;     /* XDR free result */
+       /* process the request: */
+       __be32                  (*pc_func)(struct svc_rqst *);
+       /* XDR decode args: */
+       int                     (*pc_decode)(struct svc_rqst *, __be32 *data);
+       /* XDR encode result: */
+       int                     (*pc_encode)(struct svc_rqst *, __be32 *data);
+       /* XDR free result: */
+       void                    (*pc_release)(struct svc_rqst *);
        unsigned int            pc_argsize;     /* argument struct size */
        unsigned int            pc_ressize;     /* result struct size */
-       unsigned int            pc_count;       /* call count */
        unsigned int            pc_cachetype;   /* cache info (NFS) */
        unsigned int            pc_xdrressize;  /* maximum size of XDR reply */
 };
index f3787d8..995c6fe 100644 (file)
@@ -77,46 +77,25 @@ extern atomic_t rdma_stat_sq_prod;
  */
 struct svc_rdma_op_ctxt {
        struct list_head list;
-       struct svc_rdma_op_ctxt *read_hdr;
-       struct svc_rdma_fastreg_mr *frmr;
-       int hdr_count;
        struct xdr_buf arg;
        struct ib_cqe cqe;
-       struct ib_cqe reg_cqe;
-       struct ib_cqe inv_cqe;
        u32 byte_len;
-       u32 position;
        struct svcxprt_rdma *xprt;
-       unsigned long flags;
        enum dma_data_direction direction;
        int count;
        unsigned int mapped_sges;
+       int hdr_count;
        struct ib_send_wr send_wr;
        struct ib_sge sge[1 + RPCRDMA_MAX_INLINE_THRESH / PAGE_SIZE];
        struct page *pages[RPCSVC_MAXPAGES];
 };
 
-struct svc_rdma_fastreg_mr {
-       struct ib_mr *mr;
-       struct scatterlist *sg;
-       int sg_nents;
-       unsigned long access_flags;
-       enum dma_data_direction direction;
-       struct list_head frmr_list;
-};
-
-#define RDMACTXT_F_LAST_CTXT   2
-
-#define        SVCRDMA_DEVCAP_FAST_REG         1       /* fast mr registration */
-#define        SVCRDMA_DEVCAP_READ_W_INV       2       /* read w/ invalidate */
-
 struct svcxprt_rdma {
        struct svc_xprt      sc_xprt;           /* SVC transport structure */
        struct rdma_cm_id    *sc_cm_id;         /* RDMA connection id */
        struct list_head     sc_accept_q;       /* Conn. waiting accept */
        int                  sc_ord;            /* RDMA read limit */
        int                  sc_max_sge;
-       int                  sc_max_sge_rd;     /* max sge for read target */
        bool                 sc_snd_w_inv;      /* OK to use Send With Invalidate */
 
        atomic_t             sc_sq_avail;       /* SQEs ready to be consumed */
@@ -141,14 +120,6 @@ struct svcxprt_rdma {
        struct ib_qp         *sc_qp;
        struct ib_cq         *sc_rq_cq;
        struct ib_cq         *sc_sq_cq;
-       int                  (*sc_reader)(struct svcxprt_rdma *,
-                                         struct svc_rqst *,
-                                         struct svc_rdma_op_ctxt *,
-                                         int *, u32 *, u32, u32, u64, bool);
-       u32                  sc_dev_caps;       /* distilled device caps */
-       unsigned int         sc_frmr_pg_list_len;
-       struct list_head     sc_frmr_q;
-       spinlock_t           sc_frmr_q_lock;
 
        spinlock_t           sc_lock;           /* transport lock */
 
@@ -185,20 +156,14 @@ extern int svc_rdma_handle_bc_reply(struct rpc_xprt *xprt,
                                    __be32 *rdma_resp,
                                    struct xdr_buf *rcvbuf);
 
-/* svc_rdma_marshal.c */
-extern int svc_rdma_xdr_decode_req(struct xdr_buf *);
-
 /* svc_rdma_recvfrom.c */
 extern int svc_rdma_recvfrom(struct svc_rqst *);
-extern int rdma_read_chunk_lcl(struct svcxprt_rdma *, struct svc_rqst *,
-                              struct svc_rdma_op_ctxt *, int *, u32 *,
-                              u32, u32, u64, bool);
-extern int rdma_read_chunk_frmr(struct svcxprt_rdma *, struct svc_rqst *,
-                               struct svc_rdma_op_ctxt *, int *, u32 *,
-                               u32, u32, u64, bool);
 
 /* svc_rdma_rw.c */
 extern void svc_rdma_destroy_rw_ctxts(struct svcxprt_rdma *rdma);
+extern int svc_rdma_recv_read_chunk(struct svcxprt_rdma *rdma,
+                                   struct svc_rqst *rqstp,
+                                   struct svc_rdma_op_ctxt *head, __be32 *p);
 extern int svc_rdma_send_write_chunk(struct svcxprt_rdma *rdma,
                                     __be32 *wr_ch, struct xdr_buf *xdr);
 extern int svc_rdma_send_reply_chunk(struct svcxprt_rdma *rdma,
@@ -226,9 +191,6 @@ extern int svc_rdma_create_listen(struct svc_serv *, int, struct sockaddr *);
 extern struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *);
 extern void svc_rdma_put_context(struct svc_rdma_op_ctxt *, int);
 extern void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt);
-extern struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *);
-extern void svc_rdma_put_frmr(struct svcxprt_rdma *,
-                             struct svc_rdma_fastreg_mr *);
 extern void svc_sq_reap(struct svcxprt_rdma *);
 extern void svc_rq_reap(struct svcxprt_rdma *);
 extern void svc_rdma_prep_reply_hdr(struct svc_rqst *);
index 054c8cd..261b48a 100644 (file)
@@ -17,6 +17,8 @@
 #include <asm/unaligned.h>
 #include <linux/scatterlist.h>
 
+struct rpc_rqst;
+
 /*
  * Buffer adjustment
  */
@@ -33,13 +35,6 @@ struct xdr_netobj {
 };
 
 /*
- * This is the legacy generic XDR function. rqstp is either a rpc_rqst
- * (client side) or svc_rqst pointer (server side).
- * Encode functions always assume there's enough room in the buffer.
- */
-typedef int    (*kxdrproc_t)(void *rqstp, __be32 *data, void *obj);
-
-/*
  * Basic structure for transmission/reception of a client XDR message.
  * Features a header (for a linear buffer containing RPC headers
  * and the data payload for short messages), and then an array of
@@ -222,8 +217,10 @@ struct xdr_stream {
 /*
  * These are the xdr_stream style generic XDR encode and decode functions.
  */
-typedef void   (*kxdreproc_t)(void *rqstp, struct xdr_stream *xdr, void *obj);
-typedef int    (*kxdrdproc_t)(void *rqstp, struct xdr_stream *xdr, void *obj);
+typedef void   (*kxdreproc_t)(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+               const void *obj);
+typedef int    (*kxdrdproc_t)(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+               void *obj);
 
 extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
 extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
index 80d0781..1d4dba4 100644 (file)
@@ -47,6 +47,9 @@ extern int proc_douintvec(struct ctl_table *, int,
                         void __user *, size_t *, loff_t *);
 extern int proc_dointvec_minmax(struct ctl_table *, int,
                                void __user *, size_t *, loff_t *);
+extern int proc_douintvec_minmax(struct ctl_table *table, int write,
+                                void __user *buffer, size_t *lenp,
+                                loff_t *ppos);
 extern int proc_dointvec_jiffies(struct ctl_table *, int,
                                 void __user *, size_t *, loff_t *);
 extern int proc_dointvec_userhz_jiffies(struct ctl_table *, int,
@@ -117,7 +120,7 @@ struct ctl_table
        struct ctl_table_poll *poll;
        void *extra1;
        void *extra2;
-};
+} __randomize_layout;
 
 struct ctl_node {
        struct rb_node node;
@@ -143,7 +146,7 @@ struct ctl_table_header
        struct ctl_table_set *set;
        struct ctl_dir *parent;
        struct ctl_node *node;
-       struct list_head inodes; /* head for proc_inode->sysctl_inodes */
+       struct hlist_head inodes; /* head for proc_inode->sysctl_inodes */
 };
 
 struct ctl_dir {
index 542ca1a..d7389ea 100644 (file)
@@ -148,12 +148,6 @@ struct tcp_sock {
        u16     gso_segs;       /* Max number of segs per GSO packet    */
 
 /*
- *     Header prediction flags
- *     0x5?10 << 16 + snd_wnd in net byte order
- */
-       __be32  pred_flags;
-
-/*
  *     RFC793 variables by their proper names. This means you can
  *     read the code and the spec side by side (and laugh ...)
  *     See RFC793 and RFC1122. The RFC writes these in capitals.
@@ -192,15 +186,6 @@ struct tcp_sock {
 
        struct list_head tsq_node; /* anchor in tsq_tasklet.head list */
 
-       /* Data for direct copy to user */
-       struct {
-               struct sk_buff_head     prequeue;
-               struct task_struct      *task;
-               struct msghdr           *msg;
-               int                     memory;
-               int                     len;
-       } ucopy;
-
        u32     snd_wl1;        /* Sequence for window update           */
        u32     snd_wnd;        /* The window we expect to receive      */
        u32     max_window;     /* Maximal window ever seen from peer   */
index f73cedf..536c80f 100644 (file)
@@ -338,7 +338,7 @@ enum {
 struct trace_event_file {
        struct list_head                list;
        struct trace_event_call         *event_call;
-       struct event_filter             *filter;
+       struct event_filter __rcu       *filter;
        struct dentry                   *dir;
        struct trace_array              *tr;
        struct trace_subsystem_dir      *system;
index 69464c0..79c30da 100644 (file)
@@ -332,7 +332,7 @@ struct tty_struct {
        /* If the tty has a pending do_SAK, queue it here - akpm */
        struct work_struct SAK_work;
        struct tty_port *port;
-};
+} __randomize_layout;
 
 /* Each of a tty's open files has private_data pointing to tty_file_private */
 struct tty_file_private {
index b742b5e..00b2213 100644 (file)
@@ -291,7 +291,7 @@ struct tty_operations {
        void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
 #endif
        const struct file_operations *proc_fops;
-};
+} __randomize_layout;
 
 struct tty_driver {
        int     magic;          /* magic number for this structure */
@@ -325,7 +325,7 @@ struct tty_driver {
 
        const struct tty_operations *ops;
        struct list_head tty_drivers;
-};
+} __randomize_layout;
 
 extern struct list_head tty_drivers;
 
index c5f2158..fd73bc0 100644 (file)
@@ -115,13 +115,13 @@ struct uac2_input_terminal_descriptor {
        __u8 bDescriptorType;
        __u8 bDescriptorSubtype;
        __u8 bTerminalID;
-       __u16 wTerminalType;
+       __le16 wTerminalType;
        __u8 bAssocTerminal;
        __u8 bCSourceID;
        __u8 bNrChannels;
-       __u32 bmChannelConfig;
+       __le32 bmChannelConfig;
        __u8 iChannelNames;
-       __u16 bmControls;
+       __le16 bmControls;
        __u8 iTerminal;
 } __attribute__((packed));
 
@@ -132,11 +132,11 @@ struct uac2_output_terminal_descriptor {
        __u8 bDescriptorType;
        __u8 bDescriptorSubtype;
        __u8 bTerminalID;
-       __u16 wTerminalType;
+       __le16 wTerminalType;
        __u8 bAssocTerminal;
        __u8 bSourceID;
        __u8 bCSourceID;
-       __u16 bmControls;
+       __le16 bmControls;
        __u8 iTerminal;
 } __attribute__((packed));
 
@@ -164,9 +164,9 @@ struct uac2_as_header_descriptor {
        __u8 bTerminalLink;
        __u8 bmControls;
        __u8 bFormatType;
-       __u32 bmFormats;
+       __le32 bmFormats;
        __u8 bNrChannels;
-       __u32 bmChannelConfig;
+       __le32 bmChannelConfig;
        __u8 iChannelNames;
 } __attribute__((packed));
 
index 021f7a8..1a59699 100644 (file)
@@ -83,6 +83,7 @@
 /* Driver flags */
 #define CDC_NCM_FLAG_NDP_TO_END                        0x02    /* NDP is placed at end of frame */
 #define CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE  0x04    /* Avoid altsetting toggle during init */
+#define CDC_NCM_FLAG_RESET_NTB16 0x08  /* set NDP16 one more time after altsetting switch */
 
 #define cdc_ncm_comm_intf_is_mbim(x)  ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \
                                       (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE)
index 32354b4..b3575ce 100644 (file)
@@ -66,7 +66,7 @@ struct user_namespace {
 #endif
        struct ucounts          *ucounts;
        int ucount_max[UCOUNT_COUNTS];
-};
+} __randomize_layout;
 
 struct ucounts {
        struct hlist_node node;
index 60f0bb8..da826ed 100644 (file)
@@ -26,7 +26,7 @@ struct uts_namespace {
        struct user_namespace *user_ns;
        struct ucounts *ucounts;
        struct ns_common ns;
-};
+} __randomize_layout;
 extern struct uts_namespace init_uts_ns;
 
 #ifdef CONFIG_UTS_NS
index 2251e19..33b0bdb 100644 (file)
@@ -84,26 +84,12 @@ int guid_parse(const char *uuid, guid_t *u);
 int uuid_parse(const char *uuid, uuid_t *u);
 
 /* backwards compatibility, don't use in new code */
-typedef uuid_t uuid_be;
-#define UUID_BE(a, _b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
-       UUID_INIT(a, _b, c, d0, d1, d2, d3, d4, d5, d6, d7)
-#define NULL_UUID_BE                                                   \
-       UUID_BE(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00,     \
-            0x00, 0x00, 0x00, 0x00)
-
 #define uuid_le_gen(u)         guid_gen(u)
-#define uuid_be_gen(u)         uuid_gen(u)
 #define uuid_le_to_bin(guid, u)        guid_parse(guid, u)
-#define uuid_be_to_bin(uuid, u)        uuid_parse(uuid, u)
 
 static inline int uuid_le_cmp(const guid_t u1, const guid_t u2)
 {
        return memcmp(&u1, &u2, sizeof(guid_t));
 }
 
-static inline int uuid_be_cmp(const uuid_t u1, const uuid_t u2)
-{
-       return memcmp(&u1, &u2, sizeof(uuid_t));
-}
-
 #endif
index f57076b..586809a 100644 (file)
@@ -97,6 +97,8 @@ extern void vfio_unregister_iommu_driver(
  */
 extern struct vfio_group *vfio_group_get_external_user(struct file *filep);
 extern void vfio_group_put_external_user(struct vfio_group *group);
+extern bool vfio_external_group_match_file(struct vfio_group *group,
+                                          struct file *filep);
 extern int vfio_external_user_iommu_id(struct vfio_group *group);
 extern long vfio_external_check_extension(struct vfio_group *group,
                                          unsigned long arg);
index b289c96..5b74e36 100644 (file)
@@ -529,13 +529,13 @@ do {                                                                              \
 
 /**
  * wait_event_interruptible_hrtimeout - sleep until a condition gets true or a timeout elapses
- * @wq_head: the waitqueue to wait on
+ * @wq: the waitqueue to wait on
  * @condition: a C expression for the event to wait for
  * @timeout: timeout, as a ktime_t
  *
  * The process is put to sleep (TASK_INTERRUPTIBLE) until the
  * @condition evaluates to true or a signal is received.
- * The @condition is checked each time the waitqueue @wq_head is woken up.
+ * The @condition is checked each time the waitqueue @wq is woken up.
  *
  * wake_up() has to be called after changing any variable that could
  * change the result of the wait condition.
@@ -735,12 +735,12 @@ extern int do_wait_intr_irq(wait_queue_head_t *, wait_queue_entry_t *);
 
 /**
  * wait_event_killable - sleep until a condition gets true
- * @wq: the waitqueue to wait on
+ * @wq_head: the waitqueue to wait on
  * @condition: a C expression for the event to wait for
  *
  * The process is put to sleep (TASK_KILLABLE) until the
  * @condition evaluates to true or a signal is received.
- * The @condition is checked each time the waitqueue @wq is woken up.
+ * The @condition is checked each time the waitqueue @wq_head is woken up.
  *
  * wake_up() has to be called after changing any variable that could
  * change the result of the wait condition.
index c102ef6..db6dc9d 100644 (file)
@@ -323,6 +323,7 @@ enum {
 
        __WQ_DRAINING           = 1 << 16, /* internal: workqueue is draining */
        __WQ_ORDERED            = 1 << 17, /* internal: workqueue is ordered */
+       __WQ_ORDERED_EXPLICIT   = 1 << 18, /* internal: alloc_ordered_workqueue() */
        __WQ_LEGACY             = 1 << 18, /* internal: create*_workqueue() */
 
        WQ_MAX_ACTIVE           = 512,    /* I like 512, better ideas? */
@@ -422,7 +423,8 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
  * Pointer to the allocated workqueue on success, %NULL on failure.
  */
 #define alloc_ordered_workqueue(fmt, flags, args...)                   \
-       alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
+       alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED |                \
+                       __WQ_ORDERED_EXPLICIT | (flags), 1, ##args)
 
 #define create_workqueue(name)                                         \
        alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name))
index b582339..7af9d76 100644 (file)
@@ -157,6 +157,18 @@ struct p9_client {
        enum p9_trans_status status;
        void *trans;
 
+       union {
+               struct {
+                       int rfd;
+                       int wfd;
+               } fd;
+               struct {
+                       u16 port;
+                       bool privport;
+
+               } tcp;
+       } trans_opts;
+
        struct p9_idpool *fidpool;
        struct list_head fidlist;
 
@@ -213,6 +225,7 @@ struct p9_dirent {
 
 struct iov_iter;
 
+int p9_show_client_options(struct seq_file *m, struct p9_client *clnt);
 int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb);
 int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid,
                     const char *name);
index 5122b5e..1625fb8 100644 (file)
@@ -62,6 +62,7 @@ struct p9_trans_module {
        int (*cancelled)(struct p9_client *, struct p9_req_t *req);
        int (*zc_request)(struct p9_client *, struct p9_req_t *,
                          struct iov_iter *, struct iov_iter *, int , int, int);
+       int (*show_options)(struct seq_file *, struct p9_client *);
 };
 
 void v9fs_register_trans(struct p9_trans_module *m);
index 3b3194b..afb37f8 100644 (file)
@@ -37,7 +37,7 @@ struct unix_skb_parms {
        u32                     secid;          /* Security ID          */
 #endif
        u32                     consumed;
-};
+} __randomize_layout;
 
 #define UNIXCB(skb)    (*(struct unix_skb_parms *)&((skb)->cb))
 
index afc39e3..9816df2 100644 (file)
@@ -156,7 +156,7 @@ struct neighbour {
        struct rcu_head         rcu;
        struct net_device       *dev;
        u8                      primary_key[0];
-};
+} __randomize_layout;
 
 struct neigh_ops {
        int                     family;
index 31a2b51..1c401bd 100644 (file)
@@ -148,7 +148,7 @@ struct net {
 #endif
        struct sock             *diag_nlsk;
        atomic_t                fnhe_genid;
-};
+} __randomize_layout;
 
 #include <linux/seq_file_net.h>
 
index 0170917..82dd298 100644 (file)
@@ -98,8 +98,8 @@
  *   nla_put_u8(skb, type, value)      add u8 attribute to skb
  *   nla_put_u16(skb, type, value)     add u16 attribute to skb
  *   nla_put_u32(skb, type, value)     add u32 attribute to skb
- *   nla_put_u64_64bits(skb, type,
- *                     value, padattr) add u64 attribute to skb
+ *   nla_put_u64_64bit(skb, type,
+ *                     value, padattr) add u64 attribute to skb
  *   nla_put_s8(skb, type, value)      add s8 attribute to skb
  *   nla_put_s16(skb, type, value)     add s16 attribute to skb
  *   nla_put_s32(skb, type, value)     add s32 attribute to skb
@@ -178,6 +178,7 @@ enum {
        NLA_S16,
        NLA_S32,
        NLA_S64,
+       NLA_BITFIELD32,
        __NLA_TYPE_MAX,
 };
 
@@ -206,6 +207,7 @@ enum {
  *    NLA_MSECS            Leaving the length field zero will verify the
  *                         given type fits, using it verifies minimum length
  *                         just like "All other"
+ *    NLA_BITFIELD32      A 32-bit bitmap/bitselector attribute
  *    All other            Minimum length of attribute payload
  *
  * Example:
@@ -213,11 +215,13 @@ enum {
  *     [ATTR_FOO] = { .type = NLA_U16 },
  *     [ATTR_BAR] = { .type = NLA_STRING, .len = BARSIZ },
  *     [ATTR_BAZ] = { .len = sizeof(struct mystruct) },
+ *     [ATTR_GOO] = { .type = NLA_BITFIELD32, .validation_data = &myvalidflags },
  * };
  */
 struct nla_policy {
        u16             type;
        u16             len;
+       void            *validation_data;
 };
 
 /**
@@ -1203,6 +1207,18 @@ static inline struct in6_addr nla_get_in6_addr(const struct nlattr *nla)
 }
 
 /**
+ * nla_get_bitfield32 - return payload of 32 bitfield attribute
+ * @nla: nla_bitfield32 attribute
+ */
+static inline struct nla_bitfield32 nla_get_bitfield32(const struct nlattr *nla)
+{
+       struct nla_bitfield32 tmp;
+
+       nla_memcpy(&tmp, nla, sizeof(tmp));
+       return tmp;
+}
+
+/**
  * nla_memdup - duplicate attribute memory (kmemdup)
  * @src: netlink attribute to duplicate from
  * @gfp: GFP mask
index d4679e7..1d5f6ff 100644 (file)
@@ -135,7 +135,7 @@ typedef union {
        struct sctp_init_chunk *init;
        struct sctp_ulpevent *ulpevent;
        struct sctp_packet *packet;
-       sctp_sackhdr_t *sackh;
+       struct sctp_sackhdr *sackh;
        struct sctp_datamsg *msg;
 } sctp_arg_t;
 
@@ -176,7 +176,7 @@ SCTP_ARG_CONSTRUCTOR(BA,    struct sctp_bind_addr *, bp)
 SCTP_ARG_CONSTRUCTOR(PEER_INIT,        struct sctp_init_chunk *, init)
 SCTP_ARG_CONSTRUCTOR(ULPEVENT,  struct sctp_ulpevent *, ulpevent)
 SCTP_ARG_CONSTRUCTOR(PACKET,   struct sctp_packet *, packet)
-SCTP_ARG_CONSTRUCTOR(SACKH,    sctp_sackhdr_t *, sackh)
+SCTP_ARG_CONSTRUCTOR(SACKH,    struct sctp_sackhdr *, sackh)
 SCTP_ARG_CONSTRUCTOR(DATAMSG,  struct sctp_datamsg *, msg)
 
 static inline sctp_arg_t SCTP_FORCE(void)
index a9519a0..45fd4c6 100644 (file)
@@ -469,6 +469,8 @@ _sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member)
 
 #define _sctp_walk_params(pos, chunk, end, member)\
 for (pos.v = chunk->member;\
+     (pos.v + offsetof(struct sctp_paramhdr, length) + sizeof(pos.p->length) <=\
+      (void *)chunk + end) &&\
      pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\
      ntohs(pos.p->length) >= sizeof(struct sctp_paramhdr);\
      pos.v += SCTP_PAD4(ntohs(pos.p->length)))
@@ -479,6 +481,8 @@ _sctp_walk_errors((err), (chunk_hdr), ntohs((chunk_hdr)->length))
 #define _sctp_walk_errors(err, chunk_hdr, end)\
 for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
            sizeof(struct sctp_chunkhdr));\
+     ((void *)err + offsetof(sctp_errhdr_t, length) + sizeof(err->length) <=\
+      (void *)chunk_hdr + end) &&\
      (void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\
      ntohs(err->length) >= sizeof(sctp_errhdr_t); \
      err = (sctp_errhdr_t *)((void *)err + SCTP_PAD4(ntohs(err->length))))
index f69c8c2..393c38e 100644 (file)
@@ -1128,7 +1128,7 @@ struct proto {
        atomic_t                socks;
 #endif
        int                     (*diag_destroy)(struct sock *sk, int err);
-};
+} __randomize_layout;
 
 int proto_register(struct proto *prot, int alloc_slab);
 void proto_unregister(struct proto *prot);
@@ -1582,11 +1582,14 @@ int sock_no_shutdown(struct socket *, int);
 int sock_no_getsockopt(struct socket *, int , int, char __user *, int __user *);
 int sock_no_setsockopt(struct socket *, int, int, char __user *, unsigned int);
 int sock_no_sendmsg(struct socket *, struct msghdr *, size_t);
+int sock_no_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t len);
 int sock_no_recvmsg(struct socket *, struct msghdr *, size_t, int);
 int sock_no_mmap(struct file *file, struct socket *sock,
                 struct vm_area_struct *vma);
 ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset,
                         size_t size, int flags);
+ssize_t sock_no_sendpage_locked(struct sock *sk, struct page *page,
+                               int offset, size_t size, int flags);
 
 /*
  * Functions to fill in entries in struct proto_ops when a protocol
index 0c28ad9..4fe966a 100644 (file)
 #define STRP_STATS_INCR(stat) ((stat)++)
 
 struct strp_stats {
-       unsigned long long rx_msgs;
-       unsigned long long rx_bytes;
-       unsigned int rx_mem_fail;
-       unsigned int rx_need_more_hdr;
-       unsigned int rx_msg_too_big;
-       unsigned int rx_msg_timeouts;
-       unsigned int rx_bad_hdr_len;
+       unsigned long long msgs;
+       unsigned long long bytes;
+       unsigned int mem_fail;
+       unsigned int need_more_hdr;
+       unsigned int msg_too_big;
+       unsigned int msg_timeouts;
+       unsigned int bad_hdr_len;
 };
 
 struct strp_aggr_stats {
-       unsigned long long rx_msgs;
-       unsigned long long rx_bytes;
-       unsigned int rx_mem_fail;
-       unsigned int rx_need_more_hdr;
-       unsigned int rx_msg_too_big;
-       unsigned int rx_msg_timeouts;
-       unsigned int rx_bad_hdr_len;
-       unsigned int rx_aborts;
-       unsigned int rx_interrupted;
-       unsigned int rx_unrecov_intr;
+       unsigned long long msgs;
+       unsigned long long bytes;
+       unsigned int mem_fail;
+       unsigned int need_more_hdr;
+       unsigned int msg_too_big;
+       unsigned int msg_timeouts;
+       unsigned int bad_hdr_len;
+       unsigned int aborts;
+       unsigned int interrupted;
+       unsigned int unrecov_intr;
 };
 
 struct strparser;
@@ -48,16 +48,18 @@ struct strp_callbacks {
        void (*rcv_msg)(struct strparser *strp, struct sk_buff *skb);
        int (*read_sock_done)(struct strparser *strp, int err);
        void (*abort_parser)(struct strparser *strp, int err);
+       void (*lock)(struct strparser *strp);
+       void (*unlock)(struct strparser *strp);
 };
 
-struct strp_rx_msg {
+struct strp_msg {
        int full_len;
        int offset;
 };
 
-static inline struct strp_rx_msg *strp_rx_msg(struct sk_buff *skb)
+static inline struct strp_msg *strp_msg(struct sk_buff *skb)
 {
-       return (struct strp_rx_msg *)((void *)skb->cb +
+       return (struct strp_msg *)((void *)skb->cb +
                offsetof(struct qdisc_skb_cb, data));
 }
 
@@ -65,18 +67,18 @@ static inline struct strp_rx_msg *strp_rx_msg(struct sk_buff *skb)
 struct strparser {
        struct sock *sk;
 
-       u32 rx_stopped : 1;
-       u32 rx_paused : 1;
-       u32 rx_aborted : 1;
-       u32 rx_interrupted : 1;
-       u32 rx_unrecov_intr : 1;
-
-       struct sk_buff **rx_skb_nextp;
-       struct timer_list rx_msg_timer;
-       struct sk_buff *rx_skb_head;
-       unsigned int rx_need_bytes;
-       struct delayed_work rx_delayed_work;
-       struct work_struct rx_work;
+       u32 stopped : 1;
+       u32 paused : 1;
+       u32 aborted : 1;
+       u32 interrupted : 1;
+       u32 unrecov_intr : 1;
+
+       struct sk_buff **skb_nextp;
+       struct timer_list msg_timer;
+       struct sk_buff *skb_head;
+       unsigned int need_bytes;
+       struct delayed_work delayed_work;
+       struct work_struct work;
        struct strp_stats stats;
        struct strp_callbacks cb;
 };
@@ -84,7 +86,7 @@ struct strparser {
 /* Must be called with lock held for attached socket */
 static inline void strp_pause(struct strparser *strp)
 {
-       strp->rx_paused = 1;
+       strp->paused = 1;
 }
 
 /* May be called without holding lock for attached socket */
@@ -97,37 +99,37 @@ static inline void save_strp_stats(struct strparser *strp,
 
 #define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat +=           \
                                 strp->stats._stat)
-       SAVE_PSOCK_STATS(rx_msgs);
-       SAVE_PSOCK_STATS(rx_bytes);
-       SAVE_PSOCK_STATS(rx_mem_fail);
-       SAVE_PSOCK_STATS(rx_need_more_hdr);
-       SAVE_PSOCK_STATS(rx_msg_too_big);
-       SAVE_PSOCK_STATS(rx_msg_timeouts);
-       SAVE_PSOCK_STATS(rx_bad_hdr_len);
+       SAVE_PSOCK_STATS(msgs);
+       SAVE_PSOCK_STATS(bytes);
+       SAVE_PSOCK_STATS(mem_fail);
+       SAVE_PSOCK_STATS(need_more_hdr);
+       SAVE_PSOCK_STATS(msg_too_big);
+       SAVE_PSOCK_STATS(msg_timeouts);
+       SAVE_PSOCK_STATS(bad_hdr_len);
 #undef SAVE_PSOCK_STATS
 
-       if (strp->rx_aborted)
-               agg_stats->rx_aborts++;
-       if (strp->rx_interrupted)
-               agg_stats->rx_interrupted++;
-       if (strp->rx_unrecov_intr)
-               agg_stats->rx_unrecov_intr++;
+       if (strp->aborted)
+               agg_stats->aborts++;
+       if (strp->interrupted)
+               agg_stats->interrupted++;
+       if (strp->unrecov_intr)
+               agg_stats->unrecov_intr++;
 }
 
 static inline void aggregate_strp_stats(struct strp_aggr_stats *stats,
                                        struct strp_aggr_stats *agg_stats)
 {
 #define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += stats->_stat)
-       SAVE_PSOCK_STATS(rx_msgs);
-       SAVE_PSOCK_STATS(rx_bytes);
-       SAVE_PSOCK_STATS(rx_mem_fail);
-       SAVE_PSOCK_STATS(rx_need_more_hdr);
-       SAVE_PSOCK_STATS(rx_msg_too_big);
-       SAVE_PSOCK_STATS(rx_msg_timeouts);
-       SAVE_PSOCK_STATS(rx_bad_hdr_len);
-       SAVE_PSOCK_STATS(rx_aborts);
-       SAVE_PSOCK_STATS(rx_interrupted);
-       SAVE_PSOCK_STATS(rx_unrecov_intr);
+       SAVE_PSOCK_STATS(msgs);
+       SAVE_PSOCK_STATS(bytes);
+       SAVE_PSOCK_STATS(mem_fail);
+       SAVE_PSOCK_STATS(need_more_hdr);
+       SAVE_PSOCK_STATS(msg_too_big);
+       SAVE_PSOCK_STATS(msg_timeouts);
+       SAVE_PSOCK_STATS(bad_hdr_len);
+       SAVE_PSOCK_STATS(aborts);
+       SAVE_PSOCK_STATS(interrupted);
+       SAVE_PSOCK_STATS(unrecov_intr);
 #undef SAVE_PSOCK_STATS
 
 }
@@ -135,8 +137,11 @@ static inline void aggregate_strp_stats(struct strp_aggr_stats *stats,
 void strp_done(struct strparser *strp);
 void strp_stop(struct strparser *strp);
 void strp_check_rcv(struct strparser *strp);
-int strp_init(struct strparser *strp, struct sock *csk,
+int strp_init(struct strparser *strp, struct sock *sk,
              struct strp_callbacks *cb);
 void strp_data_ready(struct strparser *strp);
+int strp_process(struct strparser *strp, struct sk_buff *orig_skb,
+                unsigned int orig_offset, size_t orig_len,
+                size_t max_msg_size, long timeo);
 
 #endif /* __NET_STRPARSER_H_ */
index 4f056ea..bb1881b 100644 (file)
@@ -256,7 +256,6 @@ extern int sysctl_tcp_rmem[3];
 extern int sysctl_tcp_app_win;
 extern int sysctl_tcp_adv_win_scale;
 extern int sysctl_tcp_frto;
-extern int sysctl_tcp_low_latency;
 extern int sysctl_tcp_nometrics_save;
 extern int sysctl_tcp_moderate_rcvbuf;
 extern int sysctl_tcp_tso_win_divisor;
@@ -351,8 +350,11 @@ int tcp_v4_rcv(struct sk_buff *skb);
 
 int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
 int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
+int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size);
 int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
                 int flags);
+int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset,
+                       size_t size, int flags);
 ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
                 size_t size, int flags);
 void tcp_release_cb(struct sock *sk);
@@ -362,7 +364,7 @@ void tcp_delack_timer_handler(struct sock *sk);
 int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb);
 void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
-                        const struct tcphdr *th, unsigned int len);
+                        const struct tcphdr *th);
 void tcp_rcv_space_adjust(struct sock *sk);
 int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);
 void tcp_twsk_destructor(struct sock *sk);
@@ -632,29 +634,6 @@ static inline u32 __tcp_set_rto(const struct tcp_sock *tp)
        return usecs_to_jiffies((tp->srtt_us >> 3) + tp->rttvar_us);
 }
 
-static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd)
-{
-       tp->pred_flags = htonl((tp->tcp_header_len << 26) |
-                              ntohl(TCP_FLAG_ACK) |
-                              snd_wnd);
-}
-
-static inline void tcp_fast_path_on(struct tcp_sock *tp)
-{
-       __tcp_fast_path_on(tp, tp->snd_wnd >> tp->rx_opt.snd_wscale);
-}
-
-static inline void tcp_fast_path_check(struct sock *sk)
-{
-       struct tcp_sock *tp = tcp_sk(sk);
-
-       if (RB_EMPTY_ROOT(&tp->out_of_order_queue) &&
-           tp->rcv_wnd &&
-           atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
-           !tp->urg_data)
-               tcp_fast_path_on(tp);
-}
-
 /* Compute the actual rto_min value */
 static inline u32 tcp_rto_min(struct sock *sk)
 {
@@ -904,9 +883,8 @@ enum tcp_ca_event {
 
 /* Information about inbound ACK, passed to cong_ops->in_ack_event() */
 enum tcp_ca_ack_event_flags {
-       CA_ACK_SLOWPATH         = (1 << 0),     /* In slow path processing */
-       CA_ACK_WIN_UPDATE       = (1 << 1),     /* ACK updated window */
-       CA_ACK_ECE              = (1 << 2),     /* ECE bit is set on ack */
+       CA_ACK_WIN_UPDATE       = (1 << 0),     /* ACK updated window */
+       CA_ACK_ECE              = (1 << 1),     /* ECE bit is set on ack */
 };
 
 /*
@@ -1244,17 +1222,6 @@ static inline bool tcp_checksum_complete(struct sk_buff *skb)
                __tcp_checksum_complete(skb);
 }
 
-/* Prequeue for VJ style copy to user, combined with checksumming. */
-
-static inline void tcp_prequeue_init(struct tcp_sock *tp)
-{
-       tp->ucopy.task = NULL;
-       tp->ucopy.len = 0;
-       tp->ucopy.memory = 0;
-       skb_queue_head_init(&tp->ucopy.prequeue);
-}
-
-bool tcp_prequeue(struct sock *sk, struct sk_buff *skb);
 bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb);
 int tcp_filter(struct sock *sk, struct sk_buff *skb);
 
index 972ce4b..cc80369 100644 (file)
@@ -260,6 +260,7 @@ static inline struct sk_buff *skb_recv_udp(struct sock *sk, unsigned int flags,
 }
 
 void udp_v4_early_demux(struct sk_buff *skb);
+void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst);
 int udp_get_port(struct sock *sk, unsigned short snum,
                 int (*saddr_cmp)(const struct sock *,
                                  const struct sock *));
@@ -305,33 +306,44 @@ struct sock *udp6_lib_lookup_skb(struct sk_buff *skb,
 /* UDP uses skb->dev_scratch to cache as much information as possible and avoid
  * possibly multiple cache miss on dequeue()
  */
-#if BITS_PER_LONG == 64
-
-/* truesize, len and the bit needed to compute skb_csum_unnecessary will be on
- * cold cache lines at recvmsg time.
- * skb->len can be stored on 16 bits since the udp header has been already
- * validated and pulled.
- */
 struct udp_dev_scratch {
-       u32 truesize;
+       /* skb->truesize and the stateless bit are embedded in a single field;
+        * do not use a bitfield since the compiler emits better/smaller code
+        * this way
+        */
+       u32 _tsize_state;
+
+#if BITS_PER_LONG == 64
+       /* len and the bit needed to compute skb_csum_unnecessary
+        * will be on cold cache lines at recvmsg time.
+        * skb->len can be stored on 16 bits since the udp header has been
+        * already validated and pulled.
+        */
        u16 len;
        bool is_linear;
        bool csum_unnecessary;
+#endif
 };
 
+static inline struct udp_dev_scratch *udp_skb_scratch(struct sk_buff *skb)
+{
+       return (struct udp_dev_scratch *)&skb->dev_scratch;
+}
+
+#if BITS_PER_LONG == 64
 static inline unsigned int udp_skb_len(struct sk_buff *skb)
 {
-       return ((struct udp_dev_scratch *)&skb->dev_scratch)->len;
+       return udp_skb_scratch(skb)->len;
 }
 
 static inline bool udp_skb_csum_unnecessary(struct sk_buff *skb)
 {
-       return ((struct udp_dev_scratch *)&skb->dev_scratch)->csum_unnecessary;
+       return udp_skb_scratch(skb)->csum_unnecessary;
 }
 
 static inline bool udp_skb_is_linear(struct sk_buff *skb)
 {
-       return ((struct udp_dev_scratch *)&skb->dev_scratch)->is_linear;
+       return udp_skb_scratch(skb)->is_linear;
 }
 
 #else
index 02c5be0..10cce0d 100644 (file)
@@ -115,6 +115,8 @@ struct udp_tunnel_info {
 /* Notify network devices of offloadable types */
 void udp_tunnel_push_rx_port(struct net_device *dev, struct socket *sock,
                             unsigned short type);
+void udp_tunnel_drop_rx_port(struct net_device *dev, struct socket *sock,
+                            unsigned short type);
 void udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type);
 void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type);
 
@@ -124,6 +126,12 @@ static inline void udp_tunnel_get_rx_info(struct net_device *dev)
        call_netdevice_notifiers(NETDEV_UDP_TUNNEL_PUSH_INFO, dev);
 }
 
+static inline void udp_tunnel_drop_rx_info(struct net_device *dev)
+{
+       ASSERT_RTNL();
+       call_netdevice_notifiers(NETDEV_UDP_TUNNEL_DROP_INFO, dev);
+}
+
 /* Transmit the skb using UDP encapsulation. */
 void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
                         __be32 src, __be32 dst, __u8 tos, __u8 ttl,
index 4b34c51..b73a14e 100644 (file)
@@ -205,11 +205,13 @@ static inline void iboe_addr_get_sgid(struct rdma_dev_addr *dev_addr,
        dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
        if (dev) {
                ip4 = in_dev_get(dev);
-               if (ip4 && ip4->ifa_list && ip4->ifa_list->ifa_address) {
+               if (ip4 && ip4->ifa_list && ip4->ifa_list->ifa_address)
                        ipv6_addr_set_v4mapped(ip4->ifa_list->ifa_address,
                                               (struct in6_addr *)gid);
+
+               if (ip4)
                        in_dev_put(ip4);
-               }
+
                dev_put(dev);
        }
 }
index 356953d..b573243 100644 (file)
@@ -1056,7 +1056,7 @@ enum ib_qp_create_flags {
        IB_QP_CREATE_MANAGED_RECV               = 1 << 4,
        IB_QP_CREATE_NETIF_QP                   = 1 << 5,
        IB_QP_CREATE_SIGNATURE_EN               = 1 << 6,
-       IB_QP_CREATE_USE_GFP_NOIO               = 1 << 7,
+       /* FREE                                 = 1 << 7, */
        IB_QP_CREATE_SCATTER_FCS                = 1 << 8,
        IB_QP_CREATE_CVLAN_STRIPPING            = 1 << 9,
        /* reserve bits 26-31 for low level drivers' internal use */
@@ -2948,6 +2948,22 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
                           struct ib_qp_init_attr *qp_init_attr);
 
 /**
+ * ib_modify_qp_with_udata - Modifies the attributes for the specified QP.
+ * @qp: The QP to modify.
+ * @attr: On input, specifies the QP attributes to modify.  On output,
+ *   the current values of selected QP attributes are returned.
+ * @attr_mask: A bit-mask used to specify which attributes of the QP
+ *   are being modified.
+ * @udata: pointer to user's input output buffer information
+ *   are being modified.
+ * It returns 0 on success and returns appropriate error code on error.
+ */
+int ib_modify_qp_with_udata(struct ib_qp *qp,
+                           struct ib_qp_attr *attr,
+                           int attr_mask,
+                           struct ib_udata *udata);
+
+/**
  * ib_modify_qp - Modifies the attributes for the specified QP and then
  *   transitions the QP to the given state.
  * @qp: The QP to modify.
index 4878aaf..55af692 100644 (file)
@@ -229,8 +229,7 @@ struct rvt_driver_provided {
         * ERR_PTR(err).  The driver is free to return NULL or a valid
         * pointer.
         */
-       void * (*qp_priv_alloc)(struct rvt_dev_info *rdi, struct rvt_qp *qp,
-                               gfp_t gfp);
+       void * (*qp_priv_alloc)(struct rvt_dev_info *rdi, struct rvt_qp *qp);
 
        /*
         * Free the driver's private qp structure.
@@ -319,7 +318,7 @@ struct rvt_driver_provided {
 
        /* Let the driver pick the next queue pair number*/
        int (*alloc_qpn)(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt,
-                        enum ib_qp_type type, u8 port_num, gfp_t gfp);
+                        enum ib_qp_type type, u8 port_num);
 
        /* Determine if its safe or allowed to modify the qp */
        int (*check_modify_qp)(struct rvt_qp *qp, struct ib_qp_attr *attr,
index be6472e..d664d2e 100644 (file)
@@ -647,6 +647,20 @@ static inline u32 rvt_div_mtu(struct rvt_qp *qp, u32 len)
        return len >> qp->log_pmtu;
 }
 
+/**
+ * rvt_timeout_to_jiffies - Convert a ULP timeout input into jiffies
+ * @timeout - timeout input(0 - 31).
+ *
+ * Return a timeout value in jiffies.
+ */
+static inline unsigned long rvt_timeout_to_jiffies(u8 timeout)
+{
+       if (timeout > 31)
+               timeout = 31;
+
+       return usecs_to_jiffies(1U << timeout) * 4096UL / 1000UL;
+}
+
 extern const int  ib_rvt_state_ops[];
 
 struct rvt_dev_info;
index 8260700..8c285d9 100644 (file)
 #define READ_32                      0x09
 #define VERIFY_32            0x0a
 #define WRITE_32             0x0b
+#define WRITE_VERIFY_32              0x0c
 #define WRITE_SAME_32        0x0d
 #define ATA_32               0x1ff0
 
index 5f17fb7..0ca1fb0 100644 (file)
@@ -66,6 +66,14 @@ struct sock;
 #define TA_DEFAULT_FABRIC_PROT_TYPE    0
 /* TPG status needs to be enabled to return sendtargets discovery endpoint info */
 #define TA_DEFAULT_TPG_ENABLED_SENDTARGETS 1
+/*
+ * Used to control the sending of keys with optional to respond state bit,
+ * as a workaround for non RFC compliant initiators,that do not propose,
+ * nor respond to specific keys required for login to complete.
+ *
+ * See iscsi_check_proposer_for_optional_reply() for more details.
+ */
+#define TA_DEFAULT_LOGIN_KEYS_WORKAROUND 1
 
 #define ISCSI_IOV_DATA_BUFFER          5
 
@@ -560,7 +568,6 @@ struct iscsi_conn {
 #define LOGIN_FLAGS_INITIAL_PDU                8
        unsigned long           login_flags;
        struct delayed_work     login_work;
-       struct delayed_work     login_cleanup_work;
        struct iscsi_login      *login;
        struct timer_list       nopin_timer;
        struct timer_list       nopin_response_timer;
@@ -769,6 +776,7 @@ struct iscsi_tpg_attrib {
        u8                      t10_pi;
        u32                     fabric_prot_type;
        u32                     tpg_enabled_sendtargets;
+       u32                     login_keys_workaround;
        struct iscsi_portal_group *tpg;
 };
 
index e475531..e150e39 100644 (file)
@@ -2,6 +2,7 @@
 #define TARGET_CORE_BACKEND_H
 
 #include <linux/types.h>
+#include <asm/unaligned.h>
 #include <target/target_core_base.h>
 
 #define TRANSPORT_FLAG_PASSTHROUGH             0x1
@@ -29,16 +30,13 @@ struct target_backend_ops {
 
        struct se_device *(*alloc_device)(struct se_hba *, const char *);
        int (*configure_device)(struct se_device *);
+       void (*destroy_device)(struct se_device *);
        void (*free_device)(struct se_device *device);
 
        ssize_t (*set_configfs_dev_params)(struct se_device *,
                                           const char *, ssize_t);
        ssize_t (*show_configfs_dev_params)(struct se_device *, char *);
 
-       void (*transport_complete)(struct se_cmd *cmd,
-                                  struct scatterlist *,
-                                  unsigned char *);
-
        sense_reason_t (*parse_cdb)(struct se_cmd *cmd);
        u32 (*get_device_type)(struct se_device *);
        sector_t (*get_blocks)(struct se_device *);
@@ -71,6 +69,8 @@ void  target_backend_unregister(const struct target_backend_ops *);
 void   target_complete_cmd(struct se_cmd *, u8);
 void   target_complete_cmd_with_length(struct se_cmd *, u8, int);
 
+void   transport_copy_sense_to_cmd(struct se_cmd *, unsigned char *);
+
 sense_reason_t spc_parse_cdb(struct se_cmd *cmd, unsigned int *size);
 sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd);
 sense_reason_t spc_emulate_inquiry_std(struct se_cmd *, unsigned char *);
@@ -104,9 +104,18 @@ bool       target_lun_is_rdonly(struct se_cmd *);
 sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd,
        sense_reason_t (*exec_cmd)(struct se_cmd *cmd));
 
+struct se_device *target_find_device(int id, bool do_depend);
+
 bool target_sense_desc_format(struct se_device *dev);
 sector_t target_to_linux_sector(struct se_device *dev, sector_t lb);
 bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
                                       struct request_queue *q);
 
+
+/* Only use get_unaligned_be24() if reading p - 1 is allowed. */
+static inline uint32_t get_unaligned_be24(const uint8_t *const p)
+{
+       return get_unaligned_be32(p - 1) & 0xffffffU;
+}
+
 #endif /* TARGET_CORE_BACKEND_H */
index 0c1dce2..516764f 100644 (file)
@@ -188,7 +188,8 @@ enum target_sc_flags_table {
        TARGET_SCF_BIDI_OP              = 0x01,
        TARGET_SCF_ACK_KREF             = 0x02,
        TARGET_SCF_UNKNOWN_SIZE         = 0x04,
-       TARGET_SCF_USE_CPUID    = 0x08,
+       TARGET_SCF_USE_CPUID            = 0x08,
+       TARGET_SCF_LOOKUP_LUN_FROM_TAG  = 0x10,
 };
 
 /* fabric independent task management function values */
@@ -218,7 +219,6 @@ enum tcm_tmrsp_table {
  */
 typedef enum {
        SCSI_INST_INDEX,
-       SCSI_DEVICE_INDEX,
        SCSI_AUTH_INTR_INDEX,
        SCSI_INDEX_TYPE_MAX
 } scsi_index_t;
@@ -701,8 +701,6 @@ struct scsi_port_stats {
 
 struct se_lun {
        u64                     unpacked_lun;
-#define SE_LUN_LINK_MAGIC                      0xffff7771
-       u32                     lun_link_magic;
        bool                    lun_shutdown;
        bool                    lun_access_ro;
        u32                     lun_index;
@@ -746,8 +744,6 @@ struct se_dev_stat_grps {
 };
 
 struct se_device {
-#define SE_DEV_LINK_MAGIC                      0xfeeddeef
-       u32                     dev_link_magic;
        /* RELATIVE TARGET PORT IDENTIFER Counter */
        u16                     dev_rpti_counter;
        /* Used for SAM Task Attribute ordering */
@@ -800,7 +796,6 @@ struct se_device {
        struct list_head        delayed_cmd_list;
        struct list_head        state_list;
        struct list_head        qf_cmd_list;
-       struct list_head        g_dev_node;
        /* Pointer to associated SE HBA */
        struct se_hba           *se_hba;
        /* T10 Inquiry and VPD WWN Information */
@@ -819,8 +814,6 @@ struct se_device {
        unsigned char           udev_path[SE_UDEV_PATH_LEN];
        /* Pointer to template of function pointers for transport */
        const struct target_backend_ops *transport;
-       /* Linked list for struct se_hba struct se_device list */
-       struct list_head        dev_list;
        struct se_lun           xcopy_lun;
        /* Protection Information */
        int                     prot_length;
index d7dd142..33d2e3e 100644 (file)
@@ -160,6 +160,7 @@ int target_get_sess_cmd(struct se_cmd *, bool);
 int    target_put_sess_cmd(struct se_cmd *);
 void   target_sess_cmd_list_set_waiting(struct se_session *);
 void   target_wait_for_sess_cmds(struct se_session *);
+void   target_show_cmd(const char *pfx, struct se_cmd *cmd);
 
 int    core_alua_check_nonop_delay(struct se_cmd *);
 
index 10e3663..8e50d01 100644 (file)
@@ -34,7 +34,7 @@
        {(unsigned long)__GFP_FS,               "__GFP_FS"},            \
        {(unsigned long)__GFP_COLD,             "__GFP_COLD"},          \
        {(unsigned long)__GFP_NOWARN,           "__GFP_NOWARN"},        \
-       {(unsigned long)__GFP_REPEAT,           "__GFP_REPEAT"},        \
+       {(unsigned long)__GFP_RETRY_MAYFAIL,    "__GFP_RETRY_MAYFAIL"}, \
        {(unsigned long)__GFP_NOFAIL,           "__GFP_NOFAIL"},        \
        {(unsigned long)__GFP_NORETRY,          "__GFP_NORETRY"},       \
        {(unsigned long)__GFP_COMP,             "__GFP_COMP"},          \
index 06d5f7d..14baf9f 100644 (file)
@@ -77,7 +77,7 @@
 #define TIOCGPKT       _IOR('T', 0x38, int) /* Get packet mode state */
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
-#define TIOCGPTPEER    _IOR('T', 0x41, int) /* Safely open the slave */
+#define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
 
 #define FIONCLEX       0x5450
 #define FIOCLEX                0x5451
index 7d4a594..9c041da 100644 (file)
@@ -1238,6 +1238,47 @@ struct ethtool_per_queue_op {
        char    data[];
 };
 
+/**
+ * struct ethtool_fecparam - Ethernet forward error correction(fec) parameters
+ * @cmd: Command number = %ETHTOOL_GFECPARAM or %ETHTOOL_SFECPARAM
+ * @active_fec: FEC mode which is active on porte
+ * @fec: Bitmask of supported/configured FEC modes
+ * @rsvd: Reserved for future extensions. i.e FEC bypass feature.
+ *
+ * Drivers should reject a non-zero setting of @autoneg when
+ * autoneogotiation is disabled (or not supported) for the link.
+ *
+ */
+struct ethtool_fecparam {
+       __u32   cmd;
+       /* bitmask of FEC modes */
+       __u32   active_fec;
+       __u32   fec;
+       __u32   reserved;
+};
+
+/**
+ * enum ethtool_fec_config_bits - flags definition of ethtool_fec_configuration
+ * @ETHTOOL_FEC_NONE: FEC mode configuration is not supported
+ * @ETHTOOL_FEC_AUTO: Default/Best FEC mode provided by driver
+ * @ETHTOOL_FEC_OFF: No FEC Mode
+ * @ETHTOOL_FEC_RS: Reed-Solomon Forward Error Detection mode
+ * @ETHTOOL_FEC_BASER: Base-R/Reed-Solomon Forward Error Detection mode
+ */
+enum ethtool_fec_config_bits {
+       ETHTOOL_FEC_NONE_BIT,
+       ETHTOOL_FEC_AUTO_BIT,
+       ETHTOOL_FEC_OFF_BIT,
+       ETHTOOL_FEC_RS_BIT,
+       ETHTOOL_FEC_BASER_BIT,
+};
+
+#define ETHTOOL_FEC_NONE               (1 << ETHTOOL_FEC_NONE_BIT)
+#define ETHTOOL_FEC_AUTO               (1 << ETHTOOL_FEC_AUTO_BIT)
+#define ETHTOOL_FEC_OFF                        (1 << ETHTOOL_FEC_OFF_BIT)
+#define ETHTOOL_FEC_RS                 (1 << ETHTOOL_FEC_RS_BIT)
+#define ETHTOOL_FEC_BASER              (1 << ETHTOOL_FEC_BASER_BIT)
+
 /* CMDs currently supported */
 #define ETHTOOL_GSET           0x00000001 /* DEPRECATED, Get settings.
                                            * Please use ETHTOOL_GLINKSETTINGS
@@ -1330,6 +1371,8 @@ struct ethtool_per_queue_op {
 #define ETHTOOL_SLINKSETTINGS  0x0000004d /* Set ethtool_link_settings */
 #define ETHTOOL_PHY_GTUNABLE   0x0000004e /* Get PHY tunable configuration */
 #define ETHTOOL_PHY_STUNABLE   0x0000004f /* Set PHY tunable configuration */
+#define ETHTOOL_GFECPARAM      0x00000050 /* Get FEC settings */
+#define ETHTOOL_SFECPARAM      0x00000051 /* Set FEC settings */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
@@ -1387,6 +1430,9 @@ enum ethtool_link_mode_bit_indices {
        ETHTOOL_LINK_MODE_2500baseT_Full_BIT    = 47,
        ETHTOOL_LINK_MODE_5000baseT_Full_BIT    = 48,
 
+       ETHTOOL_LINK_MODE_FEC_NONE_BIT  = 49,
+       ETHTOOL_LINK_MODE_FEC_RS_BIT    = 50,
+       ETHTOOL_LINK_MODE_FEC_BASER_BIT = 51,
 
        /* Last allowed bit for __ETHTOOL_LINK_MODE_LEGACY_MASK is bit
         * 31. Please do NOT define any SUPPORTED_* or ADVERTISED_*
@@ -1395,7 +1441,7 @@ enum ethtool_link_mode_bit_indices {
         */
 
        __ETHTOOL_LINK_MODE_LAST
-         = ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+         = ETHTOOL_LINK_MODE_FEC_BASER_BIT,
 };
 
 #define __ETHTOOL_LINK_MODE_LEGACY_MASK(base_name)     \
index 84df14b..481e103 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _UAPI_LINUX_KCMP_H
 #define _UAPI_LINUX_KCMP_H
 
+#include <linux/types.h>
+
 /* Comparison type */
 enum kcmp_type {
        KCMP_FILE,
@@ -10,8 +12,16 @@ enum kcmp_type {
        KCMP_SIGHAND,
        KCMP_IO,
        KCMP_SYSVSEM,
+       KCMP_EPOLL_TFD,
 
        KCMP_TYPES,
 };
 
+/* Slot for KCMP_EPOLL_TFD */
+struct kcmp_epoll_slot {
+       __u32 efd;              /* epoll file descriptor */
+       __u32 tfd;              /* target file number */
+       __u32 toff;             /* target offset within same numbered sequence */
+};
+
 #endif /* _UAPI_LINUX_KCMP_H */
index c0b6dfe..6cd63c1 100644 (file)
@@ -927,6 +927,8 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_S390_CMMA_MIGRATION 145
 #define KVM_CAP_PPC_FWNMI 146
 #define KVM_CAP_PPC_SMT_POSSIBLE 147
+#define KVM_CAP_HYPERV_SYNIC2 148
+#define KVM_CAP_HYPERV_VP_INDEX 149
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1351,7 +1353,7 @@ struct kvm_s390_ucas_mapping {
 /* Available with KVM_CAP_X86_SMM */
 #define KVM_SMI                   _IO(KVMIO,   0xb7)
 /* Available with KVM_CAP_S390_CMMA_MIGRATION */
-#define KVM_S390_GET_CMMA_BITS      _IOW(KVMIO, 0xb8, struct kvm_s390_cmma_log)
+#define KVM_S390_GET_CMMA_BITS      _IOWR(KVMIO, 0xb8, struct kvm_s390_cmma_log)
 #define KVM_S390_SET_CMMA_BITS      _IOW(KVMIO, 0xb9, struct kvm_s390_cmma_log)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU    (1 << 0)
index f86127a..f4fc9c9 100644 (file)
@@ -226,5 +226,22 @@ struct nlattr {
 #define NLA_ALIGN(len)         (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
 #define NLA_HDRLEN             ((int) NLA_ALIGN(sizeof(struct nlattr)))
 
+/* Generic 32 bitflags attribute content sent to the kernel.
+ *
+ * The value is a bitmap that defines the values being set
+ * The selector is a bitmask that defines which value is legit
+ *
+ * Examples:
+ *  value = 0x0, and selector = 0x1
+ *  implies we are selecting bit 1 and we want to set its value to 0.
+ *
+ *  value = 0x2, and selector = 0x2
+ *  implies we are selecting bit 2 and we want to set its value to 1.
+ *
+ */
+struct nla_bitfield32 {
+       __u32 value;
+       __u32 selector;
+};
 
 #endif /* _UAPI__LINUX_NETLINK_H */
index d148505..dab7dad 100644 (file)
@@ -683,10 +683,29 @@ struct tcamsg {
        unsigned char   tca__pad1;
        unsigned short  tca__pad2;
 };
+
+enum {
+       TCA_ROOT_UNSPEC,
+       TCA_ROOT_TAB,
+#define TCA_ACT_TAB TCA_ROOT_TAB
+#define TCAA_MAX TCA_ROOT_TAB
+       TCA_ROOT_FLAGS,
+       TCA_ROOT_COUNT,
+       TCA_ROOT_TIME_DELTA, /* in msecs */
+       __TCA_ROOT_MAX,
+#define        TCA_ROOT_MAX (__TCA_ROOT_MAX - 1)
+};
+
 #define TA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg))))
 #define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg))
-#define TCA_ACT_TAB 1 /* attr type must be >=1 */      
-#define TCAA_MAX 1
+/* tcamsg flags stored in attribute TCA_ROOT_FLAGS
+ *
+ * TCA_FLAG_LARGE_DUMP_ON user->kernel to request for larger than TCA_ACT_MAX_PRIO
+ * actions in a dump. All dump responses will contain the number of actions
+ * being dumped stored in for user app's consumption in TCA_ROOT_COUNT
+ *
+ */
+#define TCA_FLAG_LARGE_DUMP_ON         (1 << 0)
 
 /* New extended info filters for IFLA_EXT_MASK */
 #define RTEXT_FILTER_VF                (1 << 0)
similarity index 54%
rename from include/linux/rxrpc.h
rename to include/uapi/linux/rxrpc.h
index 7343f71..9656aad 100644 (file)
@@ -1,17 +1,18 @@
-/* AF_RXRPC parameters
+/* Types and definitions for AF_RXRPC.
  *
  * Copyright (C) 2007 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
+ * modify it under the terms of the GNU General Public Licence
  * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
+ * 2 of the Licence, or (at your option) any later version.
  */
 
-#ifndef _LINUX_RXRPC_H
-#define _LINUX_RXRPC_H
+#ifndef _UAPI_LINUX_RXRPC_H
+#define _UAPI_LINUX_RXRPC_H
 
+#include <linux/types.h>
 #include <linux/in.h>
 #include <linux/in6.h>
 
@@ -76,4 +77,48 @@ enum rxrpc_cmsg_type {
 #define RXRPC_SECURITY_RXGK    4       /* gssapi-based */
 #define RXRPC_SECURITY_RXK5    5       /* kerberos 5 */
 
-#endif /* _LINUX_RXRPC_H */
+/*
+ * RxRPC-level abort codes
+ */
+#define RX_CALL_DEAD           -1      /* call/conn has been inactive and is shut down */
+#define RX_INVALID_OPERATION   -2      /* invalid operation requested / attempted */
+#define RX_CALL_TIMEOUT                -3      /* call timeout exceeded */
+#define RX_EOF                 -4      /* unexpected end of data on read op */
+#define RX_PROTOCOL_ERROR      -5      /* low-level protocol error */
+#define RX_USER_ABORT          -6      /* generic user abort */
+#define RX_ADDRINUSE           -7      /* UDP port in use */
+#define RX_DEBUGI_BADTYPE      -8      /* bad debugging packet type */
+
+/*
+ * (un)marshalling abort codes (rxgen)
+ */
+#define RXGEN_CC_MARSHAL       -450
+#define RXGEN_CC_UNMARSHAL     -451
+#define RXGEN_SS_MARSHAL       -452
+#define RXGEN_SS_UNMARSHAL     -453
+#define RXGEN_DECODE           -454
+#define RXGEN_OPCODE           -455
+#define RXGEN_SS_XDRFREE       -456
+#define RXGEN_CC_XDRFREE       -457
+
+/*
+ * Rx kerberos security abort codes
+ * - unfortunately we have no generalised security abort codes to say things
+ *   like "unsupported security", so we have to use these instead and hope the
+ *   other side understands
+ */
+#define RXKADINCONSISTENCY     19270400        /* security module structure inconsistent */
+#define RXKADPACKETSHORT       19270401        /* packet too short for security challenge */
+#define RXKADLEVELFAIL         19270402        /* security level negotiation failed */
+#define RXKADTICKETLEN         19270403        /* ticket length too short or too long */
+#define RXKADOUTOFSEQUENCE     19270404        /* packet had bad sequence number */
+#define RXKADNOAUTH            19270405        /* caller not authorised */
+#define RXKADBADKEY            19270406        /* illegal key: bad parity or weak */
+#define RXKADBADTICKET         19270407        /* security object was passed a bad ticket */
+#define RXKADUNKNOWNKEY                19270408        /* ticket contained unknown key version number */
+#define RXKADEXPIRED           19270409        /* authentication expired */
+#define RXKADSEALEDINCON       19270410        /* sealed data inconsistent */
+#define RXKADDATALEN           19270411        /* user data too long */
+#define RXKADILLEGALLEVEL      19270412        /* caller not authorised to use encrypted conns */
+
+#endif /* _UAPI_LINUX_RXRPC_H */
index dd73b90..67eb903 100644 (file)
@@ -23,7 +23,7 @@
 struct semid_ds {
        struct ipc_perm sem_perm;               /* permissions .. see ipc.h */
        __kernel_time_t sem_otime;              /* last semop time */
-       __kernel_time_t sem_ctime;              /* last change time */
+       __kernel_time_t sem_ctime;              /* create/last semctl() time */
        struct sem      *sem_base;              /* ptr to first semaphore in array */
        struct sem_queue *sem_pending;          /* pending operations to be processed */
        struct sem_queue **sem_pending_last;    /* last pending operation */
index d856932..b3f346f 100644 (file)
@@ -184,14 +184,7 @@ enum
        LINUX_MIB_DELAYEDACKLOST,               /* DelayedACKLost */
        LINUX_MIB_LISTENOVERFLOWS,              /* ListenOverflows */
        LINUX_MIB_LISTENDROPS,                  /* ListenDrops */
-       LINUX_MIB_TCPPREQUEUED,                 /* TCPPrequeued */
-       LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG,     /* TCPDirectCopyFromBacklog */
-       LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE,    /* TCPDirectCopyFromPrequeue */
-       LINUX_MIB_TCPPREQUEUEDROPPED,           /* TCPPrequeueDropped */
-       LINUX_MIB_TCPHPHITS,                    /* TCPHPHits */
-       LINUX_MIB_TCPHPHITSTOUSER,              /* TCPHPHitsToUser */
        LINUX_MIB_TCPPUREACKS,                  /* TCPPureAcks */
-       LINUX_MIB_TCPHPACKS,                    /* TCPHPAcks */
        LINUX_MIB_TCPRENORECOVERY,              /* TCPRenoRecovery */
        LINUX_MIB_TCPSACKRECOVERY,              /* TCPSackRecovery */
        LINUX_MIB_TCPSACKRENEGING,              /* TCPSACKReneging */
@@ -208,14 +201,12 @@ enum
        LINUX_MIB_TCPSACKFAILURES,              /* TCPSackFailures */
        LINUX_MIB_TCPLOSSFAILURES,              /* TCPLossFailures */
        LINUX_MIB_TCPFASTRETRANS,               /* TCPFastRetrans */
-       LINUX_MIB_TCPFORWARDRETRANS,            /* TCPForwardRetrans */
        LINUX_MIB_TCPSLOWSTARTRETRANS,          /* TCPSlowStartRetrans */
        LINUX_MIB_TCPTIMEOUTS,                  /* TCPTimeouts */
        LINUX_MIB_TCPLOSSPROBES,                /* TCPLossProbes */
        LINUX_MIB_TCPLOSSPROBERECOVERY,         /* TCPLossProbeRecovery */
        LINUX_MIB_TCPRENORECOVERYFAIL,          /* TCPRenoRecoveryFail */
        LINUX_MIB_TCPSACKRECOVERYFAIL,          /* TCPSackRecoveryFail */
-       LINUX_MIB_TCPSCHEDULERFAILED,           /* TCPSchedulerFailed */
        LINUX_MIB_TCPRCVCOLLAPSED,              /* TCPRcvCollapsed */
        LINUX_MIB_TCPDSACKOLDSENT,              /* TCPDSACKOldSent */
        LINUX_MIB_TCPDSACKOFOSENT,              /* TCPDSACKOfoSent */
index af17b41..24a1c4e 100644 (file)
@@ -130,6 +130,11 @@ enum tcmu_genl_cmd {
        TCMU_CMD_UNSPEC,
        TCMU_CMD_ADDED_DEVICE,
        TCMU_CMD_REMOVED_DEVICE,
+       TCMU_CMD_RECONFIG_DEVICE,
+       TCMU_CMD_ADDED_DEVICE_DONE,
+       TCMU_CMD_REMOVED_DEVICE_DONE,
+       TCMU_CMD_RECONFIG_DEVICE_DONE,
+       TCMU_CMD_SET_FEATURES,
        __TCMU_CMD_MAX,
 };
 #define TCMU_CMD_MAX (__TCMU_CMD_MAX - 1)
@@ -138,6 +143,13 @@ enum tcmu_genl_attr {
        TCMU_ATTR_UNSPEC,
        TCMU_ATTR_DEVICE,
        TCMU_ATTR_MINOR,
+       TCMU_ATTR_PAD,
+       TCMU_ATTR_DEV_CFG,
+       TCMU_ATTR_DEV_SIZE,
+       TCMU_ATTR_WRITECACHE,
+       TCMU_ATTR_CMD_STATUS,
+       TCMU_ATTR_DEVICE_ID,
+       TCMU_ATTR_SUPP_KERN_CMD_REPLY,
        __TCMU_ATTR_MAX,
 };
 #define TCMU_ATTR_MAX (__TCMU_ATTR_MAX - 1)
index a5507c9..030e594 100644 (file)
@@ -231,6 +231,14 @@ enum {
        TCP_NLA_SNDBUF_LIMITED, /* Time (usec) limited by send buffer */
        TCP_NLA_DATA_SEGS_OUT,  /* Data pkts sent including retransmission */
        TCP_NLA_TOTAL_RETRANS,  /* Data pkts retransmitted */
+       TCP_NLA_PACING_RATE,    /* Pacing rate in bytes per second */
+       TCP_NLA_DELIVERY_RATE,  /* Delivery rate in bytes per second */
+       TCP_NLA_SND_CWND,       /* Sending congestion window */
+       TCP_NLA_REORDERING,     /* Reordering metric */
+       TCP_NLA_MIN_RTT,        /* minimum RTT */
+       TCP_NLA_RECUR_RETRANS,  /* Recurring retransmits for the current pkt */
+       TCP_NLA_DELIVERY_RATE_APP_LMT, /* delivery rate application limited ? */
+
 };
 
 /* for TCP_MD5SIG socket option */
index d2314be..a4680a5 100644 (file)
@@ -333,7 +333,7 @@ struct uac_processing_unit_descriptor {
        __u8 bDescriptorType;
        __u8 bDescriptorSubtype;
        __u8 bUnitID;
-       __u16 wProcessType;
+       __le16 wProcessType;
        __u8 bNrInPins;
        __u8 baSourceID[];
 } __attribute__ ((packed));
@@ -491,8 +491,8 @@ struct uac_format_type_ii_ext_descriptor {
        __u8 bDescriptorType;
        __u8 bDescriptorSubtype;
        __u8 bFormatType;
-       __u16 wMaxBitRate;
-       __u16 wSamplesPerFrame;
+       __le16 wMaxBitRate;
+       __le16 wSamplesPerFrame;
        __u8 bHeaderLength;
        __u8 bSideBandProtocol;
 } __attribute__((packed));
index d1767df..8906361 100644 (file)
@@ -35,3 +35,11 @@ static inline int register_xen_selfballooning(struct device *dev)
        return -ENOSYS;
 }
 #endif
+
+#ifdef CONFIG_XEN_BALLOON
+void xen_balloon_init(void);
+#else
+static inline void xen_balloon_init(void)
+{
+}
+#endif
index df58a41..052481f 100644 (file)
@@ -518,6 +518,7 @@ asmlinkage __visible void __init start_kernel(void)
        /*
         * Set up the initial canary ASAP:
         */
+       add_latent_entropy();
        boot_init_stack_canary();
 
        cgroup_init_early();
index 104926d..5b25e07 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -97,11 +97,11 @@ static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
 
 static void msg_rcu_free(struct rcu_head *head)
 {
-       struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
-       struct msg_queue *msq = ipc_rcu_to_struct(p);
+       struct kern_ipc_perm *p = container_of(head, struct kern_ipc_perm, rcu);
+       struct msg_queue *msq = container_of(p, struct msg_queue, q_perm);
 
        security_msg_queue_free(msq);
-       ipc_rcu_free(head);
+       kvfree(msq);
 }
 
 /**
@@ -114,12 +114,12 @@ static void msg_rcu_free(struct rcu_head *head)
 static int newque(struct ipc_namespace *ns, struct ipc_params *params)
 {
        struct msg_queue *msq;
-       int id, retval;
+       int retval;
        key_t key = params->key;
        int msgflg = params->flg;
 
-       msq = ipc_rcu_alloc(sizeof(*msq));
-       if (!msq)
+       msq = kvmalloc(sizeof(*msq), GFP_KERNEL);
+       if (unlikely(!msq))
                return -ENOMEM;
 
        msq->q_perm.mode = msgflg & S_IRWXUGO;
@@ -128,7 +128,7 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
        msq->q_perm.security = NULL;
        retval = security_msg_queue_alloc(msq);
        if (retval) {
-               ipc_rcu_putref(msq, ipc_rcu_free);
+               kvfree(msq);
                return retval;
        }
 
@@ -142,10 +142,10 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
        INIT_LIST_HEAD(&msq->q_senders);
 
        /* ipc_addid() locks msq upon success. */
-       id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
-       if (id < 0) {
-               ipc_rcu_putref(msq, msg_rcu_free);
-               return id;
+       retval = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
+       if (retval < 0) {
+               call_rcu(&msq->q_perm.rcu, msg_rcu_free);
+               return retval;
        }
 
        ipc_unlock_object(&msq->q_perm);
@@ -249,7 +249,7 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
                free_msg(msg);
        }
        atomic_sub(msq->q_cbytes, &ns->msg_bytes);
-       ipc_rcu_putref(msq, msg_rcu_free);
+       ipc_rcu_putref(&msq->q_perm, msg_rcu_free);
 }
 
 /*
@@ -688,7 +688,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
                /* enqueue the sender and prepare to block */
                ss_add(msq, &s, msgsz);
 
-               if (!ipc_rcu_getref(msq)) {
+               if (!ipc_rcu_getref(&msq->q_perm)) {
                        err = -EIDRM;
                        goto out_unlock0;
                }
@@ -700,7 +700,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
                rcu_read_lock();
                ipc_lock_object(&msq->q_perm);
 
-               ipc_rcu_putref(msq, msg_rcu_free);
+               ipc_rcu_putref(&msq->q_perm, msg_rcu_free);
                /* raced with RMID? */
                if (!ipc_valid_object(&msq->q_perm)) {
                        err = -EIDRM;
index 947dc23..9e70cd7 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
 #include <linux/uaccess.h>
 #include "util.h"
 
-/* One semaphore structure for each semaphore in the system. */
-struct sem {
-       int     semval;         /* current value */
-       /*
-        * PID of the process that last modified the semaphore. For
-        * Linux, specifically these are:
-        *  - semop
-        *  - semctl, via SETVAL and SETALL.
-        *  - at task exit when performing undo adjustments (see exit_sem).
-        */
-       int     sempid;
-       spinlock_t      lock;   /* spinlock for fine-grained semtimedop */
-       struct list_head pending_alter; /* pending single-sop operations */
-                                       /* that alter the semaphore */
-       struct list_head pending_const; /* pending single-sop operations */
-                                       /* that do not alter the semaphore*/
-       time_t  sem_otime;      /* candidate for sem_otime */
-} ____cacheline_aligned_in_smp;
 
 /* One queue for each sleeping process in the system. */
 struct sem_queue {
@@ -175,7 +157,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
  *     sem_array.sem_undo
  *
  * b) global or semaphore sem_lock() for read/write:
- *     sem_array.sem_base[i].pending_{const,alter}:
+ *     sem_array.sems[i].pending_{const,alter}:
  *
  * c) special:
  *     sem_undo_list.list_proc:
@@ -250,7 +232,7 @@ static void unmerge_queues(struct sem_array *sma)
         */
        list_for_each_entry_safe(q, tq, &sma->pending_alter, list) {
                struct sem *curr;
-               curr = &sma->sem_base[q->sops[0].sem_num];
+               curr = &sma->sems[q->sops[0].sem_num];
 
                list_add_tail(&q->list, &curr->pending_alter);
        }
@@ -270,7 +252,7 @@ static void merge_queues(struct sem_array *sma)
 {
        int i;
        for (i = 0; i < sma->sem_nsems; i++) {
-               struct sem *sem = sma->sem_base + i;
+               struct sem *sem = &sma->sems[i];
 
                list_splice_init(&sem->pending_alter, &sma->pending_alter);
        }
@@ -278,11 +260,11 @@ static void merge_queues(struct sem_array *sma)
 
 static void sem_rcu_free(struct rcu_head *head)
 {
-       struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
-       struct sem_array *sma = ipc_rcu_to_struct(p);
+       struct kern_ipc_perm *p = container_of(head, struct kern_ipc_perm, rcu);
+       struct sem_array *sma = container_of(p, struct sem_array, sem_perm);
 
        security_sem_free(sma);
-       ipc_rcu_free(head);
+       kvfree(sma);
 }
 
 /*
@@ -306,7 +288,7 @@ static void complexmode_enter(struct sem_array *sma)
        sma->use_global_lock = USE_GLOBAL_LOCK_HYSTERESIS;
 
        for (i = 0; i < sma->sem_nsems; i++) {
-               sem = sma->sem_base + i;
+               sem = &sma->sems[i];
                spin_lock(&sem->lock);
                spin_unlock(&sem->lock);
        }
@@ -366,7 +348,7 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
         *
         * Both facts are tracked by use_global_mode.
         */
-       sem = sma->sem_base + sops->sem_num;
+       sem = &sma->sems[sops->sem_num];
 
        /*
         * Initial check for use_global_lock. Just an optimization,
@@ -421,7 +403,7 @@ static inline void sem_unlock(struct sem_array *sma, int locknum)
                complexmode_tryleave(sma);
                ipc_unlock_object(&sma->sem_perm);
        } else {
-               struct sem *sem = sma->sem_base + locknum;
+               struct sem *sem = &sma->sems[locknum];
                spin_unlock(&sem->lock);
        }
 }
@@ -456,7 +438,7 @@ static inline struct sem_array *sem_obtain_object_check(struct ipc_namespace *ns
 static inline void sem_lock_and_putref(struct sem_array *sma)
 {
        sem_lock(sma, NULL, -1);
-       ipc_rcu_putref(sma, sem_rcu_free);
+       ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
 }
 
 static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
@@ -464,6 +446,24 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
        ipc_rmid(&sem_ids(ns), &s->sem_perm);
 }
 
+static struct sem_array *sem_alloc(size_t nsems)
+{
+       struct sem_array *sma;
+       size_t size;
+
+       if (nsems > (INT_MAX - sizeof(*sma)) / sizeof(sma->sems[0]))
+               return NULL;
+
+       size = sizeof(*sma) + nsems * sizeof(sma->sems[0]);
+       sma = kvmalloc(size, GFP_KERNEL);
+       if (unlikely(!sma))
+               return NULL;
+
+       memset(sma, 0, size);
+
+       return sma;
+}
+
 /**
  * newary - Create a new semaphore set
  * @ns: namespace
@@ -473,10 +473,8 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
  */
 static int newary(struct ipc_namespace *ns, struct ipc_params *params)
 {
-       int id;
        int retval;
        struct sem_array *sma;
-       int size;
        key_t key = params->key;
        int nsems = params->u.nsems;
        int semflg = params->flg;
@@ -487,29 +485,24 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
        if (ns->used_sems + nsems > ns->sc_semmns)
                return -ENOSPC;
 
-       size = sizeof(*sma) + nsems * sizeof(struct sem);
-       sma = ipc_rcu_alloc(size);
+       sma = sem_alloc(nsems);
        if (!sma)
                return -ENOMEM;
 
-       memset(sma, 0, size);
-
        sma->sem_perm.mode = (semflg & S_IRWXUGO);
        sma->sem_perm.key = key;
 
        sma->sem_perm.security = NULL;
        retval = security_sem_alloc(sma);
        if (retval) {
-               ipc_rcu_putref(sma, ipc_rcu_free);
+               kvfree(sma);
                return retval;
        }
 
-       sma->sem_base = (struct sem *) &sma[1];
-
        for (i = 0; i < nsems; i++) {
-               INIT_LIST_HEAD(&sma->sem_base[i].pending_alter);
-               INIT_LIST_HEAD(&sma->sem_base[i].pending_const);
-               spin_lock_init(&sma->sem_base[i].lock);
+               INIT_LIST_HEAD(&sma->sems[i].pending_alter);
+               INIT_LIST_HEAD(&sma->sems[i].pending_const);
+               spin_lock_init(&sma->sems[i].lock);
        }
 
        sma->complex_count = 0;
@@ -520,10 +513,10 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
        sma->sem_nsems = nsems;
        sma->sem_ctime = get_seconds();
 
-       id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
-       if (id < 0) {
-               ipc_rcu_putref(sma, sem_rcu_free);
-               return id;
+       retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
+       if (retval < 0) {
+               call_rcu(&sma->sem_perm.rcu, sem_rcu_free);
+               return retval;
        }
        ns->used_sems += nsems;
 
@@ -612,7 +605,7 @@ static int perform_atomic_semop_slow(struct sem_array *sma, struct sem_queue *q)
        un = q->undo;
 
        for (sop = sops; sop < sops + nsops; sop++) {
-               curr = sma->sem_base + sop->sem_num;
+               curr = &sma->sems[sop->sem_num];
                sem_op = sop->sem_op;
                result = curr->semval;
 
@@ -639,7 +632,7 @@ static int perform_atomic_semop_slow(struct sem_array *sma, struct sem_queue *q)
        sop--;
        pid = q->pid;
        while (sop >= sops) {
-               sma->sem_base[sop->sem_num].sempid = pid;
+               sma->sems[sop->sem_num].sempid = pid;
                sop--;
        }
 
@@ -661,7 +654,7 @@ undo:
        sop--;
        while (sop >= sops) {
                sem_op = sop->sem_op;
-               sma->sem_base[sop->sem_num].semval -= sem_op;
+               sma->sems[sop->sem_num].semval -= sem_op;
                if (sop->sem_flg & SEM_UNDO)
                        un->semadj[sop->sem_num] += sem_op;
                sop--;
@@ -692,7 +685,7 @@ static int perform_atomic_semop(struct sem_array *sma, struct sem_queue *q)
         * until the operations can go through.
         */
        for (sop = sops; sop < sops + nsops; sop++) {
-               curr = sma->sem_base + sop->sem_num;
+               curr = &sma->sems[sop->sem_num];
                sem_op = sop->sem_op;
                result = curr->semval;
 
@@ -716,7 +709,7 @@ static int perform_atomic_semop(struct sem_array *sma, struct sem_queue *q)
        }
 
        for (sop = sops; sop < sops + nsops; sop++) {
-               curr = sma->sem_base + sop->sem_num;
+               curr = &sma->sems[sop->sem_num];
                sem_op = sop->sem_op;
                result = curr->semval;
 
@@ -815,7 +808,7 @@ static int wake_const_ops(struct sem_array *sma, int semnum,
        if (semnum == -1)
                pending_list = &sma->pending_const;
        else
-               pending_list = &sma->sem_base[semnum].pending_const;
+               pending_list = &sma->sems[semnum].pending_const;
 
        list_for_each_entry_safe(q, tmp, pending_list, list) {
                int error = perform_atomic_semop(sma, q);
@@ -856,7 +849,7 @@ static int do_smart_wakeup_zero(struct sem_array *sma, struct sembuf *sops,
                for (i = 0; i < nsops; i++) {
                        int num = sops[i].sem_num;
 
-                       if (sma->sem_base[num].semval == 0) {
+                       if (sma->sems[num].semval == 0) {
                                got_zero = 1;
                                semop_completed |= wake_const_ops(sma, num, wake_q);
                        }
@@ -867,7 +860,7 @@ static int do_smart_wakeup_zero(struct sem_array *sma, struct sembuf *sops,
                 * Assume all were changed.
                 */
                for (i = 0; i < sma->sem_nsems; i++) {
-                       if (sma->sem_base[i].semval == 0) {
+                       if (sma->sems[i].semval == 0) {
                                got_zero = 1;
                                semop_completed |= wake_const_ops(sma, i, wake_q);
                        }
@@ -909,7 +902,7 @@ static int update_queue(struct sem_array *sma, int semnum, struct wake_q_head *w
        if (semnum == -1)
                pending_list = &sma->pending_alter;
        else
-               pending_list = &sma->sem_base[semnum].pending_alter;
+               pending_list = &sma->sems[semnum].pending_alter;
 
 again:
        list_for_each_entry_safe(q, tmp, pending_list, list) {
@@ -922,7 +915,7 @@ again:
                 * be in the  per semaphore pending queue, and decrements
                 * cannot be successful if the value is already 0.
                 */
-               if (semnum != -1 && sma->sem_base[semnum].semval == 0)
+               if (semnum != -1 && sma->sems[semnum].semval == 0)
                        break;
 
                error = perform_atomic_semop(sma, q);
@@ -959,9 +952,9 @@ again:
 static void set_semotime(struct sem_array *sma, struct sembuf *sops)
 {
        if (sops == NULL) {
-               sma->sem_base[0].sem_otime = get_seconds();
+               sma->sems[0].sem_otime = get_seconds();
        } else {
-               sma->sem_base[sops[0].sem_num].sem_otime =
+               sma->sems[sops[0].sem_num].sem_otime =
                                                        get_seconds();
        }
 }
@@ -1067,9 +1060,9 @@ static int count_semcnt(struct sem_array *sma, ushort semnum,
        semcnt = 0;
        /* First: check the simple operations. They are easy to evaluate */
        if (count_zero)
-               l = &sma->sem_base[semnum].pending_const;
+               l = &sma->sems[semnum].pending_const;
        else
-               l = &sma->sem_base[semnum].pending_alter;
+               l = &sma->sems[semnum].pending_alter;
 
        list_for_each_entry(q, l, list) {
                /* all task on a per-semaphore list sleep on exactly
@@ -1124,7 +1117,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
                wake_up_sem_queue_prepare(q, -EIDRM, &wake_q);
        }
        for (i = 0; i < sma->sem_nsems; i++) {
-               struct sem *sem = sma->sem_base + i;
+               struct sem *sem = &sma->sems[i];
                list_for_each_entry_safe(q, tq, &sem->pending_const, list) {
                        unlink_queue(sma, q);
                        wake_up_sem_queue_prepare(q, -EIDRM, &wake_q);
@@ -1142,7 +1135,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
 
        wake_up_q(&wake_q);
        ns->used_sems -= sma->sem_nsems;
-       ipc_rcu_putref(sma, sem_rcu_free);
+       ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
 }
 
 static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, int version)
@@ -1174,9 +1167,9 @@ static time_t get_semotime(struct sem_array *sma)
        int i;
        time_t res;
 
-       res = sma->sem_base[0].sem_otime;
+       res = sma->sems[0].sem_otime;
        for (i = 1; i < sma->sem_nsems; i++) {
-               time_t to = sma->sem_base[i].sem_otime;
+               time_t to = sma->sems[i].sem_otime;
 
                if (to > res)
                        res = to;
@@ -1325,7 +1318,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
                return -EIDRM;
        }
 
-       curr = &sma->sem_base[semnum];
+       curr = &sma->sems[semnum];
 
        ipc_assert_locked_object(&sma->sem_perm);
        list_for_each_entry(un, &sma->list_id, list_id)
@@ -1382,15 +1375,16 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                        goto out_unlock;
                }
                if (nsems > SEMMSL_FAST) {
-                       if (!ipc_rcu_getref(sma)) {
+                       if (!ipc_rcu_getref(&sma->sem_perm)) {
                                err = -EIDRM;
                                goto out_unlock;
                        }
                        sem_unlock(sma, -1);
                        rcu_read_unlock();
-                       sem_io = ipc_alloc(sizeof(ushort)*nsems);
+                       sem_io = kvmalloc_array(nsems, sizeof(ushort),
+                                               GFP_KERNEL);
                        if (sem_io == NULL) {
-                               ipc_rcu_putref(sma, sem_rcu_free);
+                               ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
                                return -ENOMEM;
                        }
 
@@ -1402,7 +1396,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                        }
                }
                for (i = 0; i < sma->sem_nsems; i++)
-                       sem_io[i] = sma->sem_base[i].semval;
+                       sem_io[i] = sma->sems[i].semval;
                sem_unlock(sma, -1);
                rcu_read_unlock();
                err = 0;
@@ -1415,29 +1409,30 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                int i;
                struct sem_undo *un;
 
-               if (!ipc_rcu_getref(sma)) {
+               if (!ipc_rcu_getref(&sma->sem_perm)) {
                        err = -EIDRM;
                        goto out_rcu_wakeup;
                }
                rcu_read_unlock();
 
                if (nsems > SEMMSL_FAST) {
-                       sem_io = ipc_alloc(sizeof(ushort)*nsems);
+                       sem_io = kvmalloc_array(nsems, sizeof(ushort),
+                                               GFP_KERNEL);
                        if (sem_io == NULL) {
-                               ipc_rcu_putref(sma, sem_rcu_free);
+                               ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
                                return -ENOMEM;
                        }
                }
 
                if (copy_from_user(sem_io, p, nsems*sizeof(ushort))) {
-                       ipc_rcu_putref(sma, sem_rcu_free);
+                       ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
                        err = -EFAULT;
                        goto out_free;
                }
 
                for (i = 0; i < nsems; i++) {
                        if (sem_io[i] > SEMVMX) {
-                               ipc_rcu_putref(sma, sem_rcu_free);
+                               ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
                                err = -ERANGE;
                                goto out_free;
                        }
@@ -1450,8 +1445,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                }
 
                for (i = 0; i < nsems; i++) {
-                       sma->sem_base[i].semval = sem_io[i];
-                       sma->sem_base[i].sempid = task_tgid_vnr(current);
+                       sma->sems[i].semval = sem_io[i];
+                       sma->sems[i].sempid = task_tgid_vnr(current);
                }
 
                ipc_assert_locked_object(&sma->sem_perm);
@@ -1476,7 +1471,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                err = -EIDRM;
                goto out_unlock;
        }
-       curr = &sma->sem_base[semnum];
+       curr = &sma->sems[semnum];
 
        switch (cmd) {
        case GETVAL:
@@ -1500,7 +1495,7 @@ out_rcu_wakeup:
        wake_up_q(&wake_q);
 out_free:
        if (sem_io != fast_sem_io)
-               ipc_free(sem_io);
+               kvfree(sem_io);
        return err;
 }
 
@@ -1719,7 +1714,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        }
 
        nsems = sma->sem_nsems;
-       if (!ipc_rcu_getref(sma)) {
+       if (!ipc_rcu_getref(&sma->sem_perm)) {
                rcu_read_unlock();
                un = ERR_PTR(-EIDRM);
                goto out;
@@ -1729,7 +1724,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        /* step 2: allocate new undo structure */
        new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
        if (!new) {
-               ipc_rcu_putref(sma, sem_rcu_free);
+               ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -1932,7 +1927,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
         */
        if (nsops == 1) {
                struct sem *curr;
-               curr = &sma->sem_base[sops->sem_num];
+               curr = &sma->sems[sops->sem_num];
 
                if (alter) {
                        if (sma->complex_count) {
@@ -2146,7 +2141,7 @@ void exit_sem(struct task_struct *tsk)
 
                /* perform adjustments registered in un */
                for (i = 0; i < sma->sem_nsems; i++) {
-                       struct sem *semaphore = &sma->sem_base[i];
+                       struct sem *semaphore = &sma->sems[i];
                        if (un->semadj[i]) {
                                semaphore->semval += un->semadj[i];
                                /*
index f45c795..28a4448 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -174,11 +174,12 @@ static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
 
 static void shm_rcu_free(struct rcu_head *head)
 {
-       struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
-       struct shmid_kernel *shp = ipc_rcu_to_struct(p);
-
+       struct kern_ipc_perm *ptr = container_of(head, struct kern_ipc_perm,
+                                                       rcu);
+       struct shmid_kernel *shp = container_of(ptr, struct shmid_kernel,
+                                                       shm_perm);
        security_shm_free(shp);
-       ipc_rcu_free(head);
+       kvfree(shp);
 }
 
 static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
@@ -241,7 +242,7 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
                user_shm_unlock(i_size_read(file_inode(shm_file)),
                                shp->mlock_user);
        fput(shm_file);
-       ipc_rcu_putref(shp, shm_rcu_free);
+       ipc_rcu_putref(&shp->shm_perm, shm_rcu_free);
 }
 
 /*
@@ -529,7 +530,6 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
        size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
        struct file *file;
        char name[13];
-       int id;
        vm_flags_t acctflag = 0;
 
        if (size < SHMMIN || size > ns->shm_ctlmax)
@@ -542,8 +542,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
                        ns->shm_tot + numpages > ns->shm_ctlall)
                return -ENOSPC;
 
-       shp = ipc_rcu_alloc(sizeof(*shp));
-       if (!shp)
+       shp = kvmalloc(sizeof(*shp), GFP_KERNEL);
+       if (unlikely(!shp))
                return -ENOMEM;
 
        shp->shm_perm.key = key;
@@ -553,7 +553,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
        shp->shm_perm.security = NULL;
        error = security_shm_alloc(shp);
        if (error) {
-               ipc_rcu_putref(shp, ipc_rcu_free);
+               kvfree(shp);
                return error;
        }
 
@@ -598,11 +598,9 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
        shp->shm_file = file;
        shp->shm_creator = current;
 
-       id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
-       if (id < 0) {
-               error = id;
+       error = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
+       if (error < 0)
                goto no_id;
-       }
 
        list_add(&shp->shm_clist, &current->sysvshm.shm_clist);
 
@@ -624,7 +622,7 @@ no_id:
                user_shm_unlock(size, shp->mlock_user);
        fput(file);
 no_file:
-       ipc_rcu_putref(shp, shm_rcu_free);
+       call_rcu(&shp->shm_perm.rcu, shm_rcu_free);
        return error;
 }
 
index caec7b1..1a2cb02 100644 (file)
@@ -232,6 +232,7 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size)
 
        idr_preload(GFP_KERNEL);
 
+       atomic_set(&new->refcount, 1);
        spin_lock_init(&new->lock);
        new->deleted = false;
        rcu_read_lock();
@@ -394,70 +395,18 @@ void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
        ipcp->deleted = true;
 }
 
-/**
- * ipc_alloc - allocate ipc space
- * @size: size desired
- *
- * Allocate memory from the appropriate pools and return a pointer to it.
- * NULL is returned if the allocation fails
- */
-void *ipc_alloc(int size)
-{
-       return kvmalloc(size, GFP_KERNEL);
-}
-
-/**
- * ipc_free - free ipc space
- * @ptr: pointer returned by ipc_alloc
- *
- * Free a block created with ipc_alloc().
- */
-void ipc_free(void *ptr)
+int ipc_rcu_getref(struct kern_ipc_perm *ptr)
 {
-       kvfree(ptr);
+       return atomic_inc_not_zero(&ptr->refcount);
 }
 
-/**
- * ipc_rcu_alloc - allocate ipc and rcu space
- * @size: size desired
- *
- * Allocate memory for the rcu header structure +  the object.
- * Returns the pointer to the object or NULL upon failure.
- */
-void *ipc_rcu_alloc(int size)
+void ipc_rcu_putref(struct kern_ipc_perm *ptr,
+                       void (*func)(struct rcu_head *head))
 {
-       /*
-        * We prepend the allocation with the rcu struct
-        */
-       struct ipc_rcu *out = ipc_alloc(sizeof(struct ipc_rcu) + size);
-       if (unlikely(!out))
-               return NULL;
-       atomic_set(&out->refcount, 1);
-       return out + 1;
-}
-
-int ipc_rcu_getref(void *ptr)
-{
-       struct ipc_rcu *p = ((struct ipc_rcu *)ptr) - 1;
-
-       return atomic_inc_not_zero(&p->refcount);
-}
-
-void ipc_rcu_putref(void *ptr, void (*func)(struct rcu_head *head))
-{
-       struct ipc_rcu *p = ((struct ipc_rcu *)ptr) - 1;
-
-       if (!atomic_dec_and_test(&p->refcount))
+       if (!atomic_dec_and_test(&ptr->refcount))
                return;
 
-       call_rcu(&p->rcu, func);
-}
-
-void ipc_rcu_free(struct rcu_head *head)
-{
-       struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
-
-       kvfree(p);
+       call_rcu(&ptr->rcu, func);
 }
 
 /**
index 60ddccc..c692010 100644 (file)
@@ -47,13 +47,6 @@ static inline void msg_exit_ns(struct ipc_namespace *ns) { }
 static inline void shm_exit_ns(struct ipc_namespace *ns) { }
 #endif
 
-struct ipc_rcu {
-       struct rcu_head rcu;
-       atomic_t refcount;
-} ____cacheline_aligned_in_smp;
-
-#define ipc_rcu_to_struct(p)  ((void *)(p+1))
-
 /*
  * Structure that holds the parameters needed by the ipc operations
  * (see after)
@@ -114,22 +107,18 @@ void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *);
 /* must be called with ipcp locked */
 int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg);
 
-/* for rare, potentially huge allocations.
- * both function can sleep
- */
-void *ipc_alloc(int size);
-void ipc_free(void *ptr);
-
 /*
  * For allocation that need to be freed by RCU.
  * Objects are reference counted, they start with reference count 1.
  * getref increases the refcount, the putref call that reduces the recount
  * to 0 schedules the rcu destruction. Caller must guarantee locking.
+ *
+ * refcount is initialized by ipc_addid(), before that point call_rcu()
+ * must be used.
  */
-void *ipc_rcu_alloc(int size);
-int ipc_rcu_getref(void *ptr);
-void ipc_rcu_putref(void *ptr, void (*func)(struct rcu_head *head));
-void ipc_rcu_free(struct rcu_head *head);
+int ipc_rcu_getref(struct kern_ipc_perm *ptr);
+void ipc_rcu_putref(struct kern_ipc_perm *ptr,
+                       void (*func)(struct rcu_head *head));
 
 struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
 struct kern_ipc_perm *ipc_obtain_object_idr(struct ipc_ids *ids, int id);
index 72aa080..4cb8e8b 100644 (file)
@@ -82,7 +82,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_KGDB) += debug/
 obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o
 obj-$(CONFIG_LOCKUP_DETECTOR) += watchdog.o
-obj-$(CONFIG_HARDLOCKUP_DETECTOR) += watchdog_hld.o
+obj-$(CONFIG_HARDLOCKUP_DETECTOR_PERF) += watchdog_hld.o
 obj-$(CONFIG_SECCOMP) += seccomp.o
 obj-$(CONFIG_RELAY) += relay.o
 obj-$(CONFIG_SYSCTL) += utsname_sysctl.o
index 833267b..6dd5569 100644 (file)
@@ -641,6 +641,7 @@ static int auditd_send_unicast_skb(struct sk_buff *skb)
        ac = rcu_dereference(auditd_conn);
        if (!ac) {
                rcu_read_unlock();
+               kfree_skb(skb);
                rc = -ECONNREFUSED;
                goto err;
        }
index 899364d..d439ee0 100644 (file)
@@ -114,6 +114,7 @@ static struct bpf_map *dev_map_alloc(union bpf_attr *attr)
        if (err)
                goto free_dtab;
 
+       err = -ENOMEM;
        /* A per cpu bitfield with a bit per possible net device */
        dtab->flush_needed = __alloc_percpu(
                                BITS_TO_LONGS(attr->max_entries) *
index 9bbd334..e833ed9 100644 (file)
@@ -377,10 +377,22 @@ static void bpf_evict_inode(struct inode *inode)
                bpf_any_put(inode->i_private, type);
 }
 
+/*
+ * Display the mount options in /proc/mounts.
+ */
+static int bpf_show_options(struct seq_file *m, struct dentry *root)
+{
+       umode_t mode = d_inode(root)->i_mode & S_IALLUGO & ~S_ISVTX;
+
+       if (mode != S_IRWXUGO)
+               seq_printf(m, ",mode=%o", mode);
+       return 0;
+}
+
 static const struct super_operations bpf_super_ops = {
        .statfs         = simple_statfs,
        .drop_inode     = generic_delete_inode,
-       .show_options   = generic_show_options,
+       .show_options   = bpf_show_options,
        .evict_inode    = bpf_evict_inode,
 };
 
@@ -434,8 +446,6 @@ static int bpf_fill_super(struct super_block *sb, void *data, int silent)
        struct inode *inode;
        int ret;
 
-       save_mount_options(sb, data);
-
        ret = bpf_parse_options(data, &opts);
        if (ret)
                return ret;
index 045646d..6c772ad 100644 (file)
@@ -1289,7 +1289,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
        info_len = min_t(u32, sizeof(info), info_len);
 
        if (copy_from_user(&info, uinfo, info_len))
-               return err;
+               return -EFAULT;
 
        info.type = prog->type;
        info.id = prog->aux->id;
@@ -1312,7 +1312,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
        }
 
        ulen = info.xlated_prog_len;
-       info.xlated_prog_len = bpf_prog_size(prog->len);
+       info.xlated_prog_len = bpf_prog_insn_size(prog);
        if (info.xlated_prog_len && ulen) {
                uinsns = u64_to_user_ptr(info.xlated_prog_insns);
                ulen = min_t(u32, info.xlated_prog_len, ulen);
index ebe9b38..f6e8b38 100644 (file)
@@ -504,6 +504,7 @@ static void reset_reg_range_values(struct bpf_reg_state *regs, u32 regno)
 {
        regs[regno].min_value = BPF_REGISTER_MIN_RANGE;
        regs[regno].max_value = BPF_REGISTER_MAX_RANGE;
+       regs[regno].value_from_signed = false;
        regs[regno].min_align = 0;
 }
 
@@ -777,12 +778,13 @@ static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off,
        return -EACCES;
 }
 
-static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
+static bool __is_pointer_value(bool allow_ptr_leaks,
+                              const struct bpf_reg_state *reg)
 {
-       if (env->allow_ptr_leaks)
+       if (allow_ptr_leaks)
                return false;
 
-       switch (env->cur_state.regs[regno].type) {
+       switch (reg->type) {
        case UNKNOWN_VALUE:
        case CONST_IMM:
                return false;
@@ -791,6 +793,11 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
        }
 }
 
+static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
+{
+       return __is_pointer_value(env->allow_ptr_leaks, &env->cur_state.regs[regno]);
+}
+
 static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg,
                                   int off, int size, bool strict)
 {
@@ -1844,10 +1851,24 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,
        dst_align = dst_reg->min_align;
 
        /* We don't know anything about what was done to this register, mark it
-        * as unknown.
+        * as unknown. Also, if both derived bounds came from signed/unsigned
+        * mixed compares and one side is unbounded, we cannot really do anything
+        * with them as boundaries cannot be trusted. Thus, arithmetic of two
+        * regs of such kind will get invalidated bounds on the dst side.
         */
-       if (min_val == BPF_REGISTER_MIN_RANGE &&
-           max_val == BPF_REGISTER_MAX_RANGE) {
+       if ((min_val == BPF_REGISTER_MIN_RANGE &&
+            max_val == BPF_REGISTER_MAX_RANGE) ||
+           (BPF_SRC(insn->code) == BPF_X &&
+            ((min_val != BPF_REGISTER_MIN_RANGE &&
+              max_val == BPF_REGISTER_MAX_RANGE) ||
+             (min_val == BPF_REGISTER_MIN_RANGE &&
+              max_val != BPF_REGISTER_MAX_RANGE) ||
+             (dst_reg->min_value != BPF_REGISTER_MIN_RANGE &&
+              dst_reg->max_value == BPF_REGISTER_MAX_RANGE) ||
+             (dst_reg->min_value == BPF_REGISTER_MIN_RANGE &&
+              dst_reg->max_value != BPF_REGISTER_MAX_RANGE)) &&
+            regs[insn->dst_reg].value_from_signed !=
+            regs[insn->src_reg].value_from_signed)) {
                reset_reg_range_values(regs, insn->dst_reg);
                return;
        }
@@ -1856,10 +1877,12 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,
         * do our normal operations to the register, we need to set the values
         * to the min/max since they are undefined.
         */
-       if (min_val == BPF_REGISTER_MIN_RANGE)
-               dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
-       if (max_val == BPF_REGISTER_MAX_RANGE)
-               dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
+       if (opcode != BPF_SUB) {
+               if (min_val == BPF_REGISTER_MIN_RANGE)
+                       dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
+               if (max_val == BPF_REGISTER_MAX_RANGE)
+                       dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
+       }
 
        switch (opcode) {
        case BPF_ADD:
@@ -1870,10 +1893,17 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,
                dst_reg->min_align = min(src_align, dst_align);
                break;
        case BPF_SUB:
+               /* If one of our values was at the end of our ranges, then the
+                * _opposite_ value in the dst_reg goes to the end of our range.
+                */
+               if (min_val == BPF_REGISTER_MIN_RANGE)
+                       dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
+               if (max_val == BPF_REGISTER_MAX_RANGE)
+                       dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
                if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
-                       dst_reg->min_value -= min_val;
+                       dst_reg->min_value -= max_val;
                if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
-                       dst_reg->max_value -= max_val;
+                       dst_reg->max_value -= min_val;
                dst_reg->min_align = min(src_align, dst_align);
                break;
        case BPF_MUL:
@@ -2035,6 +2065,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
                        regs[insn->dst_reg].max_value = insn->imm;
                        regs[insn->dst_reg].min_value = insn->imm;
                        regs[insn->dst_reg].min_align = calc_align(insn->imm);
+                       regs[insn->dst_reg].value_from_signed = false;
                }
 
        } else if (opcode > BPF_END) {
@@ -2210,40 +2241,63 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
                            struct bpf_reg_state *false_reg, u64 val,
                            u8 opcode)
 {
+       bool value_from_signed = true;
+       bool is_range = true;
+
        switch (opcode) {
        case BPF_JEQ:
                /* If this is false then we know nothing Jon Snow, but if it is
                 * true then we know for sure.
                 */
                true_reg->max_value = true_reg->min_value = val;
+               is_range = false;
                break;
        case BPF_JNE:
                /* If this is true we know nothing Jon Snow, but if it is false
                 * we know the value for sure;
                 */
                false_reg->max_value = false_reg->min_value = val;
+               is_range = false;
                break;
        case BPF_JGT:
-               /* Unsigned comparison, the minimum value is 0. */
-               false_reg->min_value = 0;
+               value_from_signed = false;
                /* fallthrough */
        case BPF_JSGT:
+               if (true_reg->value_from_signed != value_from_signed)
+                       reset_reg_range_values(true_reg, 0);
+               if (false_reg->value_from_signed != value_from_signed)
+                       reset_reg_range_values(false_reg, 0);
+               if (opcode == BPF_JGT) {
+                       /* Unsigned comparison, the minimum value is 0. */
+                       false_reg->min_value = 0;
+               }
                /* If this is false then we know the maximum val is val,
                 * otherwise we know the min val is val+1.
                 */
                false_reg->max_value = val;
+               false_reg->value_from_signed = value_from_signed;
                true_reg->min_value = val + 1;
+               true_reg->value_from_signed = value_from_signed;
                break;
        case BPF_JGE:
-               /* Unsigned comparison, the minimum value is 0. */
-               false_reg->min_value = 0;
+               value_from_signed = false;
                /* fallthrough */
        case BPF_JSGE:
+               if (true_reg->value_from_signed != value_from_signed)
+                       reset_reg_range_values(true_reg, 0);
+               if (false_reg->value_from_signed != value_from_signed)
+                       reset_reg_range_values(false_reg, 0);
+               if (opcode == BPF_JGE) {
+                       /* Unsigned comparison, the minimum value is 0. */
+                       false_reg->min_value = 0;
+               }
                /* If this is false then we know the maximum value is val - 1,
                 * otherwise we know the mimimum value is val.
                 */
                false_reg->max_value = val - 1;
+               false_reg->value_from_signed = value_from_signed;
                true_reg->min_value = val;
+               true_reg->value_from_signed = value_from_signed;
                break;
        default:
                break;
@@ -2251,6 +2305,12 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
 
        check_reg_overflow(false_reg);
        check_reg_overflow(true_reg);
+       if (is_range) {
+               if (__is_pointer_value(false, false_reg))
+                       reset_reg_range_values(false_reg, 0);
+               if (__is_pointer_value(false, true_reg))
+                       reset_reg_range_values(true_reg, 0);
+       }
 }
 
 /* Same as above, but for the case that dst_reg is a CONST_IMM reg and src_reg
@@ -2260,41 +2320,64 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg,
                                struct bpf_reg_state *false_reg, u64 val,
                                u8 opcode)
 {
+       bool value_from_signed = true;
+       bool is_range = true;
+
        switch (opcode) {
        case BPF_JEQ:
                /* If this is false then we know nothing Jon Snow, but if it is
                 * true then we know for sure.
                 */
                true_reg->max_value = true_reg->min_value = val;
+               is_range = false;
                break;
        case BPF_JNE:
                /* If this is true we know nothing Jon Snow, but if it is false
                 * we know the value for sure;
                 */
                false_reg->max_value = false_reg->min_value = val;
+               is_range = false;
                break;
        case BPF_JGT:
-               /* Unsigned comparison, the minimum value is 0. */
-               true_reg->min_value = 0;
+               value_from_signed = false;
                /* fallthrough */
        case BPF_JSGT:
+               if (true_reg->value_from_signed != value_from_signed)
+                       reset_reg_range_values(true_reg, 0);
+               if (false_reg->value_from_signed != value_from_signed)
+                       reset_reg_range_values(false_reg, 0);
+               if (opcode == BPF_JGT) {
+                       /* Unsigned comparison, the minimum value is 0. */
+                       true_reg->min_value = 0;
+               }
                /*
                 * If this is false, then the val is <= the register, if it is
                 * true the register <= to the val.
                 */
                false_reg->min_value = val;
+               false_reg->value_from_signed = value_from_signed;
                true_reg->max_value = val - 1;
+               true_reg->value_from_signed = value_from_signed;
                break;
        case BPF_JGE:
-               /* Unsigned comparison, the minimum value is 0. */
-               true_reg->min_value = 0;
+               value_from_signed = false;
                /* fallthrough */
        case BPF_JSGE:
+               if (true_reg->value_from_signed != value_from_signed)
+                       reset_reg_range_values(true_reg, 0);
+               if (false_reg->value_from_signed != value_from_signed)
+                       reset_reg_range_values(false_reg, 0);
+               if (opcode == BPF_JGE) {
+                       /* Unsigned comparison, the minimum value is 0. */
+                       true_reg->min_value = 0;
+               }
                /* If this is false then constant < register, if it is true then
                 * the register < constant.
                 */
                false_reg->min_value = val + 1;
+               false_reg->value_from_signed = value_from_signed;
                true_reg->max_value = val;
+               true_reg->value_from_signed = value_from_signed;
                break;
        default:
                break;
@@ -2302,6 +2385,12 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg,
 
        check_reg_overflow(false_reg);
        check_reg_overflow(true_reg);
+       if (is_range) {
+               if (__is_pointer_value(false, false_reg))
+                       reset_reg_range_values(false_reg, 0);
+               if (__is_pointer_value(false, true_reg))
+                       reset_reg_range_values(true_reg, 0);
+       }
 }
 
 static void mark_map_reg(struct bpf_reg_state *regs, u32 regno, u32 id,
index 793565c..8b4c3c2 100644 (file)
@@ -33,6 +33,9 @@ struct cgroup_taskset {
        struct list_head        src_csets;
        struct list_head        dst_csets;
 
+       /* the number of tasks in the set */
+       int                     nr_tasks;
+
        /* the subsys currently being processed */
        int                     ssid;
 
index 620794a..df2e0f1 100644 (file)
@@ -2006,6 +2006,8 @@ static void cgroup_migrate_add_task(struct task_struct *task,
        if (!cset->mg_src_cgrp)
                return;
 
+       mgctx->tset.nr_tasks++;
+
        list_move_tail(&task->cg_list, &cset->mg_tasks);
        if (list_empty(&cset->mg_node))
                list_add_tail(&cset->mg_node,
@@ -2094,21 +2096,19 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
        struct css_set *cset, *tmp_cset;
        int ssid, failed_ssid, ret;
 
-       /* methods shouldn't be called if no task is actually migrating */
-       if (list_empty(&tset->src_csets))
-               return 0;
-
        /* check that we can legitimately attach to the cgroup */
-       do_each_subsys_mask(ss, ssid, mgctx->ss_mask) {
-               if (ss->can_attach) {
-                       tset->ssid = ssid;
-                       ret = ss->can_attach(tset);
-                       if (ret) {
-                               failed_ssid = ssid;
-                               goto out_cancel_attach;
+       if (tset->nr_tasks) {
+               do_each_subsys_mask(ss, ssid, mgctx->ss_mask) {
+                       if (ss->can_attach) {
+                               tset->ssid = ssid;
+                               ret = ss->can_attach(tset);
+                               if (ret) {
+                                       failed_ssid = ssid;
+                                       goto out_cancel_attach;
+                               }
                        }
-               }
-       } while_each_subsys_mask();
+               } while_each_subsys_mask();
+       }
 
        /*
         * Now that we're guaranteed success, proceed to move all tasks to
@@ -2137,25 +2137,29 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
         */
        tset->csets = &tset->dst_csets;
 
-       do_each_subsys_mask(ss, ssid, mgctx->ss_mask) {
-               if (ss->attach) {
-                       tset->ssid = ssid;
-                       ss->attach(tset);
-               }
-       } while_each_subsys_mask();
+       if (tset->nr_tasks) {
+               do_each_subsys_mask(ss, ssid, mgctx->ss_mask) {
+                       if (ss->attach) {
+                               tset->ssid = ssid;
+                               ss->attach(tset);
+                       }
+               } while_each_subsys_mask();
+       }
 
        ret = 0;
        goto out_release_tset;
 
 out_cancel_attach:
-       do_each_subsys_mask(ss, ssid, mgctx->ss_mask) {
-               if (ssid == failed_ssid)
-                       break;
-               if (ss->cancel_attach) {
-                       tset->ssid = ssid;
-                       ss->cancel_attach(tset);
-               }
-       } while_each_subsys_mask();
+       if (tset->nr_tasks) {
+               do_each_subsys_mask(ss, ssid, mgctx->ss_mask) {
+                       if (ssid == failed_ssid)
+                               break;
+                       if (ss->cancel_attach) {
+                               tset->ssid = ssid;
+                               ss->cancel_attach(tset);
+                       }
+               } while_each_subsys_mask();
+       }
 out_release_tset:
        spin_lock_irq(&css_set_lock);
        list_splice_init(&tset->dst_csets, &tset->src_csets);
@@ -2997,11 +3001,11 @@ static ssize_t cgroup_subtree_control_write(struct kernfs_open_file *of,
        cgrp->subtree_control &= ~disable;
 
        ret = cgroup_apply_control(cgrp);
-
        cgroup_finalize_control(cgrp, ret);
+       if (ret)
+               goto out_unlock;
 
        kernfs_activate(cgrp->kn);
-       ret = 0;
 out_unlock:
        cgroup_kn_unlock(of->kn);
        return ret ?: nbytes;
@@ -4669,6 +4673,10 @@ int __init cgroup_init(void)
 
                if (ss->bind)
                        ss->bind(init_css_set.subsys[ssid]);
+
+               mutex_lock(&cgroup_mutex);
+               css_populate_dir(init_css_set.subsys[ssid]);
+               mutex_unlock(&cgroup_mutex);
        }
 
        /* init_css_set.subsys[] has been updated, re-hash */
index ab86045..eee0331 100644 (file)
@@ -279,7 +279,8 @@ static int bringup_wait_for_ap(unsigned int cpu)
 
        /* Wait for the CPU to reach CPUHP_AP_ONLINE_IDLE */
        wait_for_completion(&st->done);
-       BUG_ON(!cpu_online(cpu));
+       if (WARN_ON_ONCE((!cpu_online(cpu))))
+               return -ECANCELED;
 
        /* Unpark the stopper thread and the hotplug thread of the target cpu */
        stop_machine_unpark(cpu);
index fcbd568..6db80fc 100644 (file)
 #include <asm/sections.h>
 
 /* vmcoreinfo stuff */
-static unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
-u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4];
-size_t vmcoreinfo_size;
-size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data);
+static unsigned char *vmcoreinfo_data;
+static size_t vmcoreinfo_size;
+u32 *vmcoreinfo_note;
+
+/* trusted vmcoreinfo, e.g. we can make a copy in the crash memory */
+static unsigned char *vmcoreinfo_data_safecopy;
 
 /*
  * parsing the "crashkernel" commandline
@@ -324,8 +326,23 @@ static void update_vmcoreinfo_note(void)
        final_note(buf);
 }
 
+void crash_update_vmcoreinfo_safecopy(void *ptr)
+{
+       if (ptr)
+               memcpy(ptr, vmcoreinfo_data, vmcoreinfo_size);
+
+       vmcoreinfo_data_safecopy = ptr;
+}
+
 void crash_save_vmcoreinfo(void)
 {
+       if (!vmcoreinfo_note)
+               return;
+
+       /* Use the safe copy to generate vmcoreinfo note if have */
+       if (vmcoreinfo_data_safecopy)
+               vmcoreinfo_data = vmcoreinfo_data_safecopy;
+
        vmcoreinfo_append_str("CRASHTIME=%ld\n", get_seconds());
        update_vmcoreinfo_note();
 }
@@ -340,7 +357,7 @@ void vmcoreinfo_append_str(const char *fmt, ...)
        r = vscnprintf(buf, sizeof(buf), fmt, args);
        va_end(args);
 
-       r = min(r, vmcoreinfo_max_size - vmcoreinfo_size);
+       r = min(r, (size_t)VMCOREINFO_BYTES - vmcoreinfo_size);
 
        memcpy(&vmcoreinfo_data[vmcoreinfo_size], buf, r);
 
@@ -356,11 +373,26 @@ void __weak arch_crash_save_vmcoreinfo(void)
 
 phys_addr_t __weak paddr_vmcoreinfo_note(void)
 {
-       return __pa_symbol((unsigned long)(char *)&vmcoreinfo_note);
+       return __pa(vmcoreinfo_note);
 }
 
 static int __init crash_save_vmcoreinfo_init(void)
 {
+       vmcoreinfo_data = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+       if (!vmcoreinfo_data) {
+               pr_warn("Memory allocation for vmcoreinfo_data failed\n");
+               return -ENOMEM;
+       }
+
+       vmcoreinfo_note = alloc_pages_exact(VMCOREINFO_NOTE_SIZE,
+                                               GFP_KERNEL | __GFP_ZERO);
+       if (!vmcoreinfo_note) {
+               free_page((unsigned long)vmcoreinfo_data);
+               vmcoreinfo_data = NULL;
+               pr_warn("Memory allocation for vmcoreinfo_note failed\n");
+               return -ENOMEM;
+       }
+
        VMCOREINFO_OSRELEASE(init_uts_ns.name.release);
        VMCOREINFO_PAGESIZE(PAGE_SIZE);
 
index 1538df9..426c2ff 100644 (file)
@@ -1452,6 +1452,13 @@ static enum event_type_t get_event_type(struct perf_event *event)
 
        lockdep_assert_held(&ctx->lock);
 
+       /*
+        * It's 'group type', really, because if our group leader is
+        * pinned, so are we.
+        */
+       if (event->group_leader != event)
+               event = event->group_leader;
+
        event_type = event->attr.pinned ? EVENT_PINNED : EVENT_FLEXIBLE;
        if (!ctx->task)
                event_type |= EVENT_CPU;
@@ -4378,7 +4385,9 @@ EXPORT_SYMBOL_GPL(perf_event_read_value);
 static int __perf_read_group_add(struct perf_event *leader,
                                        u64 read_format, u64 *values)
 {
+       struct perf_event_context *ctx = leader->ctx;
        struct perf_event *sub;
+       unsigned long flags;
        int n = 1; /* skip @nr */
        int ret;
 
@@ -4408,12 +4417,15 @@ static int __perf_read_group_add(struct perf_event *leader,
        if (read_format & PERF_FORMAT_ID)
                values[n++] = primary_event_id(leader);
 
+       raw_spin_lock_irqsave(&ctx->lock, flags);
+
        list_for_each_entry(sub, &leader->sibling_list, group_entry) {
                values[n++] += perf_event_count(sub);
                if (read_format & PERF_FORMAT_ID)
                        values[n++] = primary_event_id(sub);
        }
 
+       raw_spin_unlock_irqrestore(&ctx->lock, flags);
        return 0;
 }
 
@@ -7321,21 +7333,6 @@ int perf_event_account_interrupt(struct perf_event *event)
        return __perf_event_account_interrupt(event, 1);
 }
 
-static bool sample_is_allowed(struct perf_event *event, struct pt_regs *regs)
-{
-       /*
-        * Due to interrupt latency (AKA "skid"), we may enter the
-        * kernel before taking an overflow, even if the PMU is only
-        * counting user events.
-        * To avoid leaking information to userspace, we must always
-        * reject kernel samples when exclude_kernel is set.
-        */
-       if (event->attr.exclude_kernel && !user_mode(regs))
-               return false;
-
-       return true;
-}
-
 /*
  * Generic event overflow handling, sampling.
  */
@@ -7357,12 +7354,6 @@ static int __perf_event_overflow(struct perf_event *event,
        ret = __perf_event_account_interrupt(event, throttle);
 
        /*
-        * For security, drop the skid kernel samples if necessary.
-        */
-       if (!sample_is_allowed(event, regs))
-               return ret;
-
-       /*
         * XXX event_limit might not quite work as expected on inherited
         * events
         */
index 0f69a3e..17921b0 100644 (file)
@@ -205,19 +205,17 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node)
        void *stack;
        int i;
 
-       local_irq_disable();
        for (i = 0; i < NR_CACHED_STACKS; i++) {
-               struct vm_struct *s = this_cpu_read(cached_stacks[i]);
+               struct vm_struct *s;
+
+               s = this_cpu_xchg(cached_stacks[i], NULL);
 
                if (!s)
                        continue;
-               this_cpu_write(cached_stacks[i], NULL);
 
                tsk->stack_vm_area = s;
-               local_irq_enable();
                return s->addr;
        }
-       local_irq_enable();
 
        stack = __vmalloc_node_range(THREAD_SIZE, THREAD_SIZE,
                                     VMALLOC_START, VMALLOC_END,
@@ -245,19 +243,15 @@ static inline void free_thread_stack(struct task_struct *tsk)
 {
 #ifdef CONFIG_VMAP_STACK
        if (task_stack_vm_area(tsk)) {
-               unsigned long flags;
                int i;
 
-               local_irq_save(flags);
                for (i = 0; i < NR_CACHED_STACKS; i++) {
-                       if (this_cpu_read(cached_stacks[i]))
+                       if (this_cpu_cmpxchg(cached_stacks[i],
+                                       NULL, tsk->stack_vm_area) != NULL)
                                continue;
 
-                       this_cpu_write(cached_stacks[i], tsk->stack_vm_area);
-                       local_irq_restore(flags);
                        return;
                }
-               local_irq_restore(flags);
 
                vfree_atomic(tsk->stack);
                return;
@@ -560,7 +554,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
        set_task_stack_end_magic(tsk);
 
 #ifdef CONFIG_CC_STACKPROTECTOR
-       tsk->stack_canary = get_random_long();
+       tsk->stack_canary = get_random_canary();
 #endif
 
        /*
@@ -579,6 +573,10 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
 
        kcov_task_init(tsk);
 
+#ifdef CONFIG_FAULT_INJECTION
+       tsk->fail_nth = 0;
+#endif
+
        return tsk;
 
 free_stack:
index c934689..16dbe4c 100644 (file)
@@ -212,7 +212,7 @@ struct futex_pi_state {
        atomic_t refcount;
 
        union futex_key key;
-};
+} __randomize_layout;
 
 /**
  * struct futex_q - The hashed futex queue entry, one per waiting task
@@ -246,7 +246,7 @@ struct futex_q {
        struct rt_mutex_waiter *rt_waiter;
        union futex_key *requeue_pi_key;
        u32 bitset;
-};
+} __randomize_layout;
 
 static const struct futex_q futex_q_init = {
        /* list gets initialized in queue_me()*/
index d171bc5..a3cc37c 100644 (file)
@@ -170,21 +170,11 @@ static void irq_state_clr_disabled(struct irq_desc *desc)
        irqd_clear(&desc->irq_data, IRQD_IRQ_DISABLED);
 }
 
-static void irq_state_set_disabled(struct irq_desc *desc)
-{
-       irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);
-}
-
 static void irq_state_clr_masked(struct irq_desc *desc)
 {
        irqd_clear(&desc->irq_data, IRQD_IRQ_MASKED);
 }
 
-static void irq_state_set_masked(struct irq_desc *desc)
-{
-       irqd_set(&desc->irq_data, IRQD_IRQ_MASKED);
-}
-
 static void irq_state_clr_started(struct irq_desc *desc)
 {
        irqd_clear(&desc->irq_data, IRQD_IRQ_STARTED);
index aee8f7e..638eb9c 100644 (file)
@@ -95,8 +95,13 @@ static bool migrate_one_irq(struct irq_desc *desc)
                affinity = cpu_online_mask;
                brokeaff = true;
        }
-
-       err = irq_do_set_affinity(d, affinity, true);
+       /*
+        * Do not set the force argument of irq_do_set_affinity() as this
+        * disables the masking of offline CPUs from the supplied affinity
+        * mask and therefore might keep/reassign the irq to the outgoing
+        * CPU.
+        */
+       err = irq_do_set_affinity(d, affinity, false);
        if (err) {
                pr_warn_ratelimited("IRQ%u: set affinity failed(%d).\n",
                                    d->irq, err);
index dbfba99..a2c4805 100644 (file)
@@ -227,6 +227,16 @@ static inline bool irqd_has_set(struct irq_data *d, unsigned int mask)
        return __irqd_to_state(d) & mask;
 }
 
+static inline void irq_state_set_disabled(struct irq_desc *desc)
+{
+       irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);
+}
+
+static inline void irq_state_set_masked(struct irq_desc *desc)
+{
+       irqd_set(&desc->irq_data, IRQD_IRQ_MASKED);
+}
+
 #undef __irqd_to_state
 
 static inline void kstat_incr_irqs_this_cpu(struct irq_desc *desc)
index 5624b2d..1d1a5b9 100644 (file)
@@ -1090,6 +1090,16 @@ setup_irq_thread(struct irqaction *new, unsigned int irq, bool secondary)
 /*
  * Internal function to register an irqaction - typically used to
  * allocate special interrupts that are part of the architecture.
+ *
+ * Locking rules:
+ *
+ * desc->request_mutex Provides serialization against a concurrent free_irq()
+ *   chip_bus_lock     Provides serialization for slow bus operations
+ *     desc->lock      Provides serialization against hard interrupts
+ *
+ * chip_bus_lock and desc->lock are sufficient for all other management and
+ * interrupt related functions. desc->request_mutex solely serializes
+ * request/free_irq().
  */
 static int
 __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
@@ -1167,20 +1177,35 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
        if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)
                new->flags &= ~IRQF_ONESHOT;
 
+       /*
+        * Protects against a concurrent __free_irq() call which might wait
+        * for synchronize_irq() to complete without holding the optional
+        * chip bus lock and desc->lock.
+        */
        mutex_lock(&desc->request_mutex);
+
+       /*
+        * Acquire bus lock as the irq_request_resources() callback below
+        * might rely on the serialization or the magic power management
+        * functions which are abusing the irq_bus_lock() callback,
+        */
+       chip_bus_lock(desc);
+
+       /* First installed action requests resources. */
        if (!desc->action) {
                ret = irq_request_resources(desc);
                if (ret) {
                        pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
                               new->name, irq, desc->irq_data.chip->name);
-                       goto out_mutex;
+                       goto out_bus_unlock;
                }
        }
 
-       chip_bus_lock(desc);
-
        /*
         * The following block of code has to be executed atomically
+        * protected against a concurrent interrupt and any of the other
+        * management calls which are not serialized via
+        * desc->request_mutex or the optional bus lock.
         */
        raw_spin_lock_irqsave(&desc->lock, flags);
        old_ptr = &desc->action;
@@ -1286,10 +1311,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                        ret = __irq_set_trigger(desc,
                                                new->flags & IRQF_TRIGGER_MASK);
 
-                       if (ret) {
-                               irq_release_resources(desc);
+                       if (ret)
                                goto out_unlock;
-                       }
                }
 
                desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \
@@ -1385,12 +1408,10 @@ mismatch:
 out_unlock:
        raw_spin_unlock_irqrestore(&desc->lock, flags);
 
-       chip_bus_sync_unlock(desc);
-
        if (!desc->action)
                irq_release_resources(desc);
-
-out_mutex:
+out_bus_unlock:
+       chip_bus_sync_unlock(desc);
        mutex_unlock(&desc->request_mutex);
 
 out_thread:
@@ -1472,6 +1493,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
                        WARN(1, "Trying to free already-free IRQ %d\n", irq);
                        raw_spin_unlock_irqrestore(&desc->lock, flags);
                        chip_bus_sync_unlock(desc);
+                       mutex_unlock(&desc->request_mutex);
                        return NULL;
                }
 
@@ -1498,6 +1520,20 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
 #endif
 
        raw_spin_unlock_irqrestore(&desc->lock, flags);
+       /*
+        * Drop bus_lock here so the changes which were done in the chip
+        * callbacks above are synced out to the irq chips which hang
+        * behind a slow bus (I2C, SPI) before calling synchronize_irq().
+        *
+        * Aside of that the bus_lock can also be taken from the threaded
+        * handler in irq_finalize_oneshot() which results in a deadlock
+        * because synchronize_irq() would wait forever for the thread to
+        * complete, which is blocked on the bus lock.
+        *
+        * The still held desc->request_mutex() protects against a
+        * concurrent request_irq() of this irq so the release of resources
+        * and timing data is properly serialized.
+        */
        chip_bus_sync_unlock(desc);
 
        unregister_handler_proc(irq, action);
@@ -1530,8 +1566,15 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
                }
        }
 
+       /* Last action releases resources */
        if (!desc->action) {
+               /*
+                * Reaquire bus lock as irq_release_resources() might
+                * require it to deallocate resources over the slow bus.
+                */
+               chip_bus_lock(desc);
                irq_release_resources(desc);
+               chip_bus_sync_unlock(desc);
                irq_remove_timings(desc);
        }
 
index cea1de0..6bd9b58 100644 (file)
@@ -149,6 +149,8 @@ static void resume_irq(struct irq_desc *desc)
 
        /* Pretend that it got disabled ! */
        desc->depth++;
+       irq_state_set_disabled(desc);
+       irq_state_set_masked(desc);
 resume:
        desc->istate &= ~IRQS_SUSPENDED;
        __enable_irq(desc);
index 3a47fa9..ea34ed8 100644 (file)
 #include <linux/bug.h>
 #include <linux/err.h>
 #include <linux/kcmp.h>
+#include <linux/capability.h>
+#include <linux/list.h>
+#include <linux/eventpoll.h>
+#include <linux/file.h>
 
 #include <asm/unistd.h>
 
@@ -94,6 +98,56 @@ static int kcmp_lock(struct mutex *m1, struct mutex *m2)
        return err;
 }
 
+#ifdef CONFIG_EPOLL
+static int kcmp_epoll_target(struct task_struct *task1,
+                            struct task_struct *task2,
+                            unsigned long idx1,
+                            struct kcmp_epoll_slot __user *uslot)
+{
+       struct file *filp, *filp_epoll, *filp_tgt;
+       struct kcmp_epoll_slot slot;
+       struct files_struct *files;
+
+       if (copy_from_user(&slot, uslot, sizeof(slot)))
+               return -EFAULT;
+
+       filp = get_file_raw_ptr(task1, idx1);
+       if (!filp)
+               return -EBADF;
+
+       files = get_files_struct(task2);
+       if (!files)
+               return -EBADF;
+
+       spin_lock(&files->file_lock);
+       filp_epoll = fcheck_files(files, slot.efd);
+       if (filp_epoll)
+               get_file(filp_epoll);
+       else
+               filp_tgt = ERR_PTR(-EBADF);
+       spin_unlock(&files->file_lock);
+       put_files_struct(files);
+
+       if (filp_epoll) {
+               filp_tgt = get_epoll_tfile_raw_ptr(filp_epoll, slot.tfd, slot.toff);
+               fput(filp_epoll);
+       } else
+
+       if (IS_ERR(filp_tgt))
+               return PTR_ERR(filp_tgt);
+
+       return kcmp_ptr(filp, filp_tgt, KCMP_FILE);
+}
+#else
+static int kcmp_epoll_target(struct task_struct *task1,
+                            struct task_struct *task2,
+                            unsigned long idx1,
+                            struct kcmp_epoll_slot __user *uslot)
+{
+       return -EOPNOTSUPP;
+}
+#endif
+
 SYSCALL_DEFINE5(kcmp, pid_t, pid1, pid_t, pid2, int, type,
                unsigned long, idx1, unsigned long, idx2)
 {
@@ -165,6 +219,9 @@ SYSCALL_DEFINE5(kcmp, pid_t, pid1, pid_t, pid2, int, type,
                ret = -EOPNOTSUPP;
 #endif
                break;
+       case KCMP_EPOLL_TFD:
+               ret = kcmp_epoll_target(task1, task2, idx1, (void *)idx2);
+               break;
        default:
                ret = -EINVAL;
                break;
index 980936a..e62ec4d 100644 (file)
@@ -144,6 +144,14 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
        if (ret)
                goto out;
 
+       /*
+        * Some architecture(like S390) may touch the crash memory before
+        * machine_kexec_prepare(), we must copy vmcoreinfo data after it.
+        */
+       ret = kimage_crash_copy_vmcoreinfo(image);
+       if (ret)
+               goto out;
+
        for (i = 0; i < nr_segments; i++) {
                ret = kimage_load_segment(image, &image->segment[i]);
                if (ret)
index 154ffb4..1ae7c41 100644 (file)
@@ -482,6 +482,40 @@ struct page *kimage_alloc_control_pages(struct kimage *image,
        return pages;
 }
 
+int kimage_crash_copy_vmcoreinfo(struct kimage *image)
+{
+       struct page *vmcoreinfo_page;
+       void *safecopy;
+
+       if (image->type != KEXEC_TYPE_CRASH)
+               return 0;
+
+       /*
+        * For kdump, allocate one vmcoreinfo safe copy from the
+        * crash memory. as we have arch_kexec_protect_crashkres()
+        * after kexec syscall, we naturally protect it from write
+        * (even read) access under kernel direct mapping. But on
+        * the other hand, we still need to operate it when crash
+        * happens to generate vmcoreinfo note, hereby we rely on
+        * vmap for this purpose.
+        */
+       vmcoreinfo_page = kimage_alloc_control_pages(image, 0);
+       if (!vmcoreinfo_page) {
+               pr_warn("Could not allocate vmcoreinfo buffer\n");
+               return -ENOMEM;
+       }
+       safecopy = vmap(&vmcoreinfo_page, 1, VM_MAP, PAGE_KERNEL);
+       if (!safecopy) {
+               pr_warn("Could not vmap vmcoreinfo buffer\n");
+               return -ENOMEM;
+       }
+
+       image->vmcoreinfo_data_copy = safecopy;
+       crash_update_vmcoreinfo_safecopy(safecopy);
+
+       return 0;
+}
+
 static int kimage_add_entry(struct kimage *image, kimage_entry_t entry)
 {
        if (*image->entry != 0)
@@ -569,6 +603,11 @@ void kimage_free(struct kimage *image)
        if (!image)
                return;
 
+       if (image->vmcoreinfo_data_copy) {
+               crash_update_vmcoreinfo_safecopy(NULL);
+               vunmap(image->vmcoreinfo_data_copy);
+       }
+
        kimage_free_extra_pages(image);
        for_each_kimage_entry(image, ptr, entry) {
                if (entry & IND_INDIRECTION) {
index 766e7e4..9f48f44 100644 (file)
 #include <linux/vmalloc.h>
 #include "kexec_internal.h"
 
-/*
- * Declare these symbols weak so that if architecture provides a purgatory,
- * these will be overridden.
- */
-char __weak kexec_purgatory[0];
-size_t __weak kexec_purgatory_size = 0;
-
 static int kexec_calculate_store_digests(struct kimage *image);
 
 /* Architectures can provide this probe function */
@@ -298,6 +291,14 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd,
        if (ret)
                goto out;
 
+       /*
+        * Some architecture(like S390) may touch the crash memory before
+        * machine_kexec_prepare(), we must copy vmcoreinfo data after it.
+        */
+       ret = kimage_crash_copy_vmcoreinfo(image);
+       if (ret)
+               goto out;
+
        ret = kexec_calculate_store_digests(image);
        if (ret)
                goto out;
index 799a8a4..50dfcb0 100644 (file)
@@ -17,6 +17,8 @@ extern struct mutex kexec_mutex;
 #ifdef CONFIG_KEXEC_FILE
 #include <linux/purgatory.h>
 void kimage_file_post_load_cleanup(struct kimage *image);
+extern char kexec_purgatory[];
+extern size_t kexec_purgatory_size;
 #else /* CONFIG_KEXEC_FILE */
 static inline void kimage_file_post_load_cleanup(struct kimage *image) { }
 #endif /* CONFIG_KEXEC_FILE */
index ff68198..6d016c5 100644 (file)
@@ -68,6 +68,7 @@ static DECLARE_RWSEM(umhelper_sem);
  */
 #define MAX_KMOD_CONCURRENT 50
 static atomic_t kmod_concurrent_max = ATOMIC_INIT(MAX_KMOD_CONCURRENT);
+static DECLARE_WAIT_QUEUE_HEAD(kmod_wq);
 
 /*
        modprobe_path is set via /proc/sys.
@@ -140,7 +141,6 @@ int __request_module(bool wait, const char *fmt, ...)
        va_list args;
        char module_name[MODULE_NAME_LEN];
        int ret;
-       static int kmod_loop_msg;
 
        /*
         * We don't allow synchronous module loading from async.  Module
@@ -164,14 +164,11 @@ int __request_module(bool wait, const char *fmt, ...)
                return ret;
 
        if (atomic_dec_if_positive(&kmod_concurrent_max) < 0) {
-               /* We may be blaming an innocent here, but unlikely */
-               if (kmod_loop_msg < 5) {
-                       printk(KERN_ERR
-                              "request_module: runaway loop modprobe %s\n",
-                              module_name);
-                       kmod_loop_msg++;
-               }
-               return -ENOMEM;
+               pr_warn_ratelimited("request_module: kmod_concurrent_max (%u) close to 0 (max_modprobes: %u), for module %s, throttling...",
+                                   atomic_read(&kmod_concurrent_max),
+                                   MAX_KMOD_CONCURRENT, module_name);
+               wait_event_interruptible(kmod_wq,
+                                        atomic_dec_if_positive(&kmod_concurrent_max) >= 0);
        }
 
        trace_module_request(module_name, wait, _RET_IP_);
@@ -179,6 +176,7 @@ int __request_module(bool wait, const char *fmt, ...)
        ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
 
        atomic_inc(&kmod_concurrent_max);
+       wake_up(&kmod_wq);
 
        return ret;
 }
index df1a9aa..46ba853 100644 (file)
@@ -134,7 +134,7 @@ static ssize_t vmcoreinfo_show(struct kobject *kobj,
 {
        phys_addr_t vmcore_base = paddr_vmcoreinfo_note();
        return sprintf(buf, "%pa %x\n", &vmcore_base,
-                      (unsigned int)sizeof(vmcoreinfo_note));
+                       (unsigned int)VMCOREINFO_NOTE_SIZE);
 }
 KERNEL_ATTR_RO(vmcoreinfo);
 
index 7806989..649dc9d 100644 (file)
@@ -963,7 +963,6 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
                return -EDEADLK;
 
        raw_spin_lock(&task->pi_lock);
-       rt_mutex_adjust_prio(task);
        waiter->task = task;
        waiter->lock = lock;
        waiter->prio = task->prio;
index 17c667b..0869b20 100644 (file)
@@ -2069,7 +2069,7 @@ out:
 /**
  * try_to_wake_up_local - try to wake up a local task with rq lock held
  * @p: the thread to be awakened
- * @cookie: context's cookie for pinning
+ * @rf: request-queue flags for pinning
  *
  * Put @p on the run-queue if it's not already there. The caller must
  * ensure that this_rq() is locked, @p is bound to this_rq() and not
index 076a2e3..29a3970 100644 (file)
@@ -610,6 +610,11 @@ static int sugov_start(struct cpufreq_policy *policy)
                sg_cpu->sg_policy = sg_policy;
                sg_cpu->flags = SCHED_CPUFREQ_RT;
                sg_cpu->iowait_boost_max = policy->cpuinfo.max_freq;
+       }
+
+       for_each_cpu(cpu, policy->cpus) {
+               struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu);
+
                cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
                                             policy_is_shared(policy) ?
                                                        sugov_update_shared :
index 6e3ea4a..14d2dbf 100644 (file)
@@ -683,7 +683,7 @@ static u64 vtime_delta(struct vtime *vtime)
 {
        unsigned long long clock;
 
-       clock = sched_clock_cpu(smp_processor_id());
+       clock = sched_clock();
        if (clock < vtime->starttime)
                return 0;
 
@@ -814,7 +814,7 @@ void arch_vtime_task_switch(struct task_struct *prev)
 
        write_seqcount_begin(&vtime->seqcount);
        vtime->state = VTIME_SYS;
-       vtime->starttime = sched_clock_cpu(smp_processor_id());
+       vtime->starttime = sched_clock();
        write_seqcount_end(&vtime->seqcount);
 }
 
@@ -826,7 +826,7 @@ void vtime_init_idle(struct task_struct *t, int cpu)
        local_irq_save(flags);
        write_seqcount_begin(&vtime->seqcount);
        vtime->state = VTIME_SYS;
-       vtime->starttime = sched_clock_cpu(cpu);
+       vtime->starttime = sched_clock();
        write_seqcount_end(&vtime->seqcount);
        local_irq_restore(flags);
 }
index a84299f..755bd3f 100644 (file)
@@ -1392,17 +1392,19 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags)
        struct sched_dl_entity *pi_se = &p->dl;
 
        /*
-        * Use the scheduling parameters of the top pi-waiter
-        * task if we have one and its (absolute) deadline is
-        * smaller than our one... OTW we keep our runtime and
-        * deadline.
+        * Use the scheduling parameters of the top pi-waiter task if:
+        * - we have a top pi-waiter which is a SCHED_DEADLINE task AND
+        * - our dl_boosted is set (i.e. the pi-waiter's (absolute) deadline is
+        *   smaller than our deadline OR we are a !SCHED_DEADLINE task getting
+        *   boosted due to a SCHED_DEADLINE pi-waiter).
+        * Otherwise we keep our runtime and deadline.
         */
-       if (pi_task && p->dl.dl_boosted && dl_prio(pi_task->normal_prio)) {
+       if (pi_task && dl_prio(pi_task->normal_prio) && p->dl.dl_boosted) {
                pi_se = &pi_task->dl;
        } else if (!dl_prio(p->normal_prio)) {
                /*
                 * Special case in which we have a !SCHED_DEADLINE task
-                * that is going to be deboosted, but exceedes its
+                * that is going to be deboosted, but exceeds its
                 * runtime while doing so. No point in replenishing
                 * it, as it's going to return back to its original
                 * scheduling class after this.
index 4dfba1a..6648fbb 100644 (file)
@@ -174,11 +174,32 @@ extern int no_unaligned_warning;
 
 #ifdef CONFIG_PROC_SYSCTL
 
-#define SYSCTL_WRITES_LEGACY   -1
-#define SYSCTL_WRITES_WARN      0
-#define SYSCTL_WRITES_STRICT    1
+/**
+ * enum sysctl_writes_mode - supported sysctl write modes
+ *
+ * @SYSCTL_WRITES_LEGACY: each write syscall must fully contain the sysctl value
+ *     to be written, and multiple writes on the same sysctl file descriptor
+ *     will rewrite the sysctl value, regardless of file position. No warning
+ *     is issued when the initial position is not 0.
+ * @SYSCTL_WRITES_WARN: same as above but warn when the initial file position is
+ *     not 0.
+ * @SYSCTL_WRITES_STRICT: writes to numeric sysctl entries must always be at
+ *     file position 0 and the value must be fully contained in the buffer
+ *     sent to the write syscall. If dealing with strings respect the file
+ *     position, but restrict this to the max length of the buffer, anything
+ *     passed the max lenght will be ignored. Multiple writes will append
+ *     to the buffer.
+ *
+ * These write modes control how current file position affects the behavior of
+ * updating sysctl values through the proc interface on each write.
+ */
+enum sysctl_writes_mode {
+       SYSCTL_WRITES_LEGACY            = -1,
+       SYSCTL_WRITES_WARN              = 0,
+       SYSCTL_WRITES_STRICT            = 1,
+};
 
-static int sysctl_writes_strict = SYSCTL_WRITES_STRICT;
+static enum sysctl_writes_mode sysctl_writes_strict = SYSCTL_WRITES_STRICT;
 
 static int proc_do_cad_pid(struct ctl_table *table, int write,
                  void __user *buffer, size_t *lenp, loff_t *ppos);
@@ -880,6 +901,14 @@ static struct ctl_table kern_table[] = {
 #endif
        },
        {
+               .procname       = "watchdog_cpumask",
+               .data           = &watchdog_cpumask_bits,
+               .maxlen         = NR_CPUS,
+               .mode           = 0644,
+               .proc_handler   = proc_watchdog_cpumask,
+       },
+#ifdef CONFIG_SOFTLOCKUP_DETECTOR
+       {
                .procname       = "soft_watchdog",
                .data           = &soft_watchdog_enabled,
                .maxlen         = sizeof (int),
@@ -889,13 +918,6 @@ static struct ctl_table kern_table[] = {
                .extra2         = &one,
        },
        {
-               .procname       = "watchdog_cpumask",
-               .data           = &watchdog_cpumask_bits,
-               .maxlen         = NR_CPUS,
-               .mode           = 0644,
-               .proc_handler   = proc_watchdog_cpumask,
-       },
-       {
                .procname       = "softlockup_panic",
                .data           = &softlockup_panic,
                .maxlen         = sizeof(int),
@@ -904,27 +926,29 @@ static struct ctl_table kern_table[] = {
                .extra1         = &zero,
                .extra2         = &one,
        },
-#ifdef CONFIG_HARDLOCKUP_DETECTOR
+#ifdef CONFIG_SMP
        {
-               .procname       = "hardlockup_panic",
-               .data           = &hardlockup_panic,
+               .procname       = "softlockup_all_cpu_backtrace",
+               .data           = &sysctl_softlockup_all_cpu_backtrace,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &one,
        },
+#endif /* CONFIG_SMP */
 #endif
-#ifdef CONFIG_SMP
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
        {
-               .procname       = "softlockup_all_cpu_backtrace",
-               .data           = &sysctl_softlockup_all_cpu_backtrace,
+               .procname       = "hardlockup_panic",
+               .data           = &hardlockup_panic,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &one,
        },
+#ifdef CONFIG_SMP
        {
                .procname       = "hardlockup_all_cpu_backtrace",
                .data           = &sysctl_hardlockup_all_cpu_backtrace,
@@ -936,6 +960,8 @@ static struct ctl_table kern_table[] = {
        },
 #endif /* CONFIG_SMP */
 #endif
+#endif
+
 #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
        {
                .procname       = "unknown_nmi_panic",
@@ -1950,6 +1976,32 @@ static void warn_sysctl_write(struct ctl_table *table)
 }
 
 /**
+ * proc_first_pos_non_zero_ignore - check if firs position is allowed
+ * @ppos: file position
+ * @table: the sysctl table
+ *
+ * Returns true if the first position is non-zero and the sysctl_writes_strict
+ * mode indicates this is not allowed for numeric input types. String proc
+ * hadlers can ignore the return value.
+ */
+static bool proc_first_pos_non_zero_ignore(loff_t *ppos,
+                                          struct ctl_table *table)
+{
+       if (!*ppos)
+               return false;
+
+       switch (sysctl_writes_strict) {
+       case SYSCTL_WRITES_STRICT:
+               return true;
+       case SYSCTL_WRITES_WARN:
+               warn_sysctl_write(table);
+               return false;
+       default:
+               return false;
+       }
+}
+
+/**
  * proc_dostring - read a string sysctl
  * @table: the sysctl table
  * @write: %TRUE if this is a write to the sysctl file
@@ -1969,8 +2021,8 @@ static void warn_sysctl_write(struct ctl_table *table)
 int proc_dostring(struct ctl_table *table, int write,
                  void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-       if (write && *ppos && sysctl_writes_strict == SYSCTL_WRITES_WARN)
-               warn_sysctl_write(table);
+       if (write)
+               proc_first_pos_non_zero_ignore(ppos, table);
 
        return _proc_do_string((char *)(table->data), table->maxlen, write,
                               (char __user *)buffer, lenp, ppos);
@@ -2128,19 +2180,18 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
        return 0;
 }
 
-static int do_proc_douintvec_conv(bool *negp, unsigned long *lvalp,
-                                int *valp,
-                                int write, void *data)
+static int do_proc_douintvec_conv(unsigned long *lvalp,
+                                 unsigned int *valp,
+                                 int write, void *data)
 {
        if (write) {
-               if (*negp)
+               if (*lvalp > UINT_MAX)
                        return -EINVAL;
                if (*lvalp > UINT_MAX)
                        return -EINVAL;
                *valp = *lvalp;
        } else {
                unsigned int val = *valp;
-               *negp = false;
                *lvalp = (unsigned long)val;
        }
        return 0;
@@ -2172,17 +2223,8 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
                conv = do_proc_dointvec_conv;
 
        if (write) {
-               if (*ppos) {
-                       switch (sysctl_writes_strict) {
-                       case SYSCTL_WRITES_STRICT:
-                               goto out;
-                       case SYSCTL_WRITES_WARN:
-                               warn_sysctl_write(table);
-                               break;
-                       default:
-                               break;
-                       }
-               }
+               if (proc_first_pos_non_zero_ignore(ppos, table))
+                       goto out;
 
                if (left > PAGE_SIZE - 1)
                        left = PAGE_SIZE - 1;
@@ -2249,6 +2291,146 @@ static int do_proc_dointvec(struct ctl_table *table, int write,
                        buffer, lenp, ppos, conv, data);
 }
 
+static int do_proc_douintvec_w(unsigned int *tbl_data,
+                              struct ctl_table *table,
+                              void __user *buffer,
+                              size_t *lenp, loff_t *ppos,
+                              int (*conv)(unsigned long *lvalp,
+                                          unsigned int *valp,
+                                          int write, void *data),
+                              void *data)
+{
+       unsigned long lval;
+       int err = 0;
+       size_t left;
+       bool neg;
+       char *kbuf = NULL, *p;
+
+       left = *lenp;
+
+       if (proc_first_pos_non_zero_ignore(ppos, table))
+               goto bail_early;
+
+       if (left > PAGE_SIZE - 1)
+               left = PAGE_SIZE - 1;
+
+       p = kbuf = memdup_user_nul(buffer, left);
+       if (IS_ERR(kbuf))
+               return -EINVAL;
+
+       left -= proc_skip_spaces(&p);
+       if (!left) {
+               err = -EINVAL;
+               goto out_free;
+       }
+
+       err = proc_get_long(&p, &left, &lval, &neg,
+                            proc_wspace_sep,
+                            sizeof(proc_wspace_sep), NULL);
+       if (err || neg) {
+               err = -EINVAL;
+               goto out_free;
+       }
+
+       if (conv(&lval, tbl_data, 1, data)) {
+               err = -EINVAL;
+               goto out_free;
+       }
+
+       if (!err && left)
+               left -= proc_skip_spaces(&p);
+
+out_free:
+       kfree(kbuf);
+       if (err)
+               return -EINVAL;
+
+       return 0;
+
+       /* This is in keeping with old __do_proc_dointvec() */
+bail_early:
+       *ppos += *lenp;
+       return err;
+}
+
+static int do_proc_douintvec_r(unsigned int *tbl_data, void __user *buffer,
+                              size_t *lenp, loff_t *ppos,
+                              int (*conv)(unsigned long *lvalp,
+                                          unsigned int *valp,
+                                          int write, void *data),
+                              void *data)
+{
+       unsigned long lval;
+       int err = 0;
+       size_t left;
+
+       left = *lenp;
+
+       if (conv(&lval, tbl_data, 0, data)) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       err = proc_put_long(&buffer, &left, lval, false);
+       if (err || !left)
+               goto out;
+
+       err = proc_put_char(&buffer, &left, '\n');
+
+out:
+       *lenp -= left;
+       *ppos += *lenp;
+
+       return err;
+}
+
+static int __do_proc_douintvec(void *tbl_data, struct ctl_table *table,
+                              int write, void __user *buffer,
+                              size_t *lenp, loff_t *ppos,
+                              int (*conv)(unsigned long *lvalp,
+                                          unsigned int *valp,
+                                          int write, void *data),
+                              void *data)
+{
+       unsigned int *i, vleft;
+
+       if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) {
+               *lenp = 0;
+               return 0;
+       }
+
+       i = (unsigned int *) tbl_data;
+       vleft = table->maxlen / sizeof(*i);
+
+       /*
+        * Arrays are not supported, keep this simple. *Do not* add
+        * support for them.
+        */
+       if (vleft != 1) {
+               *lenp = 0;
+               return -EINVAL;
+       }
+
+       if (!conv)
+               conv = do_proc_douintvec_conv;
+
+       if (write)
+               return do_proc_douintvec_w(i, table, buffer, lenp, ppos,
+                                          conv, data);
+       return do_proc_douintvec_r(i, buffer, lenp, ppos, conv, data);
+}
+
+static int do_proc_douintvec(struct ctl_table *table, int write,
+                            void __user *buffer, size_t *lenp, loff_t *ppos,
+                            int (*conv)(unsigned long *lvalp,
+                                        unsigned int *valp,
+                                        int write, void *data),
+                            void *data)
+{
+       return __do_proc_douintvec(table->data, table, write,
+                                  buffer, lenp, ppos, conv, data);
+}
+
 /**
  * proc_dointvec - read a vector of integers
  * @table: the sysctl table
@@ -2284,8 +2466,8 @@ int proc_dointvec(struct ctl_table *table, int write,
 int proc_douintvec(struct ctl_table *table, int write,
                     void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-       return do_proc_dointvec(table, write, buffer, lenp, ppos,
-                               do_proc_douintvec_conv, NULL);
+       return do_proc_douintvec(table, write, buffer, lenp, ppos,
+                                do_proc_douintvec_conv, NULL);
 }
 
 /*
@@ -2390,6 +2572,65 @@ int proc_dointvec_minmax(struct ctl_table *table, int write,
                                do_proc_dointvec_minmax_conv, &param);
 }
 
+struct do_proc_douintvec_minmax_conv_param {
+       unsigned int *min;
+       unsigned int *max;
+};
+
+static int do_proc_douintvec_minmax_conv(unsigned long *lvalp,
+                                        unsigned int *valp,
+                                        int write, void *data)
+{
+       struct do_proc_douintvec_minmax_conv_param *param = data;
+
+       if (write) {
+               unsigned int val = *lvalp;
+
+               if ((param->min && *param->min > val) ||
+                   (param->max && *param->max < val))
+                       return -ERANGE;
+
+               if (*lvalp > UINT_MAX)
+                       return -EINVAL;
+               *valp = val;
+       } else {
+               unsigned int val = *valp;
+               *lvalp = (unsigned long) val;
+       }
+
+       return 0;
+}
+
+/**
+ * proc_douintvec_minmax - read a vector of unsigned ints with min/max values
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ * @ppos: file position
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer
+ * values from/to the user buffer, treated as an ASCII string. Negative
+ * strings are not allowed.
+ *
+ * This routine will ensure the values are within the range specified by
+ * table->extra1 (min) and table->extra2 (max). There is a final sanity
+ * check for UINT_MAX to avoid having to support wrap around uses from
+ * userspace.
+ *
+ * Returns 0 on success.
+ */
+int proc_douintvec_minmax(struct ctl_table *table, int write,
+                         void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct do_proc_douintvec_minmax_conv_param param = {
+               .min = (unsigned int *) table->extra1,
+               .max = (unsigned int *) table->extra2,
+       };
+       return do_proc_douintvec(table, write, buffer, lenp, ppos,
+                                do_proc_douintvec_minmax_conv, &param);
+}
+
 static void validate_coredump_safety(void)
 {
 #ifdef CONFIG_COREDUMP
@@ -2447,17 +2688,8 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
        left = *lenp;
 
        if (write) {
-               if (*ppos) {
-                       switch (sysctl_writes_strict) {
-                       case SYSCTL_WRITES_STRICT:
-                               goto out;
-                       case SYSCTL_WRITES_WARN:
-                               warn_sysctl_write(table);
-                               break;
-                       default:
-                               break;
-                       }
-               }
+               if (proc_first_pos_non_zero_ignore(ppos, table))
+                       goto out;
 
                if (left > PAGE_SIZE - 1)
                        left = PAGE_SIZE - 1;
@@ -2898,6 +3130,12 @@ int proc_dointvec_minmax(struct ctl_table *table, int write,
        return -ENOSYS;
 }
 
+int proc_douintvec_minmax(struct ctl_table *table, int write,
+                         void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       return -ENOSYS;
+}
+
 int proc_dointvec_jiffies(struct ctl_table *table, int write,
                    void __user *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -2940,6 +3178,7 @@ EXPORT_SYMBOL(proc_dointvec);
 EXPORT_SYMBOL(proc_douintvec);
 EXPORT_SYMBOL(proc_dointvec_jiffies);
 EXPORT_SYMBOL(proc_dointvec_minmax);
+EXPORT_SYMBOL_GPL(proc_douintvec_minmax);
 EXPORT_SYMBOL(proc_dointvec_userhz_jiffies);
 EXPORT_SYMBOL(proc_dointvec_ms_jiffies);
 EXPORT_SYMBOL(proc_dostring);
index 939a158..02e1859 100644 (file)
@@ -1346,7 +1346,7 @@ static void deprecated_sysctl_warning(const int *name, int nlen)
         * CTL_KERN/KERN_VERSION is used by older glibc and cannot
         * ever go away.
         */
-       if (name[0] == CTL_KERN && name[1] == KERN_VERSION)
+       if (nlen >= 2 && name[0] == CTL_KERN && name[1] == KERN_VERSION)
                return;
 
        if (printk_ratelimit()) {
index 2953d55..02004ae 100644 (file)
@@ -113,7 +113,7 @@ static int ftrace_disabled __read_mostly;
 
 static DEFINE_MUTEX(ftrace_lock);
 
-static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end;
+static struct ftrace_ops __rcu *ftrace_ops_list __read_mostly = &ftrace_list_end;
 ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
 static struct ftrace_ops global_ops;
 
@@ -169,8 +169,11 @@ int ftrace_nr_registered_ops(void)
 
        mutex_lock(&ftrace_lock);
 
-       for (ops = ftrace_ops_list;
-            ops != &ftrace_list_end; ops = ops->next)
+       for (ops = rcu_dereference_protected(ftrace_ops_list,
+                                            lockdep_is_held(&ftrace_lock));
+            ops != &ftrace_list_end;
+            ops = rcu_dereference_protected(ops->next,
+                                            lockdep_is_held(&ftrace_lock)))
                cnt++;
 
        mutex_unlock(&ftrace_lock);
@@ -275,10 +278,11 @@ static void update_ftrace_function(void)
         * If there's only one ftrace_ops registered, the ftrace_ops_list
         * will point to the ops we want.
         */
-       set_function_trace_op = ftrace_ops_list;
+       set_function_trace_op = rcu_dereference_protected(ftrace_ops_list,
+                                               lockdep_is_held(&ftrace_lock));
 
        /* If there's no ftrace_ops registered, just call the stub function */
-       if (ftrace_ops_list == &ftrace_list_end) {
+       if (set_function_trace_op == &ftrace_list_end) {
                func = ftrace_stub;
 
        /*
@@ -286,7 +290,8 @@ static void update_ftrace_function(void)
         * recursion safe and not dynamic and the arch supports passing ops,
         * then have the mcount trampoline call the function directly.
         */
-       } else if (ftrace_ops_list->next == &ftrace_list_end) {
+       } else if (rcu_dereference_protected(ftrace_ops_list->next,
+                       lockdep_is_held(&ftrace_lock)) == &ftrace_list_end) {
                func = ftrace_ops_get_list_func(ftrace_ops_list);
 
        } else {
@@ -348,9 +353,11 @@ int using_ftrace_ops_list_func(void)
        return ftrace_trace_function == ftrace_ops_list_func;
 }
 
-static void add_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops)
+static void add_ftrace_ops(struct ftrace_ops __rcu **list,
+                          struct ftrace_ops *ops)
 {
-       ops->next = *list;
+       rcu_assign_pointer(ops->next, *list);
+
        /*
         * We are entering ops into the list but another
         * CPU might be walking that list. We need to make sure
@@ -360,7 +367,8 @@ static void add_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops)
        rcu_assign_pointer(*list, ops);
 }
 
-static int remove_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops)
+static int remove_ftrace_ops(struct ftrace_ops __rcu **list,
+                            struct ftrace_ops *ops)
 {
        struct ftrace_ops **p;
 
@@ -368,7 +376,10 @@ static int remove_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops)
         * If we are removing the last function, then simply point
         * to the ftrace_stub.
         */
-       if (*list == ops && ops->next == &ftrace_list_end) {
+       if (rcu_dereference_protected(*list,
+                       lockdep_is_held(&ftrace_lock)) == ops &&
+           rcu_dereference_protected(ops->next,
+                       lockdep_is_held(&ftrace_lock)) == &ftrace_list_end) {
                *list = &ftrace_list_end;
                return 0;
        }
@@ -1569,8 +1580,8 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
                return 0;
 #endif
 
-       hash.filter_hash = rcu_dereference_raw_notrace(ops->func_hash->filter_hash);
-       hash.notrace_hash = rcu_dereference_raw_notrace(ops->func_hash->notrace_hash);
+       rcu_assign_pointer(hash.filter_hash, ops->func_hash->filter_hash);
+       rcu_assign_pointer(hash.notrace_hash, ops->func_hash->notrace_hash);
 
        if (hash_contains_ip(ip, &hash))
                ret = 1;
@@ -2840,7 +2851,8 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
         * If there's no more ops registered with ftrace, run a
         * sanity check to make sure all rec flags are cleared.
         */
-       if (ftrace_ops_list == &ftrace_list_end) {
+       if (rcu_dereference_protected(ftrace_ops_list,
+                       lockdep_is_held(&ftrace_lock)) == &ftrace_list_end) {
                struct ftrace_page *pg;
                struct dyn_ftrace *rec;
 
@@ -3816,7 +3828,7 @@ match_records(struct ftrace_hash *hash, char *func, int len, char *mod)
        int exclude_mod = 0;
        int found = 0;
        int ret;
-       int clear_filter;
+       int clear_filter = 0;
 
        if (func) {
                func_g.type = filter_parse_regex(func, len, &func_g.search,
@@ -3950,7 +3962,7 @@ static int cache_mod(struct trace_array *tr,
                                continue;
 
                        /* no func matches all */
-                       if (!func || strcmp(func, "*") == 0 ||
+                       if (strcmp(func, "*") == 0 ||
                            (ftrace_mod->func &&
                             strcmp(ftrace_mod->func, func) == 0)) {
                                ret = 0;
@@ -3978,6 +3990,7 @@ static int
 ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
                 int reset, int enable);
 
+#ifdef CONFIG_MODULES
 static void process_mod_list(struct list_head *head, struct ftrace_ops *ops,
                             char *mod, bool enable)
 {
@@ -4068,6 +4081,7 @@ static void process_cached_mods(const char *mod_name)
 
        kfree(mod);
 }
+#endif
 
 /*
  * We register the module command as a template to show others how
@@ -6451,7 +6465,8 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
        if (ftrace_enabled) {
 
                /* we are starting ftrace again */
-               if (ftrace_ops_list != &ftrace_list_end)
+               if (rcu_dereference_protected(ftrace_ops_list,
+                       lockdep_is_held(&ftrace_lock)) != &ftrace_list_end)
                        update_ftrace_function();
 
                ftrace_startup_sysctl();
index 4ae268e..529cc50 100644 (file)
@@ -1136,12 +1136,12 @@ static int __rb_allocate_pages(long nr_pages, struct list_head *pages, int cpu)
        for (i = 0; i < nr_pages; i++) {
                struct page *page;
                /*
-                * __GFP_NORETRY flag makes sure that the allocation fails
-                * gracefully without invoking oom-killer and the system is
-                * not destabilized.
+                * __GFP_RETRY_MAYFAIL flag makes sure that the allocation fails
+                * gracefully without invoking oom-killer and the system is not
+                * destabilized.
                 */
                bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
-                                   GFP_KERNEL | __GFP_NORETRY,
+                                   GFP_KERNEL | __GFP_RETRY_MAYFAIL,
                                    cpu_to_node(cpu));
                if (!bpage)
                        goto free_pages;
@@ -1149,7 +1149,7 @@ static int __rb_allocate_pages(long nr_pages, struct list_head *pages, int cpu)
                list_add(&bpage->list, pages);
 
                page = alloc_pages_node(cpu_to_node(cpu),
-                                       GFP_KERNEL | __GFP_NORETRY, 0);
+                                       GFP_KERNEL | __GFP_RETRY_MAYFAIL, 0);
                if (!page)
                        goto free_pages;
                bpage->page = page_address(page);
index 948ec32..42b9355 100644 (file)
@@ -1916,7 +1916,11 @@ static int trace_save_cmdline(struct task_struct *tsk)
 {
        unsigned pid, idx;
 
-       if (!tsk->pid || unlikely(tsk->pid > PID_MAX_DEFAULT))
+       /* treat recording of idle task as a success */
+       if (!tsk->pid)
+               return 1;
+
+       if (unlikely(tsk->pid > PID_MAX_DEFAULT))
                return 0;
 
        /*
@@ -2002,7 +2006,11 @@ int trace_find_tgid(int pid)
 
 static int trace_save_tgid(struct task_struct *tsk)
 {
-       if (unlikely(!tgid_map || !tsk->pid || tsk->pid > PID_MAX_DEFAULT))
+       /* treat recording of idle task as a success */
+       if (!tsk->pid)
+               return 1;
+
+       if (unlikely(!tgid_map || tsk->pid > PID_MAX_DEFAULT))
                return 0;
 
        tgid_map[tsk->pid] = tsk->tgid;
@@ -2029,11 +2037,20 @@ static bool tracing_record_taskinfo_skip(int flags)
  */
 void tracing_record_taskinfo(struct task_struct *task, int flags)
 {
+       bool done;
+
        if (tracing_record_taskinfo_skip(flags))
                return;
-       if ((flags & TRACE_RECORD_CMDLINE) && !trace_save_cmdline(task))
-               return;
-       if ((flags & TRACE_RECORD_TGID) && !trace_save_tgid(task))
+
+       /*
+        * Record as much task information as possible. If some fail, continue
+        * to try to record the others.
+        */
+       done = !(flags & TRACE_RECORD_CMDLINE) || trace_save_cmdline(task);
+       done &= !(flags & TRACE_RECORD_TGID) || trace_save_tgid(task);
+
+       /* If recording any information failed, retry again soon. */
+       if (!done)
                return;
 
        __this_cpu_write(trace_taskinfo_save, false);
@@ -2050,15 +2067,22 @@ void tracing_record_taskinfo(struct task_struct *task, int flags)
 void tracing_record_taskinfo_sched_switch(struct task_struct *prev,
                                          struct task_struct *next, int flags)
 {
+       bool done;
+
        if (tracing_record_taskinfo_skip(flags))
                return;
 
-       if ((flags & TRACE_RECORD_CMDLINE) &&
-           (!trace_save_cmdline(prev) || !trace_save_cmdline(next)))
-               return;
+       /*
+        * Record as much task information as possible. If some fail, continue
+        * to try to record the others.
+        */
+       done  = !(flags & TRACE_RECORD_CMDLINE) || trace_save_cmdline(prev);
+       done &= !(flags & TRACE_RECORD_CMDLINE) || trace_save_cmdline(next);
+       done &= !(flags & TRACE_RECORD_TGID) || trace_save_tgid(prev);
+       done &= !(flags & TRACE_RECORD_TGID) || trace_save_tgid(next);
 
-       if ((flags & TRACE_RECORD_TGID) &&
-           (!trace_save_tgid(prev) || !trace_save_tgid(next)))
+       /* If recording any information failed, retry again soon. */
+       if (!done)
                return;
 
        __this_cpu_write(trace_taskinfo_save, false);
@@ -3334,14 +3358,23 @@ static void print_func_help_header_irq(struct trace_buffer *buf, struct seq_file
                                       unsigned int flags)
 {
        bool tgid = flags & TRACE_ITER_RECORD_TGID;
-
-       seq_printf(m, "#                          %s  _-----=> irqs-off\n",         tgid ? "          " : "");
-       seq_printf(m, "#                          %s / _----=> need-resched\n",     tgid ? "          " : "");
-       seq_printf(m, "#                          %s| / _---=> hardirq/softirq\n",  tgid ? "          " : "");
-       seq_printf(m, "#                          %s|| / _--=> preempt-depth\n",    tgid ? "          " : "");
-       seq_printf(m, "#                          %s||| /     delay\n",             tgid ? "          " : "");
-       seq_printf(m, "#           TASK-PID   CPU#%s||||    TIMESTAMP  FUNCTION\n", tgid ? "   TGID   " : "");
-       seq_printf(m, "#              | |       | %s||||       |         |\n",      tgid ? "     |    " : "");
+       const char tgid_space[] = "          ";
+       const char space[] = "  ";
+
+       seq_printf(m, "#                          %s  _-----=> irqs-off\n",
+                  tgid ? tgid_space : space);
+       seq_printf(m, "#                          %s / _----=> need-resched\n",
+                  tgid ? tgid_space : space);
+       seq_printf(m, "#                          %s| / _---=> hardirq/softirq\n",
+                  tgid ? tgid_space : space);
+       seq_printf(m, "#                          %s|| / _--=> preempt-depth\n",
+                  tgid ? tgid_space : space);
+       seq_printf(m, "#                          %s||| /     delay\n",
+                  tgid ? tgid_space : space);
+       seq_printf(m, "#           TASK-PID   CPU#%s||||    TIMESTAMP  FUNCTION\n",
+                  tgid ? "   TGID   " : space);
+       seq_printf(m, "#              | |       | %s||||       |         |\n",
+                  tgid ? "     |    " : space);
 }
 
 void
@@ -4689,6 +4722,76 @@ static const struct file_operations tracing_readme_fops = {
        .llseek         = generic_file_llseek,
 };
 
+static void *saved_tgids_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       int *ptr = v;
+
+       if (*pos || m->count)
+               ptr++;
+
+       (*pos)++;
+
+       for (; ptr <= &tgid_map[PID_MAX_DEFAULT]; ptr++) {
+               if (trace_find_tgid(*ptr))
+                       return ptr;
+       }
+
+       return NULL;
+}
+
+static void *saved_tgids_start(struct seq_file *m, loff_t *pos)
+{
+       void *v;
+       loff_t l = 0;
+
+       if (!tgid_map)
+               return NULL;
+
+       v = &tgid_map[0];
+       while (l <= *pos) {
+               v = saved_tgids_next(m, v, &l);
+               if (!v)
+                       return NULL;
+       }
+
+       return v;
+}
+
+static void saved_tgids_stop(struct seq_file *m, void *v)
+{
+}
+
+static int saved_tgids_show(struct seq_file *m, void *v)
+{
+       int pid = (int *)v - tgid_map;
+
+       seq_printf(m, "%d %d\n", pid, trace_find_tgid(pid));
+       return 0;
+}
+
+static const struct seq_operations tracing_saved_tgids_seq_ops = {
+       .start          = saved_tgids_start,
+       .stop           = saved_tgids_stop,
+       .next           = saved_tgids_next,
+       .show           = saved_tgids_show,
+};
+
+static int tracing_saved_tgids_open(struct inode *inode, struct file *filp)
+{
+       if (tracing_disabled)
+               return -ENODEV;
+
+       return seq_open(filp, &tracing_saved_tgids_seq_ops);
+}
+
+
+static const struct file_operations tracing_saved_tgids_fops = {
+       .open           = tracing_saved_tgids_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
 static void *saved_cmdlines_next(struct seq_file *m, void *v, loff_t *pos)
 {
        unsigned int *ptr = v;
@@ -7671,6 +7774,7 @@ static int instance_rmdir(const char *name)
        }
        kfree(tr->topts);
 
+       free_cpumask_var(tr->tracing_cpumask);
        kfree(tr->name);
        kfree(tr);
 
@@ -7921,6 +8025,9 @@ static __init int tracer_init_tracefs(void)
        trace_create_file("saved_cmdlines_size", 0644, d_tracer,
                          NULL, &tracing_saved_cmdlines_size_fops);
 
+       trace_create_file("saved_tgids", 0444, d_tracer,
+                       NULL, &tracing_saved_tgids_fops);
+
        trace_eval_init();
 
        trace_create_eval_file(d_tracer);
index 6ade1c5..490ba22 100644 (file)
@@ -1210,9 +1210,9 @@ struct ftrace_event_field {
 struct event_filter {
        int                     n_preds;        /* Number assigned */
        int                     a_preds;        /* allocated */
-       struct filter_pred      *preds;
-       struct filter_pred      *root;
-       char                    *filter_string;
+       struct filter_pred __rcu        *preds;
+       struct filter_pred __rcu        *root;
+       char                            *filter_string;
 };
 
 struct event_subsystem {
index 2c52218..c9b5aa1 100644 (file)
@@ -598,6 +598,14 @@ static struct notifier_block trace_kprobe_module_nb = {
        .priority = 1   /* Invoked after kprobe module callback */
 };
 
+/* Convert certain expected symbols into '_' when generating event names */
+static inline void sanitize_event_name(char *name)
+{
+       while (*name++ != '\0')
+               if (*name == ':' || *name == '.')
+                       *name = '_';
+}
+
 static int create_trace_kprobe(int argc, char **argv)
 {
        /*
@@ -736,6 +744,7 @@ static int create_trace_kprobe(int argc, char **argv)
                else
                        snprintf(buf, MAX_EVENT_NAME_LEN, "%c_0x%p",
                                 is_return ? 'r' : 'p', addr);
+               sanitize_event_name(buf);
                event = buf;
        }
        tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive,
index b4a751e..a4df67c 100644 (file)
@@ -406,6 +406,8 @@ static const struct file_operations stack_trace_fops = {
        .release        = seq_release,
 };
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+
 static int
 stack_trace_filter_open(struct inode *inode, struct file *file)
 {
@@ -423,6 +425,8 @@ static const struct file_operations stack_trace_filter_fops = {
        .release = ftrace_regex_release,
 };
 
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
 int
 stack_trace_sysctl(struct ctl_table *table, int write,
                   void __user *buffer, size_t *lenp,
@@ -477,8 +481,10 @@ static __init int stack_trace_init(void)
        trace_create_file("stack_trace", 0444, d_tracer,
                        NULL, &stack_trace_fops);
 
+#ifdef CONFIG_DYNAMIC_FTRACE
        trace_create_file("stack_trace_filter", 0444, d_tracer,
                          &trace_ops, &stack_trace_filter_fops);
+#endif
 
        if (stack_trace_filter_buf[0])
                ftrace_set_early_filter(&trace_ops, stack_trace_filter_buf, 1);
index 03e0b69..06d3389 100644 (file)
@@ -9,7 +9,7 @@
  * to those contributors as well.
  */
 
-#define pr_fmt(fmt) "NMI watchdog: " fmt
+#define pr_fmt(fmt) "watchdog: " fmt
 
 #include <linux/mm.h>
 #include <linux/cpu.h>
 #include <linux/kvm_para.h>
 #include <linux/kthread.h>
 
+/* Watchdog configuration */
 static DEFINE_MUTEX(watchdog_proc_mutex);
 
-#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
-unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED|NMI_WATCHDOG_ENABLED;
+int __read_mostly nmi_watchdog_enabled;
+
+#if defined(CONFIG_HARDLOCKUP_DETECTOR) || defined(CONFIG_HAVE_NMI_WATCHDOG)
+unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED |
+                                               NMI_WATCHDOG_ENABLED;
 #else
 unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED;
 #endif
-int __read_mostly nmi_watchdog_enabled;
+
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+/* boot commands */
+/*
+ * Should we panic when a soft-lockup or hard-lockup occurs:
+ */
+unsigned int __read_mostly hardlockup_panic =
+                       CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE;
+/*
+ * We may not want to enable hard lockup detection by default in all cases,
+ * for example when running the kernel as a guest on a hypervisor. In these
+ * cases this function can be called to disable hard lockup detection. This
+ * function should only be executed once by the boot processor before the
+ * kernel command line parameters are parsed, because otherwise it is not
+ * possible to override this in hardlockup_panic_setup().
+ */
+void hardlockup_detector_disable(void)
+{
+       watchdog_enabled &= ~NMI_WATCHDOG_ENABLED;
+}
+
+static int __init hardlockup_panic_setup(char *str)
+{
+       if (!strncmp(str, "panic", 5))
+               hardlockup_panic = 1;
+       else if (!strncmp(str, "nopanic", 7))
+               hardlockup_panic = 0;
+       else if (!strncmp(str, "0", 1))
+               watchdog_enabled &= ~NMI_WATCHDOG_ENABLED;
+       else if (!strncmp(str, "1", 1))
+               watchdog_enabled |= NMI_WATCHDOG_ENABLED;
+       return 1;
+}
+__setup("nmi_watchdog=", hardlockup_panic_setup);
+
+#endif
+
+#ifdef CONFIG_SOFTLOCKUP_DETECTOR
 int __read_mostly soft_watchdog_enabled;
+#endif
+
 int __read_mostly watchdog_user_enabled;
 int __read_mostly watchdog_thresh = 10;
 
@@ -45,15 +88,9 @@ int __read_mostly watchdog_thresh = 10;
 int __read_mostly sysctl_softlockup_all_cpu_backtrace;
 int __read_mostly sysctl_hardlockup_all_cpu_backtrace;
 #endif
-static struct cpumask watchdog_cpumask __read_mostly;
+struct cpumask watchdog_cpumask __read_mostly;
 unsigned long *watchdog_cpumask_bits = cpumask_bits(&watchdog_cpumask);
 
-/* Helper for online, unparked cpus. */
-#define for_each_watchdog_cpu(cpu) \
-       for_each_cpu_and((cpu), cpu_online_mask, &watchdog_cpumask)
-
-atomic_t watchdog_park_in_progress = ATOMIC_INIT(0);
-
 /*
  * The 'watchdog_running' variable is set to 1 when the watchdog threads
  * are registered/started and is set to 0 when the watchdog threads are
@@ -72,7 +109,47 @@ static int __read_mostly watchdog_running;
  * of 'watchdog_running' cannot change while the watchdog is deactivated
  * temporarily (see related code in 'proc' handlers).
  */
-static int __read_mostly watchdog_suspended;
+int __read_mostly watchdog_suspended;
+
+/*
+ * These functions can be overridden if an architecture implements its
+ * own hardlockup detector.
+ *
+ * watchdog_nmi_enable/disable can be implemented to start and stop when
+ * softlockup watchdog threads start and stop. The arch must select the
+ * SOFTLOCKUP_DETECTOR Kconfig.
+ */
+int __weak watchdog_nmi_enable(unsigned int cpu)
+{
+       return 0;
+}
+void __weak watchdog_nmi_disable(unsigned int cpu)
+{
+}
+
+/*
+ * watchdog_nmi_reconfigure can be implemented to be notified after any
+ * watchdog configuration change. The arch hardlockup watchdog should
+ * respond to the following variables:
+ * - nmi_watchdog_enabled
+ * - watchdog_thresh
+ * - watchdog_cpumask
+ * - sysctl_hardlockup_all_cpu_backtrace
+ * - hardlockup_panic
+ * - watchdog_suspended
+ */
+void __weak watchdog_nmi_reconfigure(void)
+{
+}
+
+
+#ifdef CONFIG_SOFTLOCKUP_DETECTOR
+
+/* Helper for online, unparked cpus. */
+#define for_each_watchdog_cpu(cpu) \
+       for_each_cpu_and((cpu), cpu_online_mask, &watchdog_cpumask)
+
+atomic_t watchdog_park_in_progress = ATOMIC_INIT(0);
 
 static u64 __read_mostly sample_period;
 
@@ -120,6 +197,7 @@ static int __init softlockup_all_cpu_backtrace_setup(char *str)
        return 1;
 }
 __setup("softlockup_all_cpu_backtrace=", softlockup_all_cpu_backtrace_setup);
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
 static int __init hardlockup_all_cpu_backtrace_setup(char *str)
 {
        sysctl_hardlockup_all_cpu_backtrace =
@@ -128,6 +206,7 @@ static int __init hardlockup_all_cpu_backtrace_setup(char *str)
 }
 __setup("hardlockup_all_cpu_backtrace=", hardlockup_all_cpu_backtrace_setup);
 #endif
+#endif
 
 /*
  * Hard-lockup warnings should be triggered after just a few seconds. Soft-
@@ -213,18 +292,6 @@ void touch_softlockup_watchdog_sync(void)
        __this_cpu_write(watchdog_touch_ts, 0);
 }
 
-/* watchdog detector functions */
-bool is_hardlockup(void)
-{
-       unsigned long hrint = __this_cpu_read(hrtimer_interrupts);
-
-       if (__this_cpu_read(hrtimer_interrupts_saved) == hrint)
-               return true;
-
-       __this_cpu_write(hrtimer_interrupts_saved, hrint);
-       return false;
-}
-
 static int is_softlockup(unsigned long touch_ts)
 {
        unsigned long now = get_timestamp();
@@ -237,21 +304,21 @@ static int is_softlockup(unsigned long touch_ts)
        return 0;
 }
 
-static void watchdog_interrupt_count(void)
+/* watchdog detector functions */
+bool is_hardlockup(void)
 {
-       __this_cpu_inc(hrtimer_interrupts);
-}
+       unsigned long hrint = __this_cpu_read(hrtimer_interrupts);
 
-/*
- * These two functions are mostly architecture specific
- * defining them as weak here.
- */
-int __weak watchdog_nmi_enable(unsigned int cpu)
-{
-       return 0;
+       if (__this_cpu_read(hrtimer_interrupts_saved) == hrint)
+               return true;
+
+       __this_cpu_write(hrtimer_interrupts_saved, hrint);
+       return false;
 }
-void __weak watchdog_nmi_disable(unsigned int cpu)
+
+static void watchdog_interrupt_count(void)
 {
+       __this_cpu_inc(hrtimer_interrupts);
 }
 
 static int watchdog_enable_all_cpus(void);
@@ -502,57 +569,6 @@ static void watchdog_unpark_threads(void)
                kthread_unpark(per_cpu(softlockup_watchdog, cpu));
 }
 
-/*
- * Suspend the hard and soft lockup detector by parking the watchdog threads.
- */
-int lockup_detector_suspend(void)
-{
-       int ret = 0;
-
-       get_online_cpus();
-       mutex_lock(&watchdog_proc_mutex);
-       /*
-        * Multiple suspend requests can be active in parallel (counted by
-        * the 'watchdog_suspended' variable). If the watchdog threads are
-        * running, the first caller takes care that they will be parked.
-        * The state of 'watchdog_running' cannot change while a suspend
-        * request is active (see related code in 'proc' handlers).
-        */
-       if (watchdog_running && !watchdog_suspended)
-               ret = watchdog_park_threads();
-
-       if (ret == 0)
-               watchdog_suspended++;
-       else {
-               watchdog_disable_all_cpus();
-               pr_err("Failed to suspend lockup detectors, disabled\n");
-               watchdog_enabled = 0;
-       }
-
-       mutex_unlock(&watchdog_proc_mutex);
-
-       return ret;
-}
-
-/*
- * Resume the hard and soft lockup detector by unparking the watchdog threads.
- */
-void lockup_detector_resume(void)
-{
-       mutex_lock(&watchdog_proc_mutex);
-
-       watchdog_suspended--;
-       /*
-        * The watchdog threads are unparked if they were previously running
-        * and if there is no more active suspend request.
-        */
-       if (watchdog_running && !watchdog_suspended)
-               watchdog_unpark_threads();
-
-       mutex_unlock(&watchdog_proc_mutex);
-       put_online_cpus();
-}
-
 static int update_watchdog_all_cpus(void)
 {
        int ret;
@@ -605,6 +621,100 @@ static void watchdog_disable_all_cpus(void)
 }
 
 #ifdef CONFIG_SYSCTL
+static int watchdog_update_cpus(void)
+{
+       return smpboot_update_cpumask_percpu_thread(
+                   &watchdog_threads, &watchdog_cpumask);
+}
+#endif
+
+#else /* SOFTLOCKUP */
+static int watchdog_park_threads(void)
+{
+       return 0;
+}
+
+static void watchdog_unpark_threads(void)
+{
+}
+
+static int watchdog_enable_all_cpus(void)
+{
+       return 0;
+}
+
+static void watchdog_disable_all_cpus(void)
+{
+}
+
+#ifdef CONFIG_SYSCTL
+static int watchdog_update_cpus(void)
+{
+       return 0;
+}
+#endif
+
+static void set_sample_period(void)
+{
+}
+#endif /* SOFTLOCKUP */
+
+/*
+ * Suspend the hard and soft lockup detector by parking the watchdog threads.
+ */
+int lockup_detector_suspend(void)
+{
+       int ret = 0;
+
+       get_online_cpus();
+       mutex_lock(&watchdog_proc_mutex);
+       /*
+        * Multiple suspend requests can be active in parallel (counted by
+        * the 'watchdog_suspended' variable). If the watchdog threads are
+        * running, the first caller takes care that they will be parked.
+        * The state of 'watchdog_running' cannot change while a suspend
+        * request is active (see related code in 'proc' handlers).
+        */
+       if (watchdog_running && !watchdog_suspended)
+               ret = watchdog_park_threads();
+
+       if (ret == 0)
+               watchdog_suspended++;
+       else {
+               watchdog_disable_all_cpus();
+               pr_err("Failed to suspend lockup detectors, disabled\n");
+               watchdog_enabled = 0;
+       }
+
+       watchdog_nmi_reconfigure();
+
+       mutex_unlock(&watchdog_proc_mutex);
+
+       return ret;
+}
+
+/*
+ * Resume the hard and soft lockup detector by unparking the watchdog threads.
+ */
+void lockup_detector_resume(void)
+{
+       mutex_lock(&watchdog_proc_mutex);
+
+       watchdog_suspended--;
+       /*
+        * The watchdog threads are unparked if they were previously running
+        * and if there is no more active suspend request.
+        */
+       if (watchdog_running && !watchdog_suspended)
+               watchdog_unpark_threads();
+
+       watchdog_nmi_reconfigure();
+
+       mutex_unlock(&watchdog_proc_mutex);
+       put_online_cpus();
+}
+
+#ifdef CONFIG_SYSCTL
 
 /*
  * Update the run state of the lockup detectors.
@@ -625,6 +735,8 @@ static int proc_watchdog_update(void)
        else
                watchdog_disable_all_cpus();
 
+       watchdog_nmi_reconfigure();
+
        return err;
 
 }
@@ -810,10 +922,11 @@ int proc_watchdog_cpumask(struct ctl_table *table, int write,
                         * a temporary cpumask, so we are likely not in a
                         * position to do much else to make things better.
                         */
-                       if (smpboot_update_cpumask_percpu_thread(
-                                   &watchdog_threads, &watchdog_cpumask) != 0)
+                       if (watchdog_update_cpus() != 0)
                                pr_err("cpumask update failed\n");
                }
+
+               watchdog_nmi_reconfigure();
        }
 out:
        mutex_unlock(&watchdog_proc_mutex);
index 54a427d..295a0d8 100644 (file)
@@ -22,41 +22,9 @@ static DEFINE_PER_CPU(bool, hard_watchdog_warn);
 static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
 static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
 
-/* boot commands */
-/*
- * Should we panic when a soft-lockup or hard-lockup occurs:
- */
-unsigned int __read_mostly hardlockup_panic =
-                       CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE;
 static unsigned long hardlockup_allcpu_dumped;
-/*
- * We may not want to enable hard lockup detection by default in all cases,
- * for example when running the kernel as a guest on a hypervisor. In these
- * cases this function can be called to disable hard lockup detection. This
- * function should only be executed once by the boot processor before the
- * kernel command line parameters are parsed, because otherwise it is not
- * possible to override this in hardlockup_panic_setup().
- */
-void hardlockup_detector_disable(void)
-{
-       watchdog_enabled &= ~NMI_WATCHDOG_ENABLED;
-}
-
-static int __init hardlockup_panic_setup(char *str)
-{
-       if (!strncmp(str, "panic", 5))
-               hardlockup_panic = 1;
-       else if (!strncmp(str, "nopanic", 7))
-               hardlockup_panic = 0;
-       else if (!strncmp(str, "0", 1))
-               watchdog_enabled &= ~NMI_WATCHDOG_ENABLED;
-       else if (!strncmp(str, "1", 1))
-               watchdog_enabled |= NMI_WATCHDOG_ENABLED;
-       return 1;
-}
-__setup("nmi_watchdog=", hardlockup_panic_setup);
 
-void touch_nmi_watchdog(void)
+void arch_touch_nmi_watchdog(void)
 {
        /*
         * Using __raw here because some code paths have
@@ -66,9 +34,8 @@ void touch_nmi_watchdog(void)
         * going off.
         */
        raw_cpu_write(watchdog_nmi_touch, true);
-       touch_softlockup_watchdog();
 }
-EXPORT_SYMBOL(touch_nmi_watchdog);
+EXPORT_SYMBOL(arch_touch_nmi_watchdog);
 
 static struct perf_event_attr wd_hw_attr = {
        .type           = PERF_TYPE_HARDWARE,
index a86688f..ca937b0 100644 (file)
@@ -3577,6 +3577,13 @@ static bool wq_calc_node_cpumask(const struct workqueue_attrs *attrs, int node,
 
        /* yeap, return possible CPUs in @node that @attrs wants */
        cpumask_and(cpumask, attrs->cpumask, wq_numa_possible_cpumask[node]);
+
+       if (cpumask_empty(cpumask)) {
+               pr_warn_once("WARNING: workqueue cpumask: online intersect > "
+                               "possible intersect\n");
+               return false;
+       }
+
        return !cpumask_equal(cpumask, attrs->cpumask);
 
 use_dfl:
@@ -3744,8 +3751,12 @@ static int apply_workqueue_attrs_locked(struct workqueue_struct *wq,
                return -EINVAL;
 
        /* creating multiple pwqs breaks ordering guarantee */
-       if (WARN_ON((wq->flags & __WQ_ORDERED) && !list_empty(&wq->pwqs)))
-               return -EINVAL;
+       if (!list_empty(&wq->pwqs)) {
+               if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
+                       return -EINVAL;
+
+               wq->flags &= ~__WQ_ORDERED;
+       }
 
        ctx = apply_wqattrs_prepare(wq, attrs);
        if (!ctx)
@@ -3929,6 +3940,16 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
        struct workqueue_struct *wq;
        struct pool_workqueue *pwq;
 
+       /*
+        * Unbound && max_active == 1 used to imply ordered, which is no
+        * longer the case on NUMA machines due to per-node pools.  While
+        * alloc_ordered_workqueue() is the right way to create an ordered
+        * workqueue, keep the previous behavior to avoid subtle breakages
+        * on NUMA.
+        */
+       if ((flags & WQ_UNBOUND) && max_active == 1)
+               flags |= __WQ_ORDERED;
+
        /* see the comment above the definition of WQ_POWER_EFFICIENT */
        if ((flags & WQ_POWER_EFFICIENT) && wq_power_efficient)
                flags |= WQ_UNBOUND;
@@ -4119,13 +4140,14 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)
        struct pool_workqueue *pwq;
 
        /* disallow meddling with max_active for ordered workqueues */
-       if (WARN_ON(wq->flags & __WQ_ORDERED))
+       if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
                return;
 
        max_active = wq_clamp_max_active(max_active, wq->flags, wq->name);
 
        mutex_lock(&wq->mutex);
 
+       wq->flags &= ~__WQ_ORDERED;
        wq->saved_max_active = max_active;
 
        for_each_pwq(pwq, wq)
@@ -5253,7 +5275,7 @@ int workqueue_sysfs_register(struct workqueue_struct *wq)
         * attributes breaks ordering guarantee.  Disallow exposing ordered
         * workqueues.
         */
-       if (WARN_ON(wq->flags & __WQ_ORDERED))
+       if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
                return -EINVAL;
 
        wq->wq_dev = wq_dev = kzalloc(sizeof(*wq_dev), GFP_KERNEL);
index e20fc07..98fe715 100644 (file)
@@ -778,34 +778,45 @@ config DEBUG_SHIRQ
 menu "Debug Lockups and Hangs"
 
 config LOCKUP_DETECTOR
-       bool "Detect Hard and Soft Lockups"
+       bool
+
+config SOFTLOCKUP_DETECTOR
+       bool "Detect Soft Lockups"
        depends on DEBUG_KERNEL && !S390
+       select LOCKUP_DETECTOR
        help
          Say Y here to enable the kernel to act as a watchdog to detect
-         hard and soft lockups.
+         soft lockups.
 
          Softlockups are bugs that cause the kernel to loop in kernel
          mode for more than 20 seconds, without giving other tasks a
          chance to run.  The current stack trace is displayed upon
          detection and the system will stay locked up.
 
+config HARDLOCKUP_DETECTOR_PERF
+       bool
+       select SOFTLOCKUP_DETECTOR
+
+#
+# arch/ can define HAVE_HARDLOCKUP_DETECTOR_ARCH to provide their own hard
+# lockup detector rather than the perf based detector.
+#
+config HARDLOCKUP_DETECTOR
+       bool "Detect Hard Lockups"
+       depends on DEBUG_KERNEL && !S390
+       depends on HAVE_HARDLOCKUP_DETECTOR_PERF || HAVE_HARDLOCKUP_DETECTOR_ARCH
+       select LOCKUP_DETECTOR
+       select HARDLOCKUP_DETECTOR_PERF if HAVE_HARDLOCKUP_DETECTOR_PERF
+       select HARDLOCKUP_DETECTOR_ARCH if HAVE_HARDLOCKUP_DETECTOR_ARCH
+       help
+         Say Y here to enable the kernel to act as a watchdog to detect
+         hard lockups.
+
          Hardlockups are bugs that cause the CPU to loop in kernel mode
          for more than 10 seconds, without letting other interrupts have a
          chance to run.  The current stack trace is displayed upon detection
          and the system will stay locked up.
 
-         The overhead should be minimal.  A periodic hrtimer runs to
-         generate interrupts and kick the watchdog task every 4 seconds.
-         An NMI is generated every 10 seconds or so to check for hardlockups.
-
-         The frequency of hrtimer and NMI events and the soft and hard lockup
-         thresholds can be controlled through the sysctl watchdog_thresh.
-
-config HARDLOCKUP_DETECTOR
-       def_bool y
-       depends on LOCKUP_DETECTOR && !HAVE_NMI_WATCHDOG
-       depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI
-
 config BOOTPARAM_HARDLOCKUP_PANIC
        bool "Panic (Reboot) On Hard Lockups"
        depends on HARDLOCKUP_DETECTOR
@@ -826,7 +837,7 @@ config BOOTPARAM_HARDLOCKUP_PANIC_VALUE
 
 config BOOTPARAM_SOFTLOCKUP_PANIC
        bool "Panic (Reboot) On Soft Lockups"
-       depends on LOCKUP_DETECTOR
+       depends on SOFTLOCKUP_DETECTOR
        help
          Say Y here to enable the kernel to panic on "soft lockups",
          which are bugs that cause the kernel to loop in kernel
@@ -843,7 +854,7 @@ config BOOTPARAM_SOFTLOCKUP_PANIC
 
 config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE
        int
-       depends on LOCKUP_DETECTOR
+       depends on SOFTLOCKUP_DETECTOR
        range 0 1
        default 0 if !BOOTPARAM_SOFTLOCKUP_PANIC
        default 1 if BOOTPARAM_SOFTLOCKUP_PANIC
@@ -851,7 +862,7 @@ config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE
 config DETECT_HUNG_TASK
        bool "Detect Hung Tasks"
        depends on DEBUG_KERNEL
-       default LOCKUP_DETECTOR
+       default SOFTLOCKUP_DETECTOR
        help
          Say Y here to enable the kernel to detect "hung tasks",
          which are bugs that cause the task to be stuck in
@@ -1212,6 +1223,34 @@ config STACKTRACE
          It is also used by various kernel debugging features that require
          stack trace generation.
 
+config WARN_ALL_UNSEEDED_RANDOM
+       bool "Warn for all uses of unseeded randomness"
+       default n
+       help
+         Some parts of the kernel contain bugs relating to their use of
+         cryptographically secure random numbers before it's actually possible
+         to generate those numbers securely. This setting ensures that these
+         flaws don't go unnoticed, by enabling a message, should this ever
+         occur. This will allow people with obscure setups to know when things
+         are going wrong, so that they might contact developers about fixing
+         it.
+
+         Unfortunately, on some models of some architectures getting
+         a fully seeded CRNG is extremely difficult, and so this can
+         result in dmesg getting spammed for a surprisingly long
+         time.  This is really bad from a security perspective, and
+         so architecture maintainers really need to do what they can
+         to get the CRNG seeded sooner after the system is booted.
+         However, since users can not do anything actionble to
+         address this, by default the kernel will issue only a single
+         warning for the first use of unseeded randomness.
+
+         Say Y here if you want to receive warnings for all uses of
+         unseeded randomness.  This will be of use primarily for
+         those developers interersted in improving the security of
+         Linux kernels running on their architecture (or
+         subarchitecture).
+
 config DEBUG_KOBJECT
        bool "kobject debugging"
        depends on DEBUG_KERNEL
@@ -1785,6 +1824,17 @@ config TEST_FIRMWARE
 
          If unsure, say N.
 
+config TEST_SYSCTL
+       tristate "sysctl test driver"
+       default n
+       depends on PROC_SYSCTL
+       help
+         This builds the "test_sysctl" module. This driver enables to test the
+         proc sysctl interfaces available to drivers safely without affecting
+         production knobs which might alter system functionality.
+
+         If unsure, say N.
+
 config TEST_UDELAY
        tristate "udelay test driver"
        default n
@@ -1825,6 +1875,33 @@ config BUG_ON_DATA_CORRUPTION
 
          If unsure, say N.
 
+config TEST_KMOD
+       tristate "kmod stress tester"
+       default n
+       depends on m
+       depends on BLOCK && (64BIT || LBDAF)      # for XFS, BTRFS
+       depends on NETDEVICES && NET_CORE && INET # for TUN
+       select TEST_LKM
+       select XFS_FS
+       select TUN
+       select BTRFS_FS
+       help
+         Test the kernel's module loading mechanism: kmod. kmod implements
+         support to load modules using the Linux kernel's usermode helper.
+         This test provides a series of tests against kmod.
+
+         Although technically you can either build test_kmod as a module or
+         into the kernel we disallow building it into the kernel since
+         it stress tests request_module() and this will very likely cause
+         some issues by taking over precious threads available from other
+         module load requests, ultimately this could be fatal.
+
+         To run tests run:
+
+         tools/testing/selftests/kmod/kmod.sh --help
+
+         If unsure, say N.
+
 source "samples/Kconfig"
 
 source "lib/Kconfig.kgdb"
index 5a00832..40c1837 100644 (file)
@@ -46,6 +46,7 @@ obj-$(CONFIG_TEST_HEXDUMP) += test_hexdump.o
 obj-y += kstrtox.o
 obj-$(CONFIG_TEST_BPF) += test_bpf.o
 obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
+obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o
 obj-$(CONFIG_TEST_HASH) += test_hash.o test_siphash.o
 obj-$(CONFIG_TEST_KASAN) += test_kasan.o
 obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
@@ -60,6 +61,7 @@ obj-$(CONFIG_TEST_PRINTF) += test_printf.o
 obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o
 obj-$(CONFIG_TEST_UUID) += test_uuid.o
 obj-$(CONFIG_TEST_PARMAN) += test_parman.o
+obj-$(CONFIG_TEST_KMOD) += test_kmod.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
index fd70c0e..62ab629 100644 (file)
@@ -153,8 +153,10 @@ static __init void test_atomic64(void)
        long long v0 = 0xaaa31337c001d00dLL;
        long long v1 = 0xdeadbeefdeafcafeLL;
        long long v2 = 0xfaceabadf00df001LL;
+       long long v3 = 0x8000000000000000LL;
        long long onestwos = 0x1111111122222222LL;
        long long one = 1LL;
+       int r_int;
 
        atomic64_t v = ATOMIC64_INIT(v0);
        long long r = v0;
@@ -240,6 +242,11 @@ static __init void test_atomic64(void)
        BUG_ON(!atomic64_inc_not_zero(&v));
        r += one;
        BUG_ON(v.counter != r);
+
+       /* Confirm the return value fits in an int, even if the value doesn't */
+       INIT(v3);
+       r_int = atomic64_inc_not_zero(&v);
+       BUG_ON(!r_int);
 }
 
 static __init int test_atomics_init(void)
index 4ff1571..7d315fd 100644 (file)
@@ -107,6 +107,15 @@ static inline bool fail_stacktrace(struct fault_attr *attr)
 
 bool should_fail(struct fault_attr *attr, ssize_t size)
 {
+       if (in_task()) {
+               unsigned int fail_nth = READ_ONCE(current->fail_nth);
+
+               if (fail_nth && !WRITE_ONCE(current->fail_nth, fail_nth - 1))
+                       goto fail;
+
+               return false;
+       }
+
        /* No need to check any other properties if the probability is 0 */
        if (attr->probability == 0)
                return false;
@@ -134,6 +143,7 @@ bool should_fail(struct fault_attr *attr, ssize_t size)
        if (!fail_stacktrace(attr))
                return false;
 
+fail:
        fail_dump(attr);
 
        if (atomic_read(&attr->times) != -1)
index fb52435..ee79b7a 100644 (file)
@@ -27,6 +27,30 @@ static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
        [NLA_S64]       = sizeof(s64),
 };
 
+static int validate_nla_bitfield32(const struct nlattr *nla,
+                                  u32 *valid_flags_allowed)
+{
+       const struct nla_bitfield32 *bf = nla_data(nla);
+       u32 *valid_flags_mask = valid_flags_allowed;
+
+       if (!valid_flags_allowed)
+               return -EINVAL;
+
+       /*disallow invalid bit selector */
+       if (bf->selector & ~*valid_flags_mask)
+               return -EINVAL;
+
+       /*disallow invalid bit values */
+       if (bf->value & ~*valid_flags_mask)
+               return -EINVAL;
+
+       /*disallow valid bit values that are not selected*/
+       if (bf->value & ~bf->selector)
+               return -EINVAL;
+
+       return 0;
+}
+
 static int validate_nla(const struct nlattr *nla, int maxtype,
                        const struct nla_policy *policy)
 {
@@ -46,6 +70,12 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
                        return -ERANGE;
                break;
 
+       case NLA_BITFIELD32:
+               if (attrlen != sizeof(struct nla_bitfield32))
+                       return -ERANGE;
+
+               return validate_nla_bitfield32(nla, pt->validation_data);
+
        case NLA_NUL_STRING:
                if (pt->len)
                        minlen = min_t(int, attrlen, pt->len + 1);
index 8ee7e5e..3bf4a99 100644 (file)
@@ -72,6 +72,13 @@ void percpu_counter_set(struct percpu_counter *fbc, s64 amount)
 }
 EXPORT_SYMBOL(percpu_counter_set);
 
+/**
+ * This function is both preempt and irq safe. The former is due to explicit
+ * preemption disable. The latter is guaranteed by the fact that the slow path
+ * is explicitly protected by an irq-safe spinlock whereas the fast patch uses
+ * this_cpu_add which is irq-safe by definition. Hence there is no need muck
+ * with irq state before calling this one
+ */
 void percpu_counter_add_batch(struct percpu_counter *fbc, s64 amount, s32 batch)
 {
        s64 count;
index 42466c1..707ca5d 100644 (file)
@@ -234,7 +234,7 @@ static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
 
        INIT_LIST_HEAD(&tbl->walkers);
 
-       get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd));
+       tbl->hash_rnd = get_random_u32();
 
        for (i = 0; i < nbuckets; i++)
                INIT_RHT_NULLS_HEAD(tbl->buckets[i], ht, i);
index 1c1fc91..ebbb99c 100644 (file)
@@ -978,3 +978,10 @@ char *strreplace(char *s, char old, char new)
        return s;
 }
 EXPORT_SYMBOL(strreplace);
+
+void fortify_panic(const char *name)
+{
+       pr_emerg("detected buffer overflow in %s\n", name);
+       BUG();
+}
+EXPORT_SYMBOL(fortify_panic);
diff --git a/lib/test_kmod.c b/lib/test_kmod.c
new file mode 100644 (file)
index 0000000..6c1d678
--- /dev/null
@@ -0,0 +1,1246 @@
+/*
+ * kmod stress test driver
+ *
+ * Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org>
+ *
+ * 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; or, when distributed separately from the Linux kernel or
+ * when incorporated into other software packages, subject to the following
+ * license:
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of copyleft-next (version 0.3.1 or later) as published
+ * at http://copyleft-next.org/.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+/*
+ * This driver provides an interface to trigger and test the kernel's
+ * module loader through a series of configurations and a few triggers.
+ * To test this driver use the following script as root:
+ *
+ * tools/testing/selftests/kmod/kmod.sh --help
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/printk.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+
+#define TEST_START_NUM_THREADS 50
+#define TEST_START_DRIVER      "test_module"
+#define TEST_START_TEST_FS     "xfs"
+#define TEST_START_TEST_CASE   TEST_KMOD_DRIVER
+
+
+static bool force_init_test = false;
+module_param(force_init_test, bool_enable_only, 0644);
+MODULE_PARM_DESC(force_init_test,
+                "Force kicking a test immediately after driver loads");
+
+/*
+ * For device allocation / registration
+ */
+static DEFINE_MUTEX(reg_dev_mutex);
+static LIST_HEAD(reg_test_devs);
+
+/*
+ * num_test_devs actually represents the *next* ID of the next
+ * device we will allow to create.
+ */
+static int num_test_devs;
+
+/**
+ * enum kmod_test_case - linker table test case
+ *
+ * If you add a  test case, please be sure to review if you need to se
+ * @need_mod_put for your tests case.
+ *
+ * @TEST_KMOD_DRIVER: stress tests request_module()
+ * @TEST_KMOD_FS_TYPE: stress tests get_fs_type()
+ */
+enum kmod_test_case {
+       __TEST_KMOD_INVALID = 0,
+
+       TEST_KMOD_DRIVER,
+       TEST_KMOD_FS_TYPE,
+
+       __TEST_KMOD_MAX,
+};
+
+struct test_config {
+       char *test_driver;
+       char *test_fs;
+       unsigned int num_threads;
+       enum kmod_test_case test_case;
+       int test_result;
+};
+
+struct kmod_test_device;
+
+/**
+ * kmod_test_device_info - thread info
+ *
+ * @ret_sync: return value if request_module() is used, sync request for
+ *     @TEST_KMOD_DRIVER
+ * @fs_sync: return value of get_fs_type() for @TEST_KMOD_FS_TYPE
+ * @thread_idx: thread ID
+ * @test_dev: test device test is being performed under
+ * @need_mod_put: Some tests (get_fs_type() is one) requires putting the module
+ *     (module_put(fs_sync->owner)) when done, otherwise you will not be able
+ *     to unload the respective modules and re-test. We use this to keep
+ *     accounting of when we need this and to help out in case we need to
+ *     error out and deal with module_put() on error.
+ */
+struct kmod_test_device_info {
+       int ret_sync;
+       struct file_system_type *fs_sync;
+       struct task_struct *task_sync;
+       unsigned int thread_idx;
+       struct kmod_test_device *test_dev;
+       bool need_mod_put;
+};
+
+/**
+ * kmod_test_device - test device to help test kmod
+ *
+ * @dev_idx: unique ID for test device
+ * @config: configuration for the test
+ * @misc_dev: we use a misc device under the hood
+ * @dev: pointer to misc_dev's own struct device
+ * @config_mutex: protects configuration of test
+ * @trigger_mutex: the test trigger can only be fired once at a time
+ * @thread_lock: protects @done count, and the @info per each thread
+ * @done: number of threads which have completed or failed
+ * @test_is_oom: when we run out of memory, use this to halt moving forward
+ * @kthreads_done: completion used to signal when all work is done
+ * @list: needed to be part of the reg_test_devs
+ * @info: array of info for each thread
+ */
+struct kmod_test_device {
+       int dev_idx;
+       struct test_config config;
+       struct miscdevice misc_dev;
+       struct device *dev;
+       struct mutex config_mutex;
+       struct mutex trigger_mutex;
+       struct mutex thread_mutex;
+
+       unsigned int done;
+
+       bool test_is_oom;
+       struct completion kthreads_done;
+       struct list_head list;
+
+       struct kmod_test_device_info *info;
+};
+
+static const char *test_case_str(enum kmod_test_case test_case)
+{
+       switch (test_case) {
+       case TEST_KMOD_DRIVER:
+               return "TEST_KMOD_DRIVER";
+       case TEST_KMOD_FS_TYPE:
+               return "TEST_KMOD_FS_TYPE";
+       default:
+               return "invalid";
+       }
+}
+
+static struct miscdevice *dev_to_misc_dev(struct device *dev)
+{
+       return dev_get_drvdata(dev);
+}
+
+static struct kmod_test_device *misc_dev_to_test_dev(struct miscdevice *misc_dev)
+{
+       return container_of(misc_dev, struct kmod_test_device, misc_dev);
+}
+
+static struct kmod_test_device *dev_to_test_dev(struct device *dev)
+{
+       struct miscdevice *misc_dev;
+
+       misc_dev = dev_to_misc_dev(dev);
+
+       return misc_dev_to_test_dev(misc_dev);
+}
+
+/* Must run with thread_mutex held */
+static void kmod_test_done_check(struct kmod_test_device *test_dev,
+                                unsigned int idx)
+{
+       struct test_config *config = &test_dev->config;
+
+       test_dev->done++;
+       dev_dbg(test_dev->dev, "Done thread count: %u\n", test_dev->done);
+
+       if (test_dev->done == config->num_threads) {
+               dev_info(test_dev->dev, "Done: %u threads have all run now\n",
+                        test_dev->done);
+               dev_info(test_dev->dev, "Last thread to run: %u\n", idx);
+               complete(&test_dev->kthreads_done);
+       }
+}
+
+static void test_kmod_put_module(struct kmod_test_device_info *info)
+{
+       struct kmod_test_device *test_dev = info->test_dev;
+       struct test_config *config = &test_dev->config;
+
+       if (!info->need_mod_put)
+               return;
+
+       switch (config->test_case) {
+       case TEST_KMOD_DRIVER:
+               break;
+       case TEST_KMOD_FS_TYPE:
+               if (info && info->fs_sync && info->fs_sync->owner)
+                       module_put(info->fs_sync->owner);
+               break;
+       default:
+               BUG();
+       }
+
+       info->need_mod_put = true;
+}
+
+static int run_request(void *data)
+{
+       struct kmod_test_device_info *info = data;
+       struct kmod_test_device *test_dev = info->test_dev;
+       struct test_config *config = &test_dev->config;
+
+       switch (config->test_case) {
+       case TEST_KMOD_DRIVER:
+               info->ret_sync = request_module("%s", config->test_driver);
+               break;
+       case TEST_KMOD_FS_TYPE:
+               info->fs_sync = get_fs_type(config->test_fs);
+               info->need_mod_put = true;
+               break;
+       default:
+               /* __trigger_config_run() already checked for test sanity */
+               BUG();
+               return -EINVAL;
+       }
+
+       dev_dbg(test_dev->dev, "Ran thread %u\n", info->thread_idx);
+
+       test_kmod_put_module(info);
+
+       mutex_lock(&test_dev->thread_mutex);
+       info->task_sync = NULL;
+       kmod_test_done_check(test_dev, info->thread_idx);
+       mutex_unlock(&test_dev->thread_mutex);
+
+       return 0;
+}
+
+static int tally_work_test(struct kmod_test_device_info *info)
+{
+       struct kmod_test_device *test_dev = info->test_dev;
+       struct test_config *config = &test_dev->config;
+       int err_ret = 0;
+
+       switch (config->test_case) {
+       case TEST_KMOD_DRIVER:
+               /*
+                * Only capture errors, if one is found that's
+                * enough, for now.
+                */
+               if (info->ret_sync != 0)
+                       err_ret = info->ret_sync;
+               dev_info(test_dev->dev,
+                        "Sync thread %d return status: %d\n",
+                        info->thread_idx, info->ret_sync);
+               break;
+       case TEST_KMOD_FS_TYPE:
+               /* For now we make this simple */
+               if (!info->fs_sync)
+                       err_ret = -EINVAL;
+               dev_info(test_dev->dev, "Sync thread %u fs: %s\n",
+                        info->thread_idx, info->fs_sync ? config->test_fs :
+                        "NULL");
+               break;
+       default:
+               BUG();
+       }
+
+       return err_ret;
+}
+
+/*
+ * XXX: add result option to display if all errors did not match.
+ * For now we just keep any error code if one was found.
+ *
+ * If this ran it means *all* tasks were created fine and we
+ * are now just collecting results.
+ *
+ * Only propagate errors, do not override with a subsequent sucess case.
+ */
+static void tally_up_work(struct kmod_test_device *test_dev)
+{
+       struct test_config *config = &test_dev->config;
+       struct kmod_test_device_info *info;
+       unsigned int idx;
+       int err_ret = 0;
+       int ret = 0;
+
+       mutex_lock(&test_dev->thread_mutex);
+
+       dev_info(test_dev->dev, "Results:\n");
+
+       for (idx=0; idx < config->num_threads; idx++) {
+               info = &test_dev->info[idx];
+               ret = tally_work_test(info);
+               if (ret)
+                       err_ret = ret;
+       }
+
+       /*
+        * Note: request_module() returns 256 for a module not found even
+        * though modprobe itself returns 1.
+        */
+       config->test_result = err_ret;
+
+       mutex_unlock(&test_dev->thread_mutex);
+}
+
+static int try_one_request(struct kmod_test_device *test_dev, unsigned int idx)
+{
+       struct kmod_test_device_info *info = &test_dev->info[idx];
+       int fail_ret = -ENOMEM;
+
+       mutex_lock(&test_dev->thread_mutex);
+
+       info->thread_idx = idx;
+       info->test_dev = test_dev;
+       info->task_sync = kthread_run(run_request, info, "%s-%u",
+                                     KBUILD_MODNAME, idx);
+
+       if (!info->task_sync || IS_ERR(info->task_sync)) {
+               test_dev->test_is_oom = true;
+               dev_err(test_dev->dev, "Setting up thread %u failed\n", idx);
+               info->task_sync = NULL;
+               goto err_out;
+       } else
+               dev_dbg(test_dev->dev, "Kicked off thread %u\n", idx);
+
+       mutex_unlock(&test_dev->thread_mutex);
+
+       return 0;
+
+err_out:
+       info->ret_sync = fail_ret;
+       mutex_unlock(&test_dev->thread_mutex);
+
+       return fail_ret;
+}
+
+static void test_dev_kmod_stop_tests(struct kmod_test_device *test_dev)
+{
+       struct test_config *config = &test_dev->config;
+       struct kmod_test_device_info *info;
+       unsigned int i;
+
+       dev_info(test_dev->dev, "Ending request_module() tests\n");
+
+       mutex_lock(&test_dev->thread_mutex);
+
+       for (i=0; i < config->num_threads; i++) {
+               info = &test_dev->info[i];
+               if (info->task_sync && !IS_ERR(info->task_sync)) {
+                       dev_info(test_dev->dev,
+                                "Stopping still-running thread %i\n", i);
+                       kthread_stop(info->task_sync);
+               }
+
+               /*
+                * info->task_sync is well protected, it can only be
+                * NULL or a pointer to a struct. If its NULL we either
+                * never ran, or we did and we completed the work. Completed
+                * tasks *always* put the module for us. This is a sanity
+                * check -- just in case.
+                */
+               if (info->task_sync && info->need_mod_put)
+                       test_kmod_put_module(info);
+       }
+
+       mutex_unlock(&test_dev->thread_mutex);
+}
+
+/*
+ * Only wait *iff* we did not run into any errors during all of our thread
+ * set up. If run into any issues we stop threads and just bail out with
+ * an error to the trigger. This also means we don't need any tally work
+ * for any threads which fail.
+ */
+static int try_requests(struct kmod_test_device *test_dev)
+{
+       struct test_config *config = &test_dev->config;
+       unsigned int idx;
+       int ret;
+       bool any_error = false;
+
+       for (idx=0; idx < config->num_threads; idx++) {
+               if (test_dev->test_is_oom) {
+                       any_error = true;
+                       break;
+               }
+
+               ret = try_one_request(test_dev, idx);
+               if (ret) {
+                       any_error = true;
+                       break;
+               }
+       }
+
+       if (!any_error) {
+               test_dev->test_is_oom = false;
+               dev_info(test_dev->dev,
+                        "No errors were found while initializing threads\n");
+               wait_for_completion(&test_dev->kthreads_done);
+               tally_up_work(test_dev);
+       } else {
+               test_dev->test_is_oom = true;
+               dev_info(test_dev->dev,
+                        "At least one thread failed to start, stop all work\n");
+               test_dev_kmod_stop_tests(test_dev);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int run_test_driver(struct kmod_test_device *test_dev)
+{
+       struct test_config *config = &test_dev->config;
+
+       dev_info(test_dev->dev, "Test case: %s (%u)\n",
+                test_case_str(config->test_case),
+                config->test_case);
+       dev_info(test_dev->dev, "Test driver to load: %s\n",
+                config->test_driver);
+       dev_info(test_dev->dev, "Number of threads to run: %u\n",
+                config->num_threads);
+       dev_info(test_dev->dev, "Thread IDs will range from 0 - %u\n",
+                config->num_threads - 1);
+
+       return try_requests(test_dev);
+}
+
+static int run_test_fs_type(struct kmod_test_device *test_dev)
+{
+       struct test_config *config = &test_dev->config;
+
+       dev_info(test_dev->dev, "Test case: %s (%u)\n",
+                test_case_str(config->test_case),
+                config->test_case);
+       dev_info(test_dev->dev, "Test filesystem to load: %s\n",
+                config->test_fs);
+       dev_info(test_dev->dev, "Number of threads to run: %u\n",
+                config->num_threads);
+       dev_info(test_dev->dev, "Thread IDs will range from 0 - %u\n",
+                config->num_threads - 1);
+
+       return try_requests(test_dev);
+}
+
+static ssize_t config_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       struct test_config *config = &test_dev->config;
+       int len = 0;
+
+       mutex_lock(&test_dev->config_mutex);
+
+       len += snprintf(buf, PAGE_SIZE,
+                       "Custom trigger configuration for: %s\n",
+                       dev_name(dev));
+
+       len += snprintf(buf+len, PAGE_SIZE - len,
+                       "Number of threads:\t%u\n",
+                       config->num_threads);
+
+       len += snprintf(buf+len, PAGE_SIZE - len,
+                       "Test_case:\t%s (%u)\n",
+                       test_case_str(config->test_case),
+                       config->test_case);
+
+       if (config->test_driver)
+               len += snprintf(buf+len, PAGE_SIZE - len,
+                               "driver:\t%s\n",
+                               config->test_driver);
+       else
+               len += snprintf(buf+len, PAGE_SIZE - len,
+                               "driver:\tEMTPY\n");
+
+       if (config->test_fs)
+               len += snprintf(buf+len, PAGE_SIZE - len,
+                               "fs:\t%s\n",
+                               config->test_fs);
+       else
+               len += snprintf(buf+len, PAGE_SIZE - len,
+                               "fs:\tEMTPY\n");
+
+       mutex_unlock(&test_dev->config_mutex);
+
+       return len;
+}
+static DEVICE_ATTR_RO(config);
+
+/*
+ * This ensures we don't allow kicking threads through if our configuration
+ * is faulty.
+ */
+static int __trigger_config_run(struct kmod_test_device *test_dev)
+{
+       struct test_config *config = &test_dev->config;
+
+       test_dev->done = 0;
+
+       switch (config->test_case) {
+       case TEST_KMOD_DRIVER:
+               return run_test_driver(test_dev);
+       case TEST_KMOD_FS_TYPE:
+               return run_test_fs_type(test_dev);
+       default:
+               dev_warn(test_dev->dev,
+                        "Invalid test case requested: %u\n",
+                        config->test_case);
+               return -EINVAL;
+       }
+}
+
+static int trigger_config_run(struct kmod_test_device *test_dev)
+{
+       struct test_config *config = &test_dev->config;
+       int ret;
+
+       mutex_lock(&test_dev->trigger_mutex);
+       mutex_lock(&test_dev->config_mutex);
+
+       ret = __trigger_config_run(test_dev);
+       if (ret < 0)
+               goto out;
+       dev_info(test_dev->dev, "General test result: %d\n",
+                config->test_result);
+
+       /*
+        * We must return 0 after a trigger even unless something went
+        * wrong with the setup of the test. If the test setup went fine
+        * then userspace must just check the result of config->test_result.
+        * One issue with relying on the return from a call in the kernel
+        * is if the kernel returns a possitive value using this trigger
+        * will not return the value to userspace, it would be lost.
+        *
+        * By not relying on capturing the return value of tests we are using
+        * through the trigger it also us to run tests with set -e and only
+        * fail when something went wrong with the driver upon trigger
+        * requests.
+        */
+       ret = 0;
+
+out:
+       mutex_unlock(&test_dev->config_mutex);
+       mutex_unlock(&test_dev->trigger_mutex);
+
+       return ret;
+}
+
+static ssize_t
+trigger_config_store(struct device *dev,
+                    struct device_attribute *attr,
+                    const char *buf, size_t count)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       int ret;
+
+       if (test_dev->test_is_oom)
+               return -ENOMEM;
+
+       /* For all intents and purposes we don't care what userspace
+        * sent this trigger, we care only that we were triggered.
+        * We treat the return value only for caputuring issues with
+        * the test setup. At this point all the test variables should
+        * have been allocated so typically this should never fail.
+        */
+       ret = trigger_config_run(test_dev);
+       if (unlikely(ret < 0))
+               goto out;
+
+       /*
+        * Note: any return > 0 will be treated as success
+        * and the error value will not be available to userspace.
+        * Do not rely on trying to send to userspace a test value
+        * return value as possitive return errors will be lost.
+        */
+       if (WARN_ON(ret > 0))
+               return -EINVAL;
+
+       ret = count;
+out:
+       return ret;
+}
+static DEVICE_ATTR_WO(trigger_config);
+
+/*
+ * XXX: move to kstrncpy() once merged.
+ *
+ * Users should use kfree_const() when freeing these.
+ */
+static int __kstrncpy(char **dst, const char *name, size_t count, gfp_t gfp)
+{
+       *dst = kstrndup(name, count, gfp);
+       if (!*dst)
+               return -ENOSPC;
+       return count;
+}
+
+static int config_copy_test_driver_name(struct test_config *config,
+                                   const char *name,
+                                   size_t count)
+{
+       return __kstrncpy(&config->test_driver, name, count, GFP_KERNEL);
+}
+
+
+static int config_copy_test_fs(struct test_config *config, const char *name,
+                              size_t count)
+{
+       return __kstrncpy(&config->test_fs, name, count, GFP_KERNEL);
+}
+
+static void __kmod_config_free(struct test_config *config)
+{
+       if (!config)
+               return;
+
+       kfree_const(config->test_driver);
+       config->test_driver = NULL;
+
+       kfree_const(config->test_fs);
+       config->test_driver = NULL;
+}
+
+static void kmod_config_free(struct kmod_test_device *test_dev)
+{
+       struct test_config *config;
+
+       if (!test_dev)
+               return;
+
+       config = &test_dev->config;
+
+       mutex_lock(&test_dev->config_mutex);
+       __kmod_config_free(config);
+       mutex_unlock(&test_dev->config_mutex);
+}
+
+static ssize_t config_test_driver_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       struct test_config *config = &test_dev->config;
+       int copied;
+
+       mutex_lock(&test_dev->config_mutex);
+
+       kfree_const(config->test_driver);
+       config->test_driver = NULL;
+
+       copied = config_copy_test_driver_name(config, buf, count);
+       mutex_unlock(&test_dev->config_mutex);
+
+       return copied;
+}
+
+/*
+ * As per sysfs_kf_seq_show() the buf is max PAGE_SIZE.
+ */
+static ssize_t config_test_show_str(struct mutex *config_mutex,
+                                   char *dst,
+                                   char *src)
+{
+       int len;
+
+       mutex_lock(config_mutex);
+       len = snprintf(dst, PAGE_SIZE, "%s\n", src);
+       mutex_unlock(config_mutex);
+
+       return len;
+}
+
+static ssize_t config_test_driver_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       struct test_config *config = &test_dev->config;
+
+       return config_test_show_str(&test_dev->config_mutex, buf,
+                                   config->test_driver);
+}
+static DEVICE_ATTR(config_test_driver, 0644, config_test_driver_show,
+                  config_test_driver_store);
+
+static ssize_t config_test_fs_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       struct test_config *config = &test_dev->config;
+       int copied;
+
+       mutex_lock(&test_dev->config_mutex);
+
+       kfree_const(config->test_fs);
+       config->test_fs = NULL;
+
+       copied = config_copy_test_fs(config, buf, count);
+       mutex_unlock(&test_dev->config_mutex);
+
+       return copied;
+}
+
+static ssize_t config_test_fs_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       struct test_config *config = &test_dev->config;
+
+       return config_test_show_str(&test_dev->config_mutex, buf,
+                                   config->test_fs);
+}
+static DEVICE_ATTR(config_test_fs, 0644, config_test_fs_show,
+                  config_test_fs_store);
+
+static int trigger_config_run_type(struct kmod_test_device *test_dev,
+                                  enum kmod_test_case test_case,
+                                  const char *test_str)
+{
+       int copied = 0;
+       struct test_config *config = &test_dev->config;
+
+       mutex_lock(&test_dev->config_mutex);
+
+       switch (test_case) {
+       case TEST_KMOD_DRIVER:
+               kfree_const(config->test_driver);
+               config->test_driver = NULL;
+               copied = config_copy_test_driver_name(config, test_str,
+                                                     strlen(test_str));
+               break;
+       case TEST_KMOD_FS_TYPE:
+               break;
+               kfree_const(config->test_fs);
+               config->test_driver = NULL;
+               copied = config_copy_test_fs(config, test_str,
+                                            strlen(test_str));
+       default:
+               mutex_unlock(&test_dev->config_mutex);
+               return -EINVAL;
+       }
+
+       config->test_case = test_case;
+
+       mutex_unlock(&test_dev->config_mutex);
+
+       if (copied <= 0 || copied != strlen(test_str)) {
+               test_dev->test_is_oom = true;
+               return -ENOMEM;
+       }
+
+       test_dev->test_is_oom = false;
+
+       return trigger_config_run(test_dev);
+}
+
+static void free_test_dev_info(struct kmod_test_device *test_dev)
+{
+       vfree(test_dev->info);
+       test_dev->info = NULL;
+}
+
+static int kmod_config_sync_info(struct kmod_test_device *test_dev)
+{
+       struct test_config *config = &test_dev->config;
+
+       free_test_dev_info(test_dev);
+       test_dev->info = vzalloc(config->num_threads *
+                                sizeof(struct kmod_test_device_info));
+       if (!test_dev->info) {
+               dev_err(test_dev->dev, "Cannot alloc test_dev info\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/*
+ * Old kernels may not have this, if you want to port this code to
+ * test it on older kernels.
+ */
+#ifdef get_kmod_umh_limit
+static unsigned int kmod_init_test_thread_limit(void)
+{
+       return get_kmod_umh_limit();
+}
+#else
+static unsigned int kmod_init_test_thread_limit(void)
+{
+       return TEST_START_NUM_THREADS;
+}
+#endif
+
+static int __kmod_config_init(struct kmod_test_device *test_dev)
+{
+       struct test_config *config = &test_dev->config;
+       int ret = -ENOMEM, copied;
+
+       __kmod_config_free(config);
+
+       copied = config_copy_test_driver_name(config, TEST_START_DRIVER,
+                                             strlen(TEST_START_DRIVER));
+       if (copied != strlen(TEST_START_DRIVER))
+               goto err_out;
+
+       copied = config_copy_test_fs(config, TEST_START_TEST_FS,
+                                    strlen(TEST_START_TEST_FS));
+       if (copied != strlen(TEST_START_TEST_FS))
+               goto err_out;
+
+       config->num_threads = kmod_init_test_thread_limit();
+       config->test_result = 0;
+       config->test_case = TEST_START_TEST_CASE;
+
+       ret = kmod_config_sync_info(test_dev);
+       if (ret)
+               goto err_out;
+
+       test_dev->test_is_oom = false;
+
+       return 0;
+
+err_out:
+       test_dev->test_is_oom = true;
+       WARN_ON(test_dev->test_is_oom);
+
+       __kmod_config_free(config);
+
+       return ret;
+}
+
+static ssize_t reset_store(struct device *dev,
+                          struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       int ret;
+
+       mutex_lock(&test_dev->trigger_mutex);
+       mutex_lock(&test_dev->config_mutex);
+
+       ret = __kmod_config_init(test_dev);
+       if (ret < 0) {
+               ret = -ENOMEM;
+               dev_err(dev, "could not alloc settings for config trigger: %d\n",
+                      ret);
+               goto out;
+       }
+
+       dev_info(dev, "reset\n");
+       ret = count;
+
+out:
+       mutex_unlock(&test_dev->config_mutex);
+       mutex_unlock(&test_dev->trigger_mutex);
+
+       return ret;
+}
+static DEVICE_ATTR_WO(reset);
+
+static int test_dev_config_update_uint_sync(struct kmod_test_device *test_dev,
+                                           const char *buf, size_t size,
+                                           unsigned int *config,
+                                           int (*test_sync)(struct kmod_test_device *test_dev))
+{
+       int ret;
+       long new;
+       unsigned int old_val;
+
+       ret = kstrtol(buf, 10, &new);
+       if (ret)
+               return ret;
+
+       if (new > UINT_MAX)
+               return -EINVAL;
+
+       mutex_lock(&test_dev->config_mutex);
+
+       old_val = *config;
+       *(unsigned int *)config = new;
+
+       ret = test_sync(test_dev);
+       if (ret) {
+               *(unsigned int *)config = old_val;
+
+               ret = test_sync(test_dev);
+               WARN_ON(ret);
+
+               mutex_unlock(&test_dev->config_mutex);
+               return -EINVAL;
+       }
+
+       mutex_unlock(&test_dev->config_mutex);
+       /* Always return full write size even if we didn't consume all */
+       return size;
+}
+
+static int test_dev_config_update_uint_range(struct kmod_test_device *test_dev,
+                                            const char *buf, size_t size,
+                                            unsigned int *config,
+                                            unsigned int min,
+                                            unsigned int max)
+{
+       int ret;
+       long new;
+
+       ret = kstrtol(buf, 10, &new);
+       if (ret)
+               return ret;
+
+       if (new < min || new >  max || new > UINT_MAX)
+               return -EINVAL;
+
+       mutex_lock(&test_dev->config_mutex);
+       *config = new;
+       mutex_unlock(&test_dev->config_mutex);
+
+       /* Always return full write size even if we didn't consume all */
+       return size;
+}
+
+static int test_dev_config_update_int(struct kmod_test_device *test_dev,
+                                     const char *buf, size_t size,
+                                     int *config)
+{
+       int ret;
+       long new;
+
+       ret = kstrtol(buf, 10, &new);
+       if (ret)
+               return ret;
+
+       if (new > INT_MAX || new < INT_MIN)
+               return -EINVAL;
+
+       mutex_lock(&test_dev->config_mutex);
+       *config = new;
+       mutex_unlock(&test_dev->config_mutex);
+       /* Always return full write size even if we didn't consume all */
+       return size;
+}
+
+static ssize_t test_dev_config_show_int(struct kmod_test_device *test_dev,
+                                       char *buf,
+                                       int config)
+{
+       int val;
+
+       mutex_lock(&test_dev->config_mutex);
+       val = config;
+       mutex_unlock(&test_dev->config_mutex);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t test_dev_config_show_uint(struct kmod_test_device *test_dev,
+                                        char *buf,
+                                        unsigned int config)
+{
+       unsigned int val;
+
+       mutex_lock(&test_dev->config_mutex);
+       val = config;
+       mutex_unlock(&test_dev->config_mutex);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", val);
+}
+
+static ssize_t test_result_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       struct test_config *config = &test_dev->config;
+
+       return test_dev_config_update_int(test_dev, buf, count,
+                                         &config->test_result);
+}
+
+static ssize_t config_num_threads_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       struct test_config *config = &test_dev->config;
+
+       return test_dev_config_update_uint_sync(test_dev, buf, count,
+                                               &config->num_threads,
+                                               kmod_config_sync_info);
+}
+
+static ssize_t config_num_threads_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       struct test_config *config = &test_dev->config;
+
+       return test_dev_config_show_int(test_dev, buf, config->num_threads);
+}
+static DEVICE_ATTR(config_num_threads, 0644, config_num_threads_show,
+                  config_num_threads_store);
+
+static ssize_t config_test_case_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       struct test_config *config = &test_dev->config;
+
+       return test_dev_config_update_uint_range(test_dev, buf, count,
+                                                &config->test_case,
+                                                __TEST_KMOD_INVALID + 1,
+                                                __TEST_KMOD_MAX - 1);
+}
+
+static ssize_t config_test_case_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       struct test_config *config = &test_dev->config;
+
+       return test_dev_config_show_uint(test_dev, buf, config->test_case);
+}
+static DEVICE_ATTR(config_test_case, 0644, config_test_case_show,
+                  config_test_case_store);
+
+static ssize_t test_result_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct kmod_test_device *test_dev = dev_to_test_dev(dev);
+       struct test_config *config = &test_dev->config;
+
+       return test_dev_config_show_int(test_dev, buf, config->test_result);
+}
+static DEVICE_ATTR(test_result, 0644, test_result_show, test_result_store);
+
+#define TEST_KMOD_DEV_ATTR(name)               &dev_attr_##name.attr
+
+static struct attribute *test_dev_attrs[] = {
+       TEST_KMOD_DEV_ATTR(trigger_config),
+       TEST_KMOD_DEV_ATTR(config),
+       TEST_KMOD_DEV_ATTR(reset),
+
+       TEST_KMOD_DEV_ATTR(config_test_driver),
+       TEST_KMOD_DEV_ATTR(config_test_fs),
+       TEST_KMOD_DEV_ATTR(config_num_threads),
+       TEST_KMOD_DEV_ATTR(config_test_case),
+       TEST_KMOD_DEV_ATTR(test_result),
+
+       NULL,
+};
+
+ATTRIBUTE_GROUPS(test_dev);
+
+static int kmod_config_init(struct kmod_test_device *test_dev)
+{
+       int ret;
+
+       mutex_lock(&test_dev->config_mutex);
+       ret = __kmod_config_init(test_dev);
+       mutex_unlock(&test_dev->config_mutex);
+
+       return ret;
+}
+
+static struct kmod_test_device *alloc_test_dev_kmod(int idx)
+{
+       int ret;
+       struct kmod_test_device *test_dev;
+       struct miscdevice *misc_dev;
+
+       test_dev = vzalloc(sizeof(struct kmod_test_device));
+       if (!test_dev) {
+               pr_err("Cannot alloc test_dev\n");
+               goto err_out;
+       }
+
+       mutex_init(&test_dev->config_mutex);
+       mutex_init(&test_dev->trigger_mutex);
+       mutex_init(&test_dev->thread_mutex);
+
+       init_completion(&test_dev->kthreads_done);
+
+       ret = kmod_config_init(test_dev);
+       if (ret < 0) {
+               pr_err("Cannot alloc kmod_config_init()\n");
+               goto err_out_free;
+       }
+
+       test_dev->dev_idx = idx;
+       misc_dev = &test_dev->misc_dev;
+
+       misc_dev->minor = MISC_DYNAMIC_MINOR;
+       misc_dev->name = kasprintf(GFP_KERNEL, "test_kmod%d", idx);
+       if (!misc_dev->name) {
+               pr_err("Cannot alloc misc_dev->name\n");
+               goto err_out_free_config;
+       }
+       misc_dev->groups = test_dev_groups;
+
+       return test_dev;
+
+err_out_free_config:
+       free_test_dev_info(test_dev);
+       kmod_config_free(test_dev);
+err_out_free:
+       vfree(test_dev);
+       test_dev = NULL;
+err_out:
+       return NULL;
+}
+
+static void free_test_dev_kmod(struct kmod_test_device *test_dev)
+{
+       if (test_dev) {
+               kfree_const(test_dev->misc_dev.name);
+               test_dev->misc_dev.name = NULL;
+               free_test_dev_info(test_dev);
+               kmod_config_free(test_dev);
+               vfree(test_dev);
+               test_dev = NULL;
+       }
+}
+
+static struct kmod_test_device *register_test_dev_kmod(void)
+{
+       struct kmod_test_device *test_dev = NULL;
+       int ret;
+
+       mutex_unlock(&reg_dev_mutex);
+
+       /* int should suffice for number of devices, test for wrap */
+       if (unlikely(num_test_devs + 1) < 0) {
+               pr_err("reached limit of number of test devices\n");
+               goto out;
+       }
+
+       test_dev = alloc_test_dev_kmod(num_test_devs);
+       if (!test_dev)
+               goto out;
+
+       ret = misc_register(&test_dev->misc_dev);
+       if (ret) {
+               pr_err("could not register misc device: %d\n", ret);
+               free_test_dev_kmod(test_dev);
+               goto out;
+       }
+
+       test_dev->dev = test_dev->misc_dev.this_device;
+       list_add_tail(&test_dev->list, &reg_test_devs);
+       dev_info(test_dev->dev, "interface ready\n");
+
+       num_test_devs++;
+
+out:
+       mutex_unlock(&reg_dev_mutex);
+
+       return test_dev;
+
+}
+
+static int __init test_kmod_init(void)
+{
+       struct kmod_test_device *test_dev;
+       int ret;
+
+       test_dev = register_test_dev_kmod();
+       if (!test_dev) {
+               pr_err("Cannot add first test kmod device\n");
+               return -ENODEV;
+       }
+
+       /*
+        * With some work we might be able to gracefully enable
+        * testing with this driver built-in, for now this seems
+        * rather risky. For those willing to try have at it,
+        * and enable the below. Good luck! If that works, try
+        * lowering the init level for more fun.
+        */
+       if (force_init_test) {
+               ret = trigger_config_run_type(test_dev,
+                                             TEST_KMOD_DRIVER, "tun");
+               if (WARN_ON(ret))
+                       return ret;
+               ret = trigger_config_run_type(test_dev,
+                                             TEST_KMOD_FS_TYPE, "btrfs");
+               if (WARN_ON(ret))
+                       return ret;
+       }
+
+       return 0;
+}
+late_initcall(test_kmod_init);
+
+static
+void unregister_test_dev_kmod(struct kmod_test_device *test_dev)
+{
+       mutex_lock(&test_dev->trigger_mutex);
+       mutex_lock(&test_dev->config_mutex);
+
+       test_dev_kmod_stop_tests(test_dev);
+
+       dev_info(test_dev->dev, "removing interface\n");
+       misc_deregister(&test_dev->misc_dev);
+       kfree(&test_dev->misc_dev.name);
+
+       mutex_unlock(&test_dev->config_mutex);
+       mutex_unlock(&test_dev->trigger_mutex);
+
+       free_test_dev_kmod(test_dev);
+}
+
+static void __exit test_kmod_exit(void)
+{
+       struct kmod_test_device *test_dev, *tmp;
+
+       mutex_lock(&reg_dev_mutex);
+       list_for_each_entry_safe(test_dev, tmp, &reg_test_devs, list) {
+               list_del(&test_dev->list);
+               unregister_test_dev_kmod(test_dev);
+       }
+       mutex_unlock(&reg_dev_mutex);
+}
+module_exit(test_kmod_exit);
+
+MODULE_AUTHOR("Luis R. Rodriguez <mcgrof@kernel.org>");
+MODULE_LICENSE("GPL");
index 64e899b..0ffca99 100644 (file)
@@ -56,8 +56,13 @@ static bool enomem_retry = false;
 module_param(enomem_retry, bool, 0);
 MODULE_PARM_DESC(enomem_retry, "Retry insert even if -ENOMEM was returned (default: off)");
 
+struct test_obj_val {
+       int     id;
+       int     tid;
+};
+
 struct test_obj {
-       int                     value;
+       struct test_obj_val     value;
        struct rhash_head       node;
 };
 
@@ -72,7 +77,7 @@ static struct test_obj array[MAX_ENTRIES];
 static struct rhashtable_params test_rht_params = {
        .head_offset = offsetof(struct test_obj, node),
        .key_offset = offsetof(struct test_obj, value),
-       .key_len = sizeof(int),
+       .key_len = sizeof(struct test_obj_val),
        .hashfn = jhash,
        .nulls_base = (3U << RHT_BASE_SHIFT),
 };
@@ -109,24 +114,26 @@ static int __init test_rht_lookup(struct rhashtable *ht)
        for (i = 0; i < entries * 2; i++) {
                struct test_obj *obj;
                bool expected = !(i % 2);
-               u32 key = i;
+               struct test_obj_val key = {
+                       .id = i,
+               };
 
-               if (array[i / 2].value == TEST_INSERT_FAIL)
+               if (array[i / 2].value.id == TEST_INSERT_FAIL)
                        expected = false;
 
                obj = rhashtable_lookup_fast(ht, &key, test_rht_params);
 
                if (expected && !obj) {
-                       pr_warn("Test failed: Could not find key %u\n", key);
+                       pr_warn("Test failed: Could not find key %u\n", key.id);
                        return -ENOENT;
                } else if (!expected && obj) {
                        pr_warn("Test failed: Unexpected entry found for key %u\n",
-                               key);
+                               key.id);
                        return -EEXIST;
                } else if (expected && obj) {
-                       if (obj->value != i) {
+                       if (obj->value.id != i) {
                                pr_warn("Test failed: Lookup value mismatch %u!=%u\n",
-                                       obj->value, i);
+                                       obj->value.id, i);
                                return -EINVAL;
                        }
                }
@@ -195,7 +202,7 @@ static s64 __init test_rhashtable(struct rhashtable *ht)
        for (i = 0; i < entries; i++) {
                struct test_obj *obj = &array[i];
 
-               obj->value = i * 2;
+               obj->value.id = i * 2;
                err = insert_retry(ht, &obj->node, test_rht_params);
                if (err > 0)
                        insert_retries += err;
@@ -216,9 +223,11 @@ static s64 __init test_rhashtable(struct rhashtable *ht)
 
        pr_info("  Deleting %d keys\n", entries);
        for (i = 0; i < entries; i++) {
-               u32 key = i * 2;
+               struct test_obj_val key = {
+                       .id = i * 2,
+               };
 
-               if (array[i].value != TEST_INSERT_FAIL) {
+               if (array[i].value.id != TEST_INSERT_FAIL) {
                        obj = rhashtable_lookup_fast(ht, &key, test_rht_params);
                        BUG_ON(!obj);
 
@@ -242,18 +251,21 @@ static int thread_lookup_test(struct thread_data *tdata)
 
        for (i = 0; i < entries; i++) {
                struct test_obj *obj;
-               int key = (tdata->id << 16) | i;
+               struct test_obj_val key = {
+                       .id = i,
+                       .tid = tdata->id,
+               };
 
                obj = rhashtable_lookup_fast(&ht, &key, test_rht_params);
-               if (obj && (tdata->objs[i].value == TEST_INSERT_FAIL)) {
-                       pr_err("  found unexpected object %d\n", key);
+               if (obj && (tdata->objs[i].value.id == TEST_INSERT_FAIL)) {
+                       pr_err("  found unexpected object %d-%d\n", key.tid, key.id);
                        err++;
-               } else if (!obj && (tdata->objs[i].value != TEST_INSERT_FAIL)) {
-                       pr_err("  object %d not found!\n", key);
+               } else if (!obj && (tdata->objs[i].value.id != TEST_INSERT_FAIL)) {
+                       pr_err("  object %d-%d not found!\n", key.tid, key.id);
                        err++;
-               } else if (obj && (obj->value != key)) {
-                       pr_err("  wrong object returned (got %d, expected %d)\n",
-                              obj->value, key);
+               } else if (obj && memcmp(&obj->value, &key, sizeof(key))) {
+                       pr_err("  wrong object returned (got %d-%d, expected %d-%d)\n",
+                              obj->value.tid, obj->value.id, key.tid, key.id);
                        err++;
                }
 
@@ -272,7 +284,8 @@ static int threadfunc(void *data)
                pr_err("  thread[%d]: down_interruptible failed\n", tdata->id);
 
        for (i = 0; i < entries; i++) {
-               tdata->objs[i].value = (tdata->id << 16) | i;
+               tdata->objs[i].value.id = i;
+               tdata->objs[i].value.tid = tdata->id;
                err = insert_retry(&ht, &tdata->objs[i].node, test_rht_params);
                if (err > 0) {
                        insert_retries += err;
@@ -295,7 +308,7 @@ static int threadfunc(void *data)
 
        for (step = 10; step > 0; step--) {
                for (i = 0; i < entries; i += step) {
-                       if (tdata->objs[i].value == TEST_INSERT_FAIL)
+                       if (tdata->objs[i].value.id == TEST_INSERT_FAIL)
                                continue;
                        err = rhashtable_remove_fast(&ht, &tdata->objs[i].node,
                                                     test_rht_params);
@@ -304,7 +317,7 @@ static int threadfunc(void *data)
                                       tdata->id);
                                goto out;
                        }
-                       tdata->objs[i].value = TEST_INSERT_FAIL;
+                       tdata->objs[i].value.id = TEST_INSERT_FAIL;
 
                        cond_resched();
                }
diff --git a/lib/test_sysctl.c b/lib/test_sysctl.c
new file mode 100644 (file)
index 0000000..3dd801c
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * proc sysctl test driver
+ *
+ * Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org>
+ *
+ * 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; or, when distributed separately from the Linux kernel or
+ * when incorporated into other software packages, subject to the following
+ * license:
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of copyleft-next (version 0.3.1 or later) as published
+ * at http://copyleft-next.org/.
+ */
+
+/*
+ * This module provides an interface to the the proc sysctl interfaces.  This
+ * driver requires CONFIG_PROC_SYSCTL. It will not normally be loaded by the
+ * system unless explicitly requested by name. You can also build this driver
+ * into your kernel.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/async.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+
+static int i_zero;
+static int i_one_hundred = 100;
+
+struct test_sysctl_data {
+       int int_0001;
+       int int_0002;
+       int int_0003[4];
+
+       unsigned int uint_0001;
+
+       char string_0001[65];
+};
+
+static struct test_sysctl_data test_data = {
+       .int_0001 = 60,
+       .int_0002 = 1,
+
+       .int_0003[0] = 0,
+       .int_0003[1] = 1,
+       .int_0003[2] = 2,
+       .int_0003[3] = 3,
+
+       .uint_0001 = 314,
+
+       .string_0001 = "(none)",
+};
+
+/* These are all under /proc/sys/debug/test_sysctl/ */
+static struct ctl_table test_table[] = {
+       {
+               .procname       = "int_0001",
+               .data           = &test_data.int_0001,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &i_zero,
+               .extra2         = &i_one_hundred,
+       },
+       {
+               .procname       = "int_0002",
+               .data           = &test_data.int_0002,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "int_0003",
+               .data           = &test_data.int_0003,
+               .maxlen         = sizeof(test_data.int_0003),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "uint_0001",
+               .data           = &test_data.uint_0001,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_douintvec,
+       },
+       {
+               .procname       = "string_0001",
+               .data           = &test_data.string_0001,
+               .maxlen         = sizeof(test_data.string_0001),
+               .mode           = 0644,
+               .proc_handler   = proc_dostring,
+       },
+       { }
+};
+
+static struct ctl_table test_sysctl_table[] = {
+       {
+               .procname       = "test_sysctl",
+               .maxlen         = 0,
+               .mode           = 0555,
+               .child          = test_table,
+       },
+       { }
+};
+
+static struct ctl_table test_sysctl_root_table[] = {
+       {
+               .procname       = "debug",
+               .maxlen         = 0,
+               .mode           = 0555,
+               .child          = test_sysctl_table,
+       },
+       { }
+};
+
+static struct ctl_table_header *test_sysctl_header;
+
+static int __init test_sysctl_init(void)
+{
+       test_sysctl_header = register_sysctl_table(test_sysctl_root_table);
+       if (!test_sysctl_header)
+               return -ENOMEM;
+       return 0;
+}
+late_initcall(test_sysctl_init);
+
+static void __exit test_sysctl_exit(void)
+{
+       if (test_sysctl_header)
+               unregister_sysctl_table(test_sysctl_header);
+}
+
+module_exit(test_sysctl_exit);
+
+MODULE_AUTHOR("Luis R. Rodriguez <mcgrof@kernel.org>");
+MODULE_LICENSE("GPL");
index 478c049..cd819c3 100644 (file)
@@ -82,7 +82,7 @@ static void __init test_uuid_test(const struct test_uuid_data *data)
                test_uuid_failed("conversion", false, true, data->uuid, NULL);
 
        total_tests++;
-       if (uuid_equal(&data->be, &be)) {
+       if (!uuid_equal(&data->be, &be)) {
                sprintf(buf, "%pUb", &be);
                test_uuid_failed("cmp", false, true, data->uuid, buf);
        }
index 1e51652..bc48ee7 100644 (file)
@@ -1384,7 +1384,7 @@ static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid)
 
        page = __alloc_pages_node(nid,
                htlb_alloc_mask(h)|__GFP_COMP|__GFP_THISNODE|
-                                               __GFP_REPEAT|__GFP_NOWARN,
+                                               __GFP_RETRY_MAYFAIL|__GFP_NOWARN,
                huge_page_order(h));
        if (page) {
                prep_new_huge_page(h, page, nid);
@@ -1525,7 +1525,7 @@ static struct page *__hugetlb_alloc_buddy_huge_page(struct hstate *h,
 {
        int order = huge_page_order(h);
 
-       gfp_mask |= __GFP_COMP|__GFP_REPEAT|__GFP_NOWARN;
+       gfp_mask |= __GFP_COMP|__GFP_RETRY_MAYFAIL|__GFP_NOWARN;
        if (nid == NUMA_NO_NODE)
                nid = numa_mem_id();
        return __alloc_pages_nodemask(gfp_mask, order, nid, nmask);
index 0e4f558..24d88f0 100644 (file)
@@ -23,7 +23,7 @@
  * hints such as HIGHMEM usage.
  */
 #define GFP_RECLAIM_MASK (__GFP_RECLAIM|__GFP_HIGH|__GFP_IO|__GFP_FS|\
-                       __GFP_NOWARN|__GFP_REPEAT|__GFP_NOFAIL|\
+                       __GFP_NOWARN|__GFP_RETRY_MAYFAIL|__GFP_NOFAIL|\
                        __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC|\
                        __GFP_ATOMIC)
 
index cbb5719..0e517be 100644 (file)
@@ -3591,7 +3591,7 @@ out:
        return 0;
 }
 
-static int create_huge_pmd(struct vm_fault *vmf)
+static inline int create_huge_pmd(struct vm_fault *vmf)
 {
        if (vma_is_anonymous(vmf->vma))
                return do_huge_pmd_anonymous_page(vmf);
index 7d8e562..d911fa5 100644 (file)
@@ -1078,7 +1078,8 @@ static struct page *new_page(struct page *page, unsigned long start, int **x)
        /*
         * if !vma, alloc_page_vma() will use task or system default policy
         */
-       return alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
+       return alloc_page_vma(GFP_HIGHUSER_MOVABLE | __GFP_RETRY_MAYFAIL,
+                       vma, address);
 }
 #else
 
index 7fa6759..f19efcf 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2231,7 +2231,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
 
        /* Guard against exceeding limits of the address space. */
        address &= PAGE_MASK;
-       if (address >= TASK_SIZE)
+       if (address >= (TASK_SIZE & PAGE_MASK))
                return -ENOMEM;
        address += PAGE_SIZE;
 
index 0b60cc7..96e93b2 100644 (file)
@@ -601,7 +601,7 @@ static inline void __wb_writeout_inc(struct bdi_writeback *wb)
 {
        struct wb_domain *cgdom;
 
-       __inc_wb_stat(wb, WB_WRITTEN);
+       inc_wb_stat(wb, WB_WRITTEN);
        wb_domain_writeout_inc(&global_wb_domain, &wb->completions,
                               wb->bdi->max_prop_frac);
 
@@ -2435,8 +2435,8 @@ void account_page_dirtied(struct page *page, struct address_space *mapping)
                __inc_lruvec_page_state(page, NR_FILE_DIRTY);
                __inc_zone_page_state(page, NR_ZONE_WRITE_PENDING);
                __inc_node_page_state(page, NR_DIRTIED);
-               __inc_wb_stat(wb, WB_RECLAIMABLE);
-               __inc_wb_stat(wb, WB_DIRTIED);
+               inc_wb_stat(wb, WB_RECLAIMABLE);
+               inc_wb_stat(wb, WB_DIRTIED);
                task_io_account_write(PAGE_SIZE);
                current->nr_dirtied++;
                this_cpu_inc(bdp_ratelimits);
@@ -2741,7 +2741,7 @@ int test_clear_page_writeback(struct page *page)
                        if (bdi_cap_account_writeback(bdi)) {
                                struct bdi_writeback *wb = inode_to_wb(inode);
 
-                               __dec_wb_stat(wb, WB_WRITEBACK);
+                               dec_wb_stat(wb, WB_WRITEBACK);
                                __wb_writeout_inc(wb);
                        }
                }
@@ -2786,7 +2786,7 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
                                                page_index(page),
                                                PAGECACHE_TAG_WRITEBACK);
                        if (bdi_cap_account_writeback(bdi))
-                               __inc_wb_stat(inode_to_wb(inode), WB_WRITEBACK);
+                               inc_wb_stat(inode_to_wb(inode), WB_WRITEBACK);
 
                        /*
                         * We can come through here when swapping anonymous
index 64b7d82..6d30e91 100644 (file)
@@ -3284,6 +3284,14 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
        /* The OOM killer will not help higher order allocs */
        if (order > PAGE_ALLOC_COSTLY_ORDER)
                goto out;
+       /*
+        * We have already exhausted all our reclaim opportunities without any
+        * success so it is time to admit defeat. We will skip the OOM killer
+        * because it is very likely that the caller has a more reasonable
+        * fallback than shooting a random task.
+        */
+       if (gfp_mask & __GFP_RETRY_MAYFAIL)
+               goto out;
        /* The OOM killer does not needlessly kill tasks for lowmem */
        if (ac->high_zoneidx < ZONE_NORMAL)
                goto out;
@@ -3413,7 +3421,7 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
        }
 
        /*
-        * !costly requests are much more important than __GFP_REPEAT
+        * !costly requests are much more important than __GFP_RETRY_MAYFAIL
         * costly ones because they are de facto nofail and invoke OOM
         * killer to move on while costly can fail and users are ready
         * to cope with that. 1/4 retries is rather arbitrary but we
@@ -3920,9 +3928,9 @@ retry:
 
        /*
         * Do not retry costly high order allocations unless they are
-        * __GFP_REPEAT
+        * __GFP_RETRY_MAYFAIL
         */
-       if (costly_order && !(gfp_mask & __GFP_REPEAT))
+       if (costly_order && !(gfp_mask & __GFP_RETRY_MAYFAIL))
                goto nopage;
 
        if (should_reclaim_retry(gfp_mask, order, ac, alloc_flags,
index a56c398..c50b1a1 100644 (file)
@@ -56,11 +56,11 @@ void * __meminit vmemmap_alloc_block(unsigned long size, int node)
 
                if (node_state(node, N_HIGH_MEMORY))
                        page = alloc_pages_node(
-                               node, GFP_KERNEL | __GFP_ZERO | __GFP_REPEAT,
+                               node, GFP_KERNEL | __GFP_ZERO | __GFP_RETRY_MAYFAIL,
                                get_order(size));
                else
                        page = alloc_pages(
-                               GFP_KERNEL | __GFP_ZERO | __GFP_REPEAT,
+                               GFP_KERNEL | __GFP_ZERO | __GFP_RETRY_MAYFAIL,
                                get_order(size));
                if (page)
                        return page_address(page);
index 26be640..7b07ec8 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -83,6 +83,8 @@ EXPORT_SYMBOL(kstrdup_const);
  * @s: the string to duplicate
  * @max: read at most @max chars from @s
  * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ *
+ * Note: Use kmemdup_nul() instead if the size is known exactly.
  */
 char *kstrndup(const char *s, size_t max, gfp_t gfp)
 {
@@ -121,6 +123,28 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp)
 EXPORT_SYMBOL(kmemdup);
 
 /**
+ * kmemdup_nul - Create a NUL-terminated string from unterminated data
+ * @s: The data to stringify
+ * @len: The size of the data
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ */
+char *kmemdup_nul(const char *s, size_t len, gfp_t gfp)
+{
+       char *buf;
+
+       if (!s)
+               return NULL;
+
+       buf = kmalloc_track_caller(len + 1, gfp);
+       if (buf) {
+               memcpy(buf, s, len);
+               buf[len] = '\0';
+       }
+       return buf;
+}
+EXPORT_SYMBOL(kmemdup_nul);
+
+/**
  * memdup_user - duplicate memory region from user space
  *
  * @src: source address in user space
@@ -339,9 +363,9 @@ EXPORT_SYMBOL(vm_mmap);
  * Uses kmalloc to get the memory but if the allocation fails then falls back
  * to the vmalloc allocator. Use kvfree for freeing the memory.
  *
- * Reclaim modifiers - __GFP_NORETRY and __GFP_NOFAIL are not supported. __GFP_REPEAT
- * is supported only for large (>32kB) allocations, and it should be used only if
- * kmalloc is preferable to the vmalloc fallback, due to visible performance drawbacks.
+ * Reclaim modifiers - __GFP_NORETRY and __GFP_NOFAIL are not supported.
+ * __GFP_RETRY_MAYFAIL is supported, and it should be used only if kmalloc is
+ * preferable to the vmalloc fallback, due to visible performance drawbacks.
  *
  * Any use of gfp flags outside of GFP_KERNEL should be consulted with mm people.
  */
@@ -366,13 +390,7 @@ void *kvmalloc_node(size_t size, gfp_t flags, int node)
        if (size > PAGE_SIZE) {
                kmalloc_flags |= __GFP_NOWARN;
 
-               /*
-                * We have to override __GFP_REPEAT by __GFP_NORETRY for !costly
-                * requests because there is no other way to tell the allocator
-                * that we want to fail rather than retry endlessly.
-                */
-               if (!(kmalloc_flags & __GFP_REPEAT) ||
-                               (size <= PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
+               if (!(kmalloc_flags & __GFP_RETRY_MAYFAIL))
                        kmalloc_flags |= __GFP_NORETRY;
        }
 
index 6016ab0..8698c1c 100644 (file)
@@ -1795,7 +1795,7 @@ fail:
  *     allocator with @gfp_mask flags.  Map them into contiguous
  *     kernel virtual space, using a pagetable protection of @prot.
  *
- *     Reclaim modifiers in @gfp_mask - __GFP_NORETRY, __GFP_REPEAT
+ *     Reclaim modifiers in @gfp_mask - __GFP_NORETRY, __GFP_RETRY_MAYFAIL
  *     and __GFP_NOFAIL are not supported
  *
  *     Any use of gfp flags outside of GFP_KERNEL should be consulted
index e9210f8..a1af041 100644 (file)
@@ -2506,18 +2506,18 @@ static inline bool should_continue_reclaim(struct pglist_data *pgdat,
                return false;
 
        /* Consider stopping depending on scan and reclaim activity */
-       if (sc->gfp_mask & __GFP_REPEAT) {
+       if (sc->gfp_mask & __GFP_RETRY_MAYFAIL) {
                /*
-                * For __GFP_REPEAT allocations, stop reclaiming if the
+                * For __GFP_RETRY_MAYFAIL allocations, stop reclaiming if the
                 * full LRU list has been scanned and we are still failing
                 * to reclaim pages. This full LRU scan is potentially
-                * expensive but a __GFP_REPEAT caller really wants to succeed
+                * expensive but a __GFP_RETRY_MAYFAIL caller really wants to succeed
                 */
                if (!nr_reclaimed && !nr_scanned)
                        return false;
        } else {
                /*
-                * For non-__GFP_REPEAT allocations which can presumably
+                * For non-__GFP_RETRY_MAYFAIL allocations which can presumably
                 * fail without consequence, stop if we failed to reclaim
                 * any pages from the last SWAP_CLUSTER_MAX number of
                 * pages that were scanned. This will return to the
index 1218fb3..4674235 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/uio.h>
 #include <net/9p/9p.h>
 #include <linux/parser.h>
+#include <linux/seq_file.h>
 #include <net/9p/client.h>
 #include <net/9p/transport.h>
 #include "protocol.h"
@@ -77,6 +78,30 @@ inline int p9_is_proto_dotu(struct p9_client *clnt)
 }
 EXPORT_SYMBOL(p9_is_proto_dotu);
 
+int p9_show_client_options(struct seq_file *m, struct p9_client *clnt)
+{
+       if (clnt->msize != 8192)
+               seq_printf(m, ",msize=%u", clnt->msize);
+       seq_printf(m, "trans=%s", clnt->trans_mod->name);
+
+       switch (clnt->proto_version) {
+       case p9_proto_legacy:
+               seq_puts(m, ",noextend");
+               break;
+       case p9_proto_2000u:
+               seq_puts(m, ",version=9p2000.u");
+               break;
+       case p9_proto_2000L:
+               /* Default */
+               break;
+       }
+
+       if (clnt->trans_mod->show_options)
+               return clnt->trans_mod->show_options(m, clnt);
+       return 0;
+}
+EXPORT_SYMBOL(p9_show_client_options);
+
 /*
  * Some error codes are taken directly from the server replies,
  * make sure they are valid.
index dca3cdd..ddfa866 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/file.h>
 #include <linux/parser.h>
 #include <linux/slab.h>
+#include <linux/seq_file.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 #include <net/9p/transport.h>
@@ -51,6 +52,9 @@
 #define MAX_SOCK_BUF (64*1024)
 #define MAXPOLLWADDR   2
 
+static struct p9_trans_module p9_tcp_trans;
+static struct p9_trans_module p9_fd_trans;
+
 /**
  * struct p9_fd_opts - per-transport options
  * @rfd: file descriptor for reading (trans=fd)
@@ -63,7 +67,7 @@ struct p9_fd_opts {
        int rfd;
        int wfd;
        u16 port;
-       int privport;
+       bool privport;
 };
 
 /*
@@ -720,6 +724,20 @@ static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req)
        return 0;
 }
 
+static int p9_fd_show_options(struct seq_file *m, struct p9_client *clnt)
+{
+       if (clnt->trans_mod == &p9_tcp_trans) {
+               if (clnt->trans_opts.tcp.port != P9_PORT)
+                       seq_printf(m, "port=%u", clnt->trans_opts.tcp.port);
+       } else if (clnt->trans_mod == &p9_fd_trans) {
+               if (clnt->trans_opts.fd.rfd != ~0)
+                       seq_printf(m, "rfd=%u", clnt->trans_opts.fd.rfd);
+               if (clnt->trans_opts.fd.wfd != ~0)
+                       seq_printf(m, "wfd=%u", clnt->trans_opts.fd.wfd);
+       }
+       return 0;
+}
+
 /**
  * parse_opts - parse mount options into p9_fd_opts structure
  * @params: options string passed from mount
@@ -738,7 +756,7 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
        opts->port = P9_PORT;
        opts->rfd = ~0;
        opts->wfd = ~0;
-       opts->privport = 0;
+       opts->privport = false;
 
        if (!params)
                return 0;
@@ -776,7 +794,7 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
                        opts->wfd = option;
                        break;
                case Opt_privport:
-                       opts->privport = 1;
+                       opts->privport = true;
                        break;
                default:
                        continue;
@@ -942,6 +960,8 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
 
        csocket = NULL;
 
+       client->trans_opts.tcp.port = opts.port;
+       client->trans_opts.tcp.privport = opts.privport;
        sin_server.sin_family = AF_INET;
        sin_server.sin_addr.s_addr = in_aton(addr);
        sin_server.sin_port = htons(opts.port);
@@ -1020,6 +1040,8 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args)
        struct p9_fd_opts opts;
 
        parse_opts(args, &opts);
+       client->trans_opts.fd.rfd = opts.rfd;
+       client->trans_opts.fd.wfd = opts.wfd;
 
        if (opts.rfd == ~0 || opts.wfd == ~0) {
                pr_err("Insufficient options for proto=fd\n");
@@ -1044,6 +1066,7 @@ static struct p9_trans_module p9_tcp_trans = {
        .request = p9_fd_request,
        .cancel = p9_fd_cancel,
        .cancelled = p9_fd_cancelled,
+       .show_options = p9_fd_show_options,
        .owner = THIS_MODULE,
 };
 
@@ -1056,6 +1079,7 @@ static struct p9_trans_module p9_unix_trans = {
        .request = p9_fd_request,
        .cancel = p9_fd_cancel,
        .cancelled = p9_fd_cancelled,
+       .show_options = p9_fd_show_options,
        .owner = THIS_MODULE,
 };
 
@@ -1068,6 +1092,7 @@ static struct p9_trans_module p9_fd_trans = {
        .request = p9_fd_request,
        .cancel = p9_fd_cancel,
        .cancelled = p9_fd_cancelled,
+       .show_options = p9_fd_show_options,
        .owner = THIS_MODULE,
 };
 
index 553ed4e..6d8e303 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/parser.h>
 #include <linux/semaphore.h>
 #include <linux/slab.h>
+#include <linux/seq_file.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 #include <net/9p/transport.h>
@@ -70,6 +71,8 @@
  * @dm_mr: DMA Memory Region pointer
  * @lkey: The local access only memory region key
  * @timeout: Number of uSecs to wait for connection management events
+ * @privport: Whether a privileged port may be used
+ * @port: The port to use
  * @sq_depth: The depth of the Send Queue
  * @sq_sem: Semaphore for the SQ
  * @rq_depth: The depth of the Receive Queue.
@@ -95,6 +98,8 @@ struct p9_trans_rdma {
        struct ib_qp *qp;
        struct ib_cq *cq;
        long timeout;
+       bool privport;
+       u16 port;
        int sq_depth;
        struct semaphore sq_sem;
        int rq_depth;
@@ -133,10 +138,10 @@ struct p9_rdma_context {
  */
 struct p9_rdma_opts {
        short port;
+       bool privport;
        int sq_depth;
        int rq_depth;
        long timeout;
-       int privport;
 };
 
 /*
@@ -159,6 +164,23 @@ static match_table_t tokens = {
        {Opt_err, NULL},
 };
 
+static int p9_rdma_show_options(struct seq_file *m, struct p9_client *clnt)
+{
+       struct p9_trans_rdma *rdma = clnt->trans;
+
+       if (rdma->port != P9_PORT)
+               seq_printf(m, ",port=%u", rdma->port);
+       if (rdma->sq_depth != P9_RDMA_SQ_DEPTH)
+               seq_printf(m, ",sq=%u", rdma->sq_depth);
+       if (rdma->rq_depth != P9_RDMA_RQ_DEPTH)
+               seq_printf(m, ",rq=%u", rdma->rq_depth);
+       if (rdma->timeout != P9_RDMA_TIMEOUT)
+               seq_printf(m, ",timeout=%lu", rdma->timeout);
+       if (rdma->privport)
+               seq_puts(m, ",privport");
+       return 0;
+}
+
 /**
  * parse_opts - parse mount options into rdma options structure
  * @params: options string passed from mount
@@ -177,7 +199,7 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts)
        opts->sq_depth = P9_RDMA_SQ_DEPTH;
        opts->rq_depth = P9_RDMA_RQ_DEPTH;
        opts->timeout = P9_RDMA_TIMEOUT;
-       opts->privport = 0;
+       opts->privport = false;
 
        if (!params)
                return 0;
@@ -218,7 +240,7 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts)
                        opts->timeout = option;
                        break;
                case Opt_privport:
-                       opts->privport = 1;
+                       opts->privport = true;
                        break;
                default:
                        continue;
@@ -560,6 +582,8 @@ static struct p9_trans_rdma *alloc_rdma(struct p9_rdma_opts *opts)
        if (!rdma)
                return NULL;
 
+       rdma->port = opts->port;
+       rdma->privport = opts->privport;
        rdma->sq_depth = opts->sq_depth;
        rdma->rq_depth = opts->rq_depth;
        rdma->timeout = opts->timeout;
@@ -733,6 +757,7 @@ static struct p9_trans_module p9_rdma_trans = {
        .request = rdma_request,
        .cancel = rdma_cancel,
        .cancelled = rdma_cancelled,
+       .show_options = p9_rdma_show_options,
 };
 
 /**
index 2af4f1c..4e2576f 100644 (file)
@@ -273,9 +273,6 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
                           struct lowpan_peer *peer)
 {
        const u8 *saddr;
-       struct lowpan_btle_dev *dev;
-
-       dev = lowpan_btle_dev(netdev);
 
        saddr = peer->lladdr;
 
index f0f3447..861ae2a 100644 (file)
@@ -34,11 +34,11 @@ static struct lock_class_key bridge_netdev_addr_lock_key;
 netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct net_bridge *br = netdev_priv(dev);
-       const unsigned char *dest = skb->data;
        struct net_bridge_fdb_entry *dst;
        struct net_bridge_mdb_entry *mdst;
        struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
        const struct nf_br_ops *nf_ops;
+       const unsigned char *dest;
        u16 vid = 0;
 
        rcu_read_lock();
@@ -61,6 +61,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid))
                goto out;
 
+       dest = eth_hdr(skb)->h_dest;
        if (is_broadcast_ether_addr(dest)) {
                br_flood(br, skb, BR_PKT_BROADCAST, false, true);
        } else if (is_multicast_ether_addr(dest)) {
index 013f229..7637f58 100644 (file)
@@ -131,11 +131,11 @@ static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br,
 int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
        struct net_bridge_port *p = br_port_get_rcu(skb->dev);
-       const unsigned char *dest = eth_hdr(skb)->h_dest;
        enum br_pkt_type pkt_type = BR_PKT_UNICAST;
        struct net_bridge_fdb_entry *dst = NULL;
        struct net_bridge_mdb_entry *mdst;
        bool local_rcv, mcast_hit = false;
+       const unsigned char *dest;
        struct net_bridge *br;
        u16 vid = 0;
 
@@ -153,6 +153,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
                br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, false);
 
        local_rcv = !!(br->dev->flags & IFF_PROMISC);
+       dest = eth_hdr(skb)->h_dest;
        if (is_multicast_ether_addr(dest)) {
                /* by definition the broadcast is also a multicast address */
                if (is_broadcast_ether_addr(dest)) {
index 3d265c5..5c036d2 100644 (file)
@@ -599,7 +599,11 @@ struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private)
 {
        struct ceph_client *client;
        struct ceph_entity_addr *myaddr = NULL;
-       int err = -ENOMEM;
+       int err;
+
+       err = wait_for_random_bytes();
+       if (err < 0)
+               return ERR_PTR(err);
 
        client = kzalloc(sizeof(*client), GFP_KERNEL);
        if (client == NULL)
index 0c31035..b7cc615 100644 (file)
@@ -3203,8 +3203,10 @@ static struct ceph_msg_data *ceph_msg_data_create(enum ceph_msg_data_type type)
                return NULL;
 
        data = kmem_cache_zalloc(ceph_msg_data_cache, GFP_NOFS);
-       if (data)
-               data->type = type;
+       if (!data)
+               return NULL;
+
+       data->type = type;
        INIT_LIST_HEAD(&data->links);
 
        return data;
index 86a9737..901bb82 100644 (file)
@@ -5310,7 +5310,10 @@ static int invalidate_authorizer(struct ceph_connection *con)
 
 static void osd_reencode_message(struct ceph_msg *msg)
 {
-       encode_request_finish(msg);
+       int type = le16_to_cpu(msg->hdr.type);
+
+       if (type == CEPH_MSG_OSD_OP)
+               encode_request_finish(msg);
 }
 
 static int osd_sign_message(struct ceph_msg *msg)
index 864789c..64ae9f8 100644 (file)
@@ -338,7 +338,7 @@ static void crush_finalize(struct crush_map *c)
 static struct crush_map *crush_decode(void *pbyval, void *end)
 {
        struct crush_map *c;
-       int err = -EINVAL;
+       int err;
        int i, j;
        void **p = &pbyval;
        void *start = pbyval;
@@ -407,7 +407,6 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
                        size = sizeof(struct crush_bucket_straw2);
                        break;
                default:
-                       err = -EINVAL;
                        goto bad;
                }
                BUG_ON(size == 0);
@@ -439,31 +438,31 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
                        err = crush_decode_uniform_bucket(p, end,
                                  (struct crush_bucket_uniform *)b);
                        if (err < 0)
-                               goto bad;
+                               goto fail;
                        break;
                case CRUSH_BUCKET_LIST:
                        err = crush_decode_list_bucket(p, end,
                               (struct crush_bucket_list *)b);
                        if (err < 0)
-                               goto bad;
+                               goto fail;
                        break;
                case CRUSH_BUCKET_TREE:
                        err = crush_decode_tree_bucket(p, end,
                                (struct crush_bucket_tree *)b);
                        if (err < 0)
-                               goto bad;
+                               goto fail;
                        break;
                case CRUSH_BUCKET_STRAW:
                        err = crush_decode_straw_bucket(p, end,
                                (struct crush_bucket_straw *)b);
                        if (err < 0)
-                               goto bad;
+                               goto fail;
                        break;
                case CRUSH_BUCKET_STRAW2:
                        err = crush_decode_straw2_bucket(p, end,
                                (struct crush_bucket_straw2 *)b);
                        if (err < 0)
-                               goto bad;
+                               goto fail;
                        break;
                }
        }
@@ -474,7 +473,6 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
                u32 yes;
                struct crush_rule *r;
 
-               err = -EINVAL;
                ceph_decode_32_safe(p, end, yes, bad);
                if (!yes) {
                        dout("crush_decode NO rule %d off %x %p to %p\n",
@@ -489,7 +487,6 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
                /* len */
                ceph_decode_32_safe(p, end, yes, bad);
 #if BITS_PER_LONG == 32
-               err = -EINVAL;
                if (yes > (ULONG_MAX - sizeof(*r))
                          / sizeof(struct crush_rule_step))
                        goto bad;
@@ -557,7 +554,7 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
        if (*p != end) {
                err = decode_choose_args(p, end, c);
                if (err)
-                       goto bad;
+                       goto fail;
        }
 
 done:
@@ -567,10 +564,14 @@ done:
 
 badmem:
        err = -ENOMEM;
-bad:
+fail:
        dout("crush_decode fail %d\n", err);
        crush_destroy(c);
        return ERR_PTR(err);
+
+bad:
+       err = -EINVAL;
+       goto fail;
 }
 
 int ceph_pg_compare(const struct ceph_pg *lhs, const struct ceph_pg *rhs)
@@ -1399,7 +1400,7 @@ static struct ceph_pg_mapping *__decode_pg_upmap_items(void **p, void *end,
                return ERR_PTR(-EINVAL);
 
        ceph_decode_need(p, end, 2 * len * sizeof(u32), e_inval);
-       pg = kzalloc(sizeof(*pg) + 2 * len * sizeof(u32), GFP_NOIO);
+       pg = alloc_pg_mapping(2 * len * sizeof(u32));
        if (!pg)
                return ERR_PTR(-ENOMEM);
 
@@ -1544,7 +1545,7 @@ static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
        if (struct_v >= 3) {
                /* erasure_code_profiles */
                ceph_decode_skip_map_of_map(p, end, string, string, string,
-                                           bad);
+                                           e_inval);
        }
 
        if (struct_v >= 4) {
@@ -1825,9 +1826,9 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
        if (struct_v >= 3) {
                /* new_erasure_code_profiles */
                ceph_decode_skip_map_of_map(p, end, string, string, string,
-                                           bad);
+                                           e_inval);
                /* old_erasure_code_profiles */
-               ceph_decode_skip_set(p, end, string, bad);
+               ceph_decode_skip_set(p, end, string, e_inval);
        }
 
        if (struct_v >= 4) {
index aba929e..6ded6c8 100644 (file)
@@ -37,21 +37,16 @@ int get_compat_msghdr(struct msghdr *kmsg,
                      struct sockaddr __user **save_addr,
                      struct iovec **iov)
 {
-       compat_uptr_t uaddr, uiov, tmp3;
-       compat_size_t nr_segs;
+       struct compat_msghdr msg;
        ssize_t err;
 
-       if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) ||
-           __get_user(uaddr, &umsg->msg_name) ||
-           __get_user(kmsg->msg_namelen, &umsg->msg_namelen) ||
-           __get_user(uiov, &umsg->msg_iov) ||
-           __get_user(nr_segs, &umsg->msg_iovlen) ||
-           __get_user(tmp3, &umsg->msg_control) ||
-           __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
-           __get_user(kmsg->msg_flags, &umsg->msg_flags))
+       if (copy_from_user(&msg, umsg, sizeof(*umsg)))
                return -EFAULT;
 
-       if (!uaddr)
+       kmsg->msg_flags = msg.msg_flags;
+       kmsg->msg_namelen = msg.msg_namelen;
+
+       if (!msg.msg_name)
                kmsg->msg_namelen = 0;
 
        if (kmsg->msg_namelen < 0)
@@ -59,14 +54,16 @@ int get_compat_msghdr(struct msghdr *kmsg,
 
        if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
                kmsg->msg_namelen = sizeof(struct sockaddr_storage);
-       kmsg->msg_control = compat_ptr(tmp3);
+
+       kmsg->msg_control = compat_ptr(msg.msg_control);
+       kmsg->msg_controllen = msg.msg_controllen;
 
        if (save_addr)
-               *save_addr = compat_ptr(uaddr);
+               *save_addr = compat_ptr(msg.msg_name);
 
-       if (uaddr && kmsg->msg_namelen) {
+       if (msg.msg_name && kmsg->msg_namelen) {
                if (!save_addr) {
-                       err = move_addr_to_kernel(compat_ptr(uaddr),
+                       err = move_addr_to_kernel(compat_ptr(msg.msg_name),
                                                  kmsg->msg_namelen,
                                                  kmsg->msg_name);
                        if (err < 0)
@@ -77,13 +74,13 @@ int get_compat_msghdr(struct msghdr *kmsg,
                kmsg->msg_namelen = 0;
        }
 
-       if (nr_segs > UIO_MAXIOV)
+       if (msg.msg_iovlen > UIO_MAXIOV)
                return -EMSGSIZE;
 
        kmsg->msg_iocb = NULL;
 
        return compat_import_iovec(save_addr ? READ : WRITE,
-                                  compat_ptr(uiov), nr_segs,
+                                  compat_ptr(msg.msg_iov), msg.msg_iovlen,
                                   UIO_FASTIOV, iov, &kmsg->msg_iter);
 }
 
@@ -316,15 +313,15 @@ struct sock_fprog __user *get_compat_bpf_fprog(char __user *optval)
 {
        struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval;
        struct sock_fprog __user *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog));
-       compat_uptr_t ptr;
-       u16 len;
-
-       if (!access_ok(VERIFY_READ, fprog32, sizeof(*fprog32)) ||
-           !access_ok(VERIFY_WRITE, kfprog, sizeof(struct sock_fprog)) ||
-           __get_user(len, &fprog32->len) ||
-           __get_user(ptr, &fprog32->filter) ||
-           __put_user(len, &kfprog->len) ||
-           __put_user(compat_ptr(ptr), &kfprog->filter))
+       struct compat_sock_fprog f32;
+       struct sock_fprog f;
+
+       if (copy_from_user(&f32, fprog32, sizeof(*fprog32)))
+               return NULL;
+       memset(&f, 0, sizeof(f));
+       f.len = f32.len;
+       f.filter = compat_ptr(f32.filter);
+       if (copy_to_user(kfprog, &f, sizeof(struct sock_fprog)))
                return NULL;
 
        return kfprog;
index d1b9c9b..8ea6b4b 100644 (file)
 #include <linux/netfilter_ingress.h>
 #include <linux/crash_dump.h>
 #include <linux/sctp.h>
+#include <net/udp_tunnel.h>
 
 #include "net-sysfs.h"
 
@@ -7327,8 +7328,27 @@ sync_lower:
        netdev_for_each_lower_dev(dev, lower, iter)
                netdev_sync_lower_features(dev, lower, features);
 
-       if (!err)
+       if (!err) {
+               netdev_features_t diff = features ^ dev->features;
+
+               if (diff & NETIF_F_RX_UDP_TUNNEL_PORT) {
+                       /* udp_tunnel_{get,drop}_rx_info both need
+                        * NETIF_F_RX_UDP_TUNNEL_PORT enabled on the
+                        * device, or they won't do anything.
+                        * Thus we need to update dev->features
+                        * *before* calling udp_tunnel_get_rx_info,
+                        * but *after* calling udp_tunnel_drop_rx_info.
+                        */
+                       if (features & NETIF_F_RX_UDP_TUNNEL_PORT) {
+                               dev->features = features;
+                               udp_tunnel_get_rx_info(dev);
+                       } else {
+                               udp_tunnel_drop_rx_info(dev);
+                       }
+               }
+
                dev->features = features;
+       }
 
        return err < 0 ? 0 : 1;
 }
@@ -7398,7 +7418,7 @@ static int netif_alloc_rx_queues(struct net_device *dev)
 
        BUG_ON(count < 1);
 
-       rx = kvzalloc(sz, GFP_KERNEL | __GFP_REPEAT);
+       rx = kvzalloc(sz, GFP_KERNEL | __GFP_RETRY_MAYFAIL);
        if (!rx)
                return -ENOMEM;
 
@@ -7438,7 +7458,7 @@ static int netif_alloc_netdev_queues(struct net_device *dev)
        if (count < 1 || count > 0xffff)
                return -EINVAL;
 
-       tx = kvzalloc(sz, GFP_KERNEL | __GFP_REPEAT);
+       tx = kvzalloc(sz, GFP_KERNEL | __GFP_RETRY_MAYFAIL);
        if (!tx)
                return -ENOMEM;
 
@@ -7530,6 +7550,12 @@ int register_netdevice(struct net_device *dev)
         */
        dev->hw_features |= NETIF_F_SOFT_FEATURES;
        dev->features |= NETIF_F_SOFT_FEATURES;
+
+       if (dev->netdev_ops->ndo_udp_tunnel_add) {
+               dev->features |= NETIF_F_RX_UDP_TUNNEL_PORT;
+               dev->hw_features |= NETIF_F_RX_UDP_TUNNEL_PORT;
+       }
+
        dev->wanted_features = dev->features & dev->hw_features;
 
        if (!(dev->flags & IFF_LOOPBACK))
@@ -7979,7 +8005,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
        /* ensure 32-byte alignment of whole construct */
        alloc_size += NETDEV_ALIGN - 1;
 
-       p = kvzalloc(alloc_size, GFP_KERNEL | __GFP_REPEAT);
+       p = kvzalloc(alloc_size, GFP_KERNEL | __GFP_RETRY_MAYFAIL);
        if (!p)
                return NULL;
 
index 82fd4c9..709a4e6 100644 (file)
@@ -28,6 +28,7 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg)
 
        if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
                return -EFAULT;
+       ifr.ifr_name[IFNAMSIZ-1] = 0;
 
        error = netdev_get_name(net, ifr.ifr_name, ifr.ifr_ifindex);
        if (error)
@@ -262,6 +263,8 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                return dev_set_mtu(dev, ifr->ifr_mtu);
 
        case SIOCSIFHWADDR:
+               if (dev->addr_len > sizeof(struct sockaddr))
+                       return -EINVAL;
                return dev_set_mac_address(dev, &ifr->ifr_hwaddr);
 
        case SIOCSIFHWBROADCAST:
@@ -424,6 +427,8 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
                if (copy_from_user(&iwr, arg, sizeof(iwr)))
                        return -EFAULT;
 
+               iwr.ifr_name[sizeof(iwr.ifr_name) - 1] = 0;
+
                return wext_handle_ioctl(net, &iwr, cmd, arg);
        }
 
index 78408ab..6a582ae 100644 (file)
@@ -105,6 +105,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
        [NETIF_F_HW_TC_BIT] =            "hw-tc-offload",
        [NETIF_F_HW_ESP_BIT] =           "esp-hw-offload",
        [NETIF_F_HW_ESP_TX_CSUM_BIT] =   "esp-tx-csum-hw-offload",
+       [NETIF_F_RX_UDP_TUNNEL_PORT_BIT] =       "rx-udp_tunnel-port-offload",
 };
 
 static const char
@@ -2511,6 +2512,33 @@ static int set_phy_tunable(struct net_device *dev, void __user *useraddr)
        return ret;
 }
 
+static int ethtool_get_fecparam(struct net_device *dev, void __user *useraddr)
+{
+       struct ethtool_fecparam fecparam = { ETHTOOL_GFECPARAM };
+
+       if (!dev->ethtool_ops->get_fecparam)
+               return -EOPNOTSUPP;
+
+       dev->ethtool_ops->get_fecparam(dev, &fecparam);
+
+       if (copy_to_user(useraddr, &fecparam, sizeof(fecparam)))
+               return -EFAULT;
+       return 0;
+}
+
+static int ethtool_set_fecparam(struct net_device *dev, void __user *useraddr)
+{
+       struct ethtool_fecparam fecparam;
+
+       if (!dev->ethtool_ops->set_fecparam)
+               return -EOPNOTSUPP;
+
+       if (copy_from_user(&fecparam, useraddr, sizeof(fecparam)))
+               return -EFAULT;
+
+       return dev->ethtool_ops->set_fecparam(dev, &fecparam);
+}
+
 /* The main entry point in this file.  Called from net/core/dev_ioctl.c */
 
 int dev_ethtool(struct net *net, struct ifreq *ifr)
@@ -2569,6 +2597,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_GTUNABLE:
        case ETHTOOL_PHY_GTUNABLE:
        case ETHTOOL_GLINKSETTINGS:
+       case ETHTOOL_GFECPARAM:
                break;
        default:
                if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
@@ -2778,6 +2807,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_PHY_STUNABLE:
                rc = set_phy_tunable(dev, useraddr);
                break;
+       case ETHTOOL_GFECPARAM:
+               rc = ethtool_get_fecparam(dev, useraddr);
+               break;
+       case ETHTOOL_SFECPARAM:
+               rc = ethtool_set_fecparam(dev, useraddr);
+               break;
        default:
                rc = -EOPNOTSUPP;
        }
index a0093e1..fdcb1bc 100644 (file)
@@ -400,6 +400,7 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
                err = -ENOMEM;
                goto errout;
        }
+       refcount_set(&rule->refcnt, 1);
        rule->fr_net = net;
 
        rule->pref = tb[FRA_PRIORITY] ? nla_get_u32(tb[FRA_PRIORITY])
@@ -517,8 +518,6 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
                last = r;
        }
 
-       refcount_set(&rule->refcnt, 1);
-
        if (last)
                list_add_rcu(&rule->list, &last->list);
        else
index 29e690c..7e97086 100644 (file)
@@ -2275,7 +2275,7 @@ static int bpf_skb_adjust_net(struct sk_buff *skb, s32 len_diff)
                       bpf_skb_net_grow(skb, len_diff_abs);
 
        bpf_compute_data_end(skb);
-       return 0;
+       return ret;
 }
 
 BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,
index e31fc11..d071362 100644 (file)
@@ -347,8 +347,7 @@ out_entries:
 
 static void neigh_get_hash_rnd(u32 *x)
 {
-       get_random_bytes(x, sizeof(*x));
-       *x |= 1;
+       *x = get_random_u32() | 1;
 }
 
 static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
index d3408a6..912731b 100644 (file)
@@ -277,7 +277,7 @@ static void zap_completion_queue(void)
                        struct sk_buff *skb = clist;
                        clist = clist->next;
                        if (!skb_irq_freeable(skb)) {
-                               refcount_inc(&skb->users);
+                               refcount_set(&skb->users, 1);
                                dev_kfree_skb_any(skb); /* put this one back */
                        } else {
                                __kfree_skb(skb);
@@ -666,7 +666,7 @@ int netpoll_setup(struct netpoll *np)
        int err;
 
        rtnl_lock();
-       if (np->dev_name) {
+       if (np->dev_name[0]) {
                struct net *net = current->nsproxy->net_ns;
                ndev = __dev_get_by_name(net, np->dev_name);
        }
index d1ba909..9201e36 100644 (file)
@@ -2031,7 +2031,8 @@ static int do_setlink(const struct sk_buff *skb,
                struct sockaddr *sa;
                int len;
 
-               len = sizeof(sa_family_t) + dev->addr_len;
+               len = sizeof(sa_family_t) + max_t(size_t, dev->addr_len,
+                                                 sizeof(*sa));
                sa = kmalloc(len, GFP_KERNEL);
                if (!sa) {
                        err = -ENOMEM;
@@ -4241,6 +4242,7 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi
 
        switch (event) {
        case NETDEV_REBOOT:
+       case NETDEV_CHANGEADDR:
        case NETDEV_CHANGENAME:
        case NETDEV_FEAT_CHANGE:
        case NETDEV_BONDING_FAILOVER:
index 6bc19c8..0f0933b 100644 (file)
@@ -638,7 +638,8 @@ void skb_release_head_state(struct sk_buff *skb)
 static void skb_release_all(struct sk_buff *skb)
 {
        skb_release_head_state(skb);
-       skb_release_data(skb);
+       if (likely(skb->head))
+               skb_release_data(skb);
 }
 
 /**
@@ -937,8 +938,10 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
        struct ubuf_info *uarg = skb_shinfo(skb)->destructor_arg;
 
        for (i = 0; i < num_frags; i++) {
-               u8 *vaddr;
                skb_frag_t *f = &skb_shinfo(skb)->frags[i];
+               u32 p_off, p_len, copied;
+               struct page *p;
+               u8 *vaddr;
 
                page = alloc_page(gfp_mask);
                if (!page) {
@@ -949,10 +952,15 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
                        }
                        return -ENOMEM;
                }
-               vaddr = kmap_atomic(skb_frag_page(f));
-               memcpy(page_address(page),
-                      vaddr + f->page_offset, skb_frag_size(f));
-               kunmap_atomic(vaddr);
+
+               skb_frag_foreach_page(f, f->page_offset, skb_frag_size(f),
+                                     p, p_off, p_len, copied) {
+                       vaddr = kmap_atomic(p);
+                       memcpy(page_address(page) + copied, vaddr + p_off,
+                              p_len);
+                       kunmap_atomic(vaddr);
+               }
+
                set_page_private(page, (unsigned long)head);
                head = page;
        }
@@ -1752,16 +1760,20 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
 
                end = start + skb_frag_size(f);
                if ((copy = end - offset) > 0) {
+                       u32 p_off, p_len, copied;
+                       struct page *p;
                        u8 *vaddr;
 
                        if (copy > len)
                                copy = len;
 
-                       vaddr = kmap_atomic(skb_frag_page(f));
-                       memcpy(to,
-                              vaddr + f->page_offset + offset - start,
-                              copy);
-                       kunmap_atomic(vaddr);
+                       skb_frag_foreach_page(f,
+                                             f->page_offset + offset - start,
+                                             copy, p, p_off, p_len, copied) {
+                               vaddr = kmap_atomic(p);
+                               memcpy(to + copied, vaddr + p_off, p_len);
+                               kunmap_atomic(vaddr);
+                       }
 
                        if ((len -= copy) == 0)
                                return 0;
@@ -1981,6 +1993,107 @@ int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
 }
 EXPORT_SYMBOL_GPL(skb_splice_bits);
 
+/* Send skb data on a socket. Socket must be locked. */
+int skb_send_sock_locked(struct sock *sk, struct sk_buff *skb, int offset,
+                        int len)
+{
+       unsigned int orig_len = len;
+       struct sk_buff *head = skb;
+       unsigned short fragidx;
+       int slen, ret;
+
+do_frag_list:
+
+       /* Deal with head data */
+       while (offset < skb_headlen(skb) && len) {
+               struct kvec kv;
+               struct msghdr msg;
+
+               slen = min_t(int, len, skb_headlen(skb) - offset);
+               kv.iov_base = skb->data + offset;
+               kv.iov_len = len;
+               memset(&msg, 0, sizeof(msg));
+
+               ret = kernel_sendmsg_locked(sk, &msg, &kv, 1, slen);
+               if (ret <= 0)
+                       goto error;
+
+               offset += ret;
+               len -= ret;
+       }
+
+       /* All the data was skb head? */
+       if (!len)
+               goto out;
+
+       /* Make offset relative to start of frags */
+       offset -= skb_headlen(skb);
+
+       /* Find where we are in frag list */
+       for (fragidx = 0; fragidx < skb_shinfo(skb)->nr_frags; fragidx++) {
+               skb_frag_t *frag  = &skb_shinfo(skb)->frags[fragidx];
+
+               if (offset < frag->size)
+                       break;
+
+               offset -= frag->size;
+       }
+
+       for (; len && fragidx < skb_shinfo(skb)->nr_frags; fragidx++) {
+               skb_frag_t *frag  = &skb_shinfo(skb)->frags[fragidx];
+
+               slen = min_t(size_t, len, frag->size - offset);
+
+               while (slen) {
+                       ret = kernel_sendpage_locked(sk, frag->page.p,
+                                                    frag->page_offset + offset,
+                                                    slen, MSG_DONTWAIT);
+                       if (ret <= 0)
+                               goto error;
+
+                       len -= ret;
+                       offset += ret;
+                       slen -= ret;
+               }
+
+               offset = 0;
+       }
+
+       if (len) {
+               /* Process any frag lists */
+
+               if (skb == head) {
+                       if (skb_has_frag_list(skb)) {
+                               skb = skb_shinfo(skb)->frag_list;
+                               goto do_frag_list;
+                       }
+               } else if (skb->next) {
+                       skb = skb->next;
+                       goto do_frag_list;
+               }
+       }
+
+out:
+       return orig_len - len;
+
+error:
+       return orig_len == len ? ret : orig_len - len;
+}
+EXPORT_SYMBOL_GPL(skb_send_sock_locked);
+
+/* Send skb data on a socket. */
+int skb_send_sock(struct sock *sk, struct sk_buff *skb, int offset, int len)
+{
+       int ret = 0;
+
+       lock_sock(sk);
+       ret = skb_send_sock_locked(sk, skb, offset, len);
+       release_sock(sk);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(skb_send_sock);
+
 /**
  *     skb_store_bits - store bits from kernel buffer to skb
  *     @skb: destination buffer
@@ -2020,15 +2133,20 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
 
                end = start + skb_frag_size(frag);
                if ((copy = end - offset) > 0) {
+                       u32 p_off, p_len, copied;
+                       struct page *p;
                        u8 *vaddr;
 
                        if (copy > len)
                                copy = len;
 
-                       vaddr = kmap_atomic(skb_frag_page(frag));
-                       memcpy(vaddr + frag->page_offset + offset - start,
-                              from, copy);
-                       kunmap_atomic(vaddr);
+                       skb_frag_foreach_page(frag,
+                                             frag->page_offset + offset - start,
+                                             copy, p, p_off, p_len, copied) {
+                               vaddr = kmap_atomic(p);
+                               memcpy(vaddr + p_off, from + copied, p_len);
+                               kunmap_atomic(vaddr);
+                       }
 
                        if ((len -= copy) == 0)
                                return 0;
@@ -2093,20 +2211,27 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
 
                end = start + skb_frag_size(frag);
                if ((copy = end - offset) > 0) {
+                       u32 p_off, p_len, copied;
+                       struct page *p;
                        __wsum csum2;
                        u8 *vaddr;
 
                        if (copy > len)
                                copy = len;
-                       vaddr = kmap_atomic(skb_frag_page(frag));
-                       csum2 = ops->update(vaddr + frag->page_offset +
-                                           offset - start, copy, 0);
-                       kunmap_atomic(vaddr);
-                       csum = ops->combine(csum, csum2, pos, copy);
+
+                       skb_frag_foreach_page(frag,
+                                             frag->page_offset + offset - start,
+                                             copy, p, p_off, p_len, copied) {
+                               vaddr = kmap_atomic(p);
+                               csum2 = ops->update(vaddr + p_off, p_len, 0);
+                               kunmap_atomic(vaddr);
+                               csum = ops->combine(csum, csum2, pos, p_len);
+                               pos += p_len;
+                       }
+
                        if (!(len -= copy))
                                return csum;
                        offset += copy;
-                       pos    += copy;
                }
                start = end;
        }
@@ -2179,24 +2304,31 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
 
                end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
                if ((copy = end - offset) > 0) {
+                       skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+                       u32 p_off, p_len, copied;
+                       struct page *p;
                        __wsum csum2;
                        u8 *vaddr;
-                       skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
                        if (copy > len)
                                copy = len;
-                       vaddr = kmap_atomic(skb_frag_page(frag));
-                       csum2 = csum_partial_copy_nocheck(vaddr +
-                                                         frag->page_offset +
-                                                         offset - start, to,
-                                                         copy, 0);
-                       kunmap_atomic(vaddr);
-                       csum = csum_block_add(csum, csum2, pos);
+
+                       skb_frag_foreach_page(frag,
+                                             frag->page_offset + offset - start,
+                                             copy, p, p_off, p_len, copied) {
+                               vaddr = kmap_atomic(p);
+                               csum2 = csum_partial_copy_nocheck(vaddr + p_off,
+                                                                 to + copied,
+                                                                 p_len, 0);
+                               kunmap_atomic(vaddr);
+                               csum = csum_block_add(csum, csum2, pos);
+                               pos += p_len;
+                       }
+
                        if (!(len -= copy))
                                return csum;
                        offset += copy;
                        to     += copy;
-                       pos    += copy;
                }
                start = end;
        }
@@ -4723,7 +4855,7 @@ struct sk_buff *alloc_skb_with_frags(unsigned long header_len,
 
        gfp_head = gfp_mask;
        if (gfp_head & __GFP_DIRECT_RECLAIM)
-               gfp_head |= __GFP_REPEAT;
+               gfp_head |= __GFP_RETRY_MAYFAIL;
 
        *errcode = -ENOBUFS;
        skb = alloc_skb(header_len, gfp_head);
index ac2a404..742f68c 100644 (file)
@@ -2500,6 +2500,12 @@ int sock_no_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
 }
 EXPORT_SYMBOL(sock_no_sendmsg);
 
+int sock_no_sendmsg_locked(struct sock *sk, struct msghdr *m, size_t len)
+{
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(sock_no_sendmsg_locked);
+
 int sock_no_recvmsg(struct socket *sock, struct msghdr *m, size_t len,
                    int flags)
 {
@@ -2528,6 +2534,22 @@ ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, siz
 }
 EXPORT_SYMBOL(sock_no_sendpage);
 
+ssize_t sock_no_sendpage_locked(struct sock *sk, struct page *page,
+                               int offset, size_t size, int flags)
+{
+       ssize_t res;
+       struct msghdr msg = {.msg_flags = flags};
+       struct kvec iov;
+       char *kaddr = kmap(page);
+
+       iov.iov_base = kaddr + offset;
+       iov.iov_len = size;
+       res = kernel_sendmsg_locked(sk, &msg, &iov, 1, size);
+       kunmap(page);
+       return res;
+}
+EXPORT_SYMBOL(sock_no_sendpage_locked);
+
 /*
  *     Default Socket Callbacks
  */
index 1704948..f227f00 100644 (file)
@@ -1471,9 +1471,12 @@ int dccp_feat_init(struct sock *sk)
         * singleton values (which always leads to failure).
         * These settings can still (later) be overridden via sockopts.
         */
-       if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
-           ccid_get_builtin_ccids(&rx.val, &rx.len))
+       if (ccid_get_builtin_ccids(&tx.val, &tx.len))
                return -ENOBUFS;
+       if (ccid_get_builtin_ccids(&rx.val, &rx.len)) {
+               kfree(tx.val);
+               return -ENOBUFS;
+       }
 
        if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
            !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
index 4a05d78..fa6be97 100644 (file)
@@ -126,7 +126,7 @@ static int dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb)
 
 static u16 dccp_reset_code_convert(const u8 code)
 {
-       const u16 error_code[] = {
+       static const u16 error_code[] = {
        [DCCP_RESET_CODE_CLOSED]             = 0,       /* normal termination */
        [DCCP_RESET_CODE_UNSPECIFIED]        = 0,       /* nothing known */
        [DCCP_RESET_CODE_ABORTED]            = ECONNRESET,
index f85d901..1b202f1 100644 (file)
@@ -631,6 +631,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
                goto drop_and_free;
 
        inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
+       reqsk_put(req);
        return 0;
 
 drop_and_free:
index c376af5..1b58eac 100644 (file)
@@ -380,6 +380,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
                goto drop_and_free;
 
        inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
+       reqsk_put(req);
        return 0;
 
 drop_and_free:
index 56e4609..c442051 100644 (file)
@@ -509,21 +509,22 @@ static int dsa_cpu_parse(struct dsa_port *port, u32 index,
                dst->cpu_dp->netdev = ethernet_dev;
        }
 
+       /* Initialize cpu_port_mask now for drv->setup()
+        * to have access to a correct value, just like what
+        * net/dsa/dsa.c::dsa_switch_setup_one does.
+        */
+       ds->cpu_port_mask |= BIT(index);
+
        tag_protocol = ds->ops->get_tag_protocol(ds);
        dst->tag_ops = dsa_resolve_tag_protocol(tag_protocol);
        if (IS_ERR(dst->tag_ops)) {
                dev_warn(ds->dev, "No tagger for this switch\n");
+               ds->cpu_port_mask &= ~BIT(index);
                return PTR_ERR(dst->tag_ops);
        }
 
        dst->rcv = dst->tag_ops->rcv;
 
-       /* Initialize cpu_port_mask now for drv->setup()
-        * to have access to a correct value, just like what
-        * net/dsa/dsa.c::dsa_switch_setup_one does.
-        */
-       ds->cpu_port_mask |= BIT(index);
-
        return 0;
 }
 
index 5ce44fb..f0103ff 100644 (file)
@@ -944,6 +944,8 @@ const struct proto_ops inet_stream_ops = {
        .sendpage          = inet_sendpage,
        .splice_read       = tcp_splice_read,
        .read_sock         = tcp_read_sock,
+       .sendmsg_locked    = tcp_sendmsg_locked,
+       .sendpage_locked   = tcp_sendpage_locked,
        .peek_len          = tcp_peek_len,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_sock_common_setsockopt,
index 4e678fa..044d2a1 100644 (file)
@@ -1334,13 +1334,14 @@ static struct pernet_operations fib_net_ops = {
 
 void __init ip_fib_init(void)
 {
-       rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL);
-       rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL);
-       rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL);
+       fib_trie_init();
 
        register_pernet_subsys(&fib_net_ops);
+
        register_netdevice_notifier(&fib_netdev_notifier);
        register_inetaddr_notifier(&fib_inetaddr_notifier);
 
-       fib_trie_init();
+       rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL);
+       rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL);
+       rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL);
 }
index 2221001..b8d1817 100644 (file)
@@ -1452,7 +1452,7 @@ static int call_fib_nh_notifiers(struct fib_nh *fib_nh,
                return call_fib_notifiers(dev_net(fib_nh->nh_dev), event_type,
                                          &info.info);
        case FIB_EVENT_NH_DEL:
-               if ((IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
+               if ((in_dev && IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
                     fib_nh->nh_flags & RTNH_F_LINKDOWN) ||
                    (fib_nh->nh_flags & RTNH_F_DEAD))
                        return call_fib_notifiers(dev_net(fib_nh->nh_dev),
index d338f86..b631ec6 100644 (file)
@@ -599,6 +599,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
        hlen = iph->ihl * 4;
        mtu = mtu - hlen;       /* Size of data space */
        IPCB(skb)->flags |= IPSKB_FRAG_COMPLETE;
+       ll_rs = LL_RESERVED_SPACE(rt->dst.dev);
 
        /* When frag_list is given, use it. First, check its validity:
         * some transformers could create wrong frag_list or break existing
@@ -614,14 +615,15 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
                if (first_len - hlen > mtu ||
                    ((first_len - hlen) & 7) ||
                    ip_is_fragment(iph) ||
-                   skb_cloned(skb))
+                   skb_cloned(skb) ||
+                   skb_headroom(skb) < ll_rs)
                        goto slow_path;
 
                skb_walk_frags(skb, frag) {
                        /* Correct geometry. */
                        if (frag->len > mtu ||
                            ((frag->len & 7) && frag->next) ||
-                           skb_headroom(frag) < hlen)
+                           skb_headroom(frag) < hlen + ll_rs)
                                goto slow_path_clean;
 
                        /* Partially cloned skb? */
@@ -711,8 +713,6 @@ slow_path:
        left = skb->len - hlen;         /* Space per frame */
        ptr = hlen;             /* Where to start from */
 
-       ll_rs = LL_RESERVED_SPACE(rt->dst.dev);
-
        /*
         *      Fragment the datagram.
         */
index 805c8dd..4bbc273 100644 (file)
@@ -72,8 +72,7 @@ static const struct nf_chain_type filter_arp = {
        .family         = NFPROTO_ARP,
        .owner          = THIS_MODULE,
        .hook_mask      = (1 << NF_ARP_IN) |
-                         (1 << NF_ARP_OUT) |
-                         (1 << NF_ARP_FORWARD),
+                         (1 << NF_ARP_OUT),
 };
 
 static int __init nf_tables_arp_init(void)
index 43eb656..b6d3fe0 100644 (file)
@@ -206,14 +206,7 @@ static const struct snmp_mib snmp4_net_list[] = {
        SNMP_MIB_ITEM("DelayedACKLost", LINUX_MIB_DELAYEDACKLOST),
        SNMP_MIB_ITEM("ListenOverflows", LINUX_MIB_LISTENOVERFLOWS),
        SNMP_MIB_ITEM("ListenDrops", LINUX_MIB_LISTENDROPS),
-       SNMP_MIB_ITEM("TCPPrequeued", LINUX_MIB_TCPPREQUEUED),
-       SNMP_MIB_ITEM("TCPDirectCopyFromBacklog", LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG),
-       SNMP_MIB_ITEM("TCPDirectCopyFromPrequeue", LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE),
-       SNMP_MIB_ITEM("TCPPrequeueDropped", LINUX_MIB_TCPPREQUEUEDROPPED),
-       SNMP_MIB_ITEM("TCPHPHits", LINUX_MIB_TCPHPHITS),
-       SNMP_MIB_ITEM("TCPHPHitsToUser", LINUX_MIB_TCPHPHITSTOUSER),
        SNMP_MIB_ITEM("TCPPureAcks", LINUX_MIB_TCPPUREACKS),
-       SNMP_MIB_ITEM("TCPHPAcks", LINUX_MIB_TCPHPACKS),
        SNMP_MIB_ITEM("TCPRenoRecovery", LINUX_MIB_TCPRENORECOVERY),
        SNMP_MIB_ITEM("TCPSackRecovery", LINUX_MIB_TCPSACKRECOVERY),
        SNMP_MIB_ITEM("TCPSACKReneging", LINUX_MIB_TCPSACKRENEGING),
@@ -230,14 +223,12 @@ static const struct snmp_mib snmp4_net_list[] = {
        SNMP_MIB_ITEM("TCPSackFailures", LINUX_MIB_TCPSACKFAILURES),
        SNMP_MIB_ITEM("TCPLossFailures", LINUX_MIB_TCPLOSSFAILURES),
        SNMP_MIB_ITEM("TCPFastRetrans", LINUX_MIB_TCPFASTRETRANS),
-       SNMP_MIB_ITEM("TCPForwardRetrans", LINUX_MIB_TCPFORWARDRETRANS),
        SNMP_MIB_ITEM("TCPSlowStartRetrans", LINUX_MIB_TCPSLOWSTARTRETRANS),
        SNMP_MIB_ITEM("TCPTimeouts", LINUX_MIB_TCPTIMEOUTS),
        SNMP_MIB_ITEM("TCPLossProbes", LINUX_MIB_TCPLOSSPROBES),
        SNMP_MIB_ITEM("TCPLossProbeRecovery", LINUX_MIB_TCPLOSSPROBERECOVERY),
        SNMP_MIB_ITEM("TCPRenoRecoveryFail", LINUX_MIB_TCPRENORECOVERYFAIL),
        SNMP_MIB_ITEM("TCPSackRecoveryFail", LINUX_MIB_TCPSACKRECOVERYFAIL),
-       SNMP_MIB_ITEM("TCPSchedulerFailed", LINUX_MIB_TCPSCHEDULERFAILED),
        SNMP_MIB_ITEM("TCPRcvCollapsed", LINUX_MIB_TCPRCVCOLLAPSED),
        SNMP_MIB_ITEM("TCPDSACKOldSent", LINUX_MIB_TCPDSACKOLDSENT),
        SNMP_MIB_ITEM("TCPDSACKOfoSent", LINUX_MIB_TCPDSACKOFOSENT),
index c816cd5..0383e66 100644 (file)
@@ -2979,8 +2979,7 @@ static __net_init int rt_genid_init(struct net *net)
 {
        atomic_set(&net->ipv4.rt_genid, 0);
        atomic_set(&net->fnhe_genid, 0);
-       get_random_bytes(&net->ipv4.dev_addr_genid,
-                        sizeof(net->ipv4.dev_addr_genid));
+       atomic_set(&net->ipv4.dev_addr_genid, get_random_int());
        return 0;
 }
 
index 0905cf0..03ad877 100644 (file)
@@ -335,6 +335,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
        treq->rcv_isn           = ntohl(th->seq) - 1;
        treq->snt_isn           = cookie;
        treq->ts_off            = 0;
+       treq->txhash            = net_tx_rndhash();
        req->mss                = mss;
        ireq->ir_num            = ntohs(th->dest);
        ireq->ir_rmt_port       = th->source;
index 9bf8097..0d3c038 100644 (file)
@@ -45,6 +45,9 @@ static int tcp_syn_retries_max = MAX_TCP_SYNCNT;
 static int ip_ping_group_range_min[] = { 0, 0 };
 static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
 
+/* obsolete */
+static int sysctl_tcp_low_latency __read_mostly;
+
 /* Update system visible IP port range */
 static void set_local_port_range(struct net *net, int range[2])
 {
index 71ce33d..9dd6f4d 100644 (file)
@@ -388,6 +388,19 @@ static int retrans_to_secs(u8 retrans, int timeout, int rto_max)
        return period;
 }
 
+static u64 tcp_compute_delivery_rate(const struct tcp_sock *tp)
+{
+       u32 rate = READ_ONCE(tp->rate_delivered);
+       u32 intv = READ_ONCE(tp->rate_interval_us);
+       u64 rate64 = 0;
+
+       if (rate && intv) {
+               rate64 = (u64)rate * tp->mss_cache * USEC_PER_SEC;
+               do_div(rate64, intv);
+       }
+       return rate64;
+}
+
 /* Address-family independent initialization for a tcp_sock.
  *
  * NOTE: A lot of things set to zero explicitly by call to
@@ -400,7 +413,6 @@ void tcp_init_sock(struct sock *sk)
 
        tp->out_of_order_queue = RB_ROOT;
        tcp_init_xmit_timers(sk);
-       tcp_prequeue_init(tp);
        INIT_LIST_HEAD(&tp->tsq_node);
 
        icsk->icsk_rto = TCP_TIMEOUT_INIT;
@@ -1034,23 +1046,29 @@ out_err:
 }
 EXPORT_SYMBOL_GPL(do_tcp_sendpages);
 
-int tcp_sendpage(struct sock *sk, struct page *page, int offset,
-                size_t size, int flags)
+int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset,
+                       size_t size, int flags)
 {
-       ssize_t res;
-
        if (!(sk->sk_route_caps & NETIF_F_SG) ||
            !sk_check_csum_caps(sk))
                return sock_no_sendpage(sk->sk_socket, page, offset, size,
                                        flags);
 
-       lock_sock(sk);
-
        tcp_rate_check_app_limited(sk);  /* is sending application-limited? */
 
-       res = do_tcp_sendpages(sk, page, offset, size, flags);
+       return do_tcp_sendpages(sk, page, offset, size, flags);
+}
+
+int tcp_sendpage(struct sock *sk, struct page *page, int offset,
+                size_t size, int flags)
+{
+       int ret;
+
+       lock_sock(sk);
+       ret = tcp_sendpage_locked(sk, page, offset, size, flags);
        release_sock(sk);
-       return res;
+
+       return ret;
 }
 EXPORT_SYMBOL(tcp_sendpage);
 
@@ -1144,7 +1162,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
        return err;
 }
 
-int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
+int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
@@ -1155,8 +1173,6 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
        bool sg;
        long timeo;
 
-       lock_sock(sk);
-
        flags = msg->msg_flags;
        if (unlikely(flags & MSG_FASTOPEN || inet_sk(sk)->defer_connect)) {
                err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
@@ -1365,7 +1381,6 @@ out:
                tcp_push(sk, flags, mss_now, tp->nonagle, size_goal);
        }
 out_nopush:
-       release_sock(sk);
        return copied + copied_syn;
 
 do_fault:
@@ -1389,9 +1404,19 @@ out_err:
                sk->sk_write_space(sk);
                tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED);
        }
-       release_sock(sk);
        return err;
 }
+
+int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
+{
+       int ret;
+
+       lock_sock(sk);
+       ret = tcp_sendmsg_locked(sk, msg, size);
+       release_sock(sk);
+
+       return ret;
+}
 EXPORT_SYMBOL(tcp_sendmsg);
 
 /*
@@ -1525,20 +1550,6 @@ static void tcp_cleanup_rbuf(struct sock *sk, int copied)
                tcp_send_ack(sk);
 }
 
-static void tcp_prequeue_process(struct sock *sk)
-{
-       struct sk_buff *skb;
-       struct tcp_sock *tp = tcp_sk(sk);
-
-       NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPREQUEUED);
-
-       while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL)
-               sk_backlog_rcv(sk, skb);
-
-       /* Clear memory counter. */
-       tp->ucopy.memory = 0;
-}
-
 static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
 {
        struct sk_buff *skb;
@@ -1671,7 +1682,6 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
        int err;
        int target;             /* Read at least this many bytes */
        long timeo;
-       struct task_struct *user_recv = NULL;
        struct sk_buff *skb, *last;
        u32 urg_hole = 0;
 
@@ -1806,51 +1816,6 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
 
                tcp_cleanup_rbuf(sk, copied);
 
-               if (!sysctl_tcp_low_latency && tp->ucopy.task == user_recv) {
-                       /* Install new reader */
-                       if (!user_recv && !(flags & (MSG_TRUNC | MSG_PEEK))) {
-                               user_recv = current;
-                               tp->ucopy.task = user_recv;
-                               tp->ucopy.msg = msg;
-                       }
-
-                       tp->ucopy.len = len;
-
-                       WARN_ON(tp->copied_seq != tp->rcv_nxt &&
-                               !(flags & (MSG_PEEK | MSG_TRUNC)));
-
-                       /* Ugly... If prequeue is not empty, we have to
-                        * process it before releasing socket, otherwise
-                        * order will be broken at second iteration.
-                        * More elegant solution is required!!!
-                        *
-                        * Look: we have the following (pseudo)queues:
-                        *
-                        * 1. packets in flight
-                        * 2. backlog
-                        * 3. prequeue
-                        * 4. receive_queue
-                        *
-                        * Each queue can be processed only if the next ones
-                        * are empty. At this point we have empty receive_queue.
-                        * But prequeue _can_ be not empty after 2nd iteration,
-                        * when we jumped to start of loop because backlog
-                        * processing added something to receive_queue.
-                        * We cannot release_sock(), because backlog contains
-                        * packets arrived _after_ prequeued ones.
-                        *
-                        * Shortly, algorithm is clear --- to process all
-                        * the queues in order. We could make it more directly,
-                        * requeueing packets from backlog to prequeue, if
-                        * is not empty. It is more elegant, but eats cycles,
-                        * unfortunately.
-                        */
-                       if (!skb_queue_empty(&tp->ucopy.prequeue))
-                               goto do_prequeue;
-
-                       /* __ Set realtime policy in scheduler __ */
-               }
-
                if (copied >= target) {
                        /* Do not sleep, just process backlog. */
                        release_sock(sk);
@@ -1859,31 +1824,6 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
                        sk_wait_data(sk, &timeo, last);
                }
 
-               if (user_recv) {
-                       int chunk;
-
-                       /* __ Restore normal policy in scheduler __ */
-
-                       chunk = len - tp->ucopy.len;
-                       if (chunk != 0) {
-                               NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG, chunk);
-                               len -= chunk;
-                               copied += chunk;
-                       }
-
-                       if (tp->rcv_nxt == tp->copied_seq &&
-                           !skb_queue_empty(&tp->ucopy.prequeue)) {
-do_prequeue:
-                               tcp_prequeue_process(sk);
-
-                               chunk = len - tp->ucopy.len;
-                               if (chunk != 0) {
-                                       NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, chunk);
-                                       len -= chunk;
-                                       copied += chunk;
-                               }
-                       }
-               }
                if ((flags & MSG_PEEK) &&
                    (peek_seq - copied - urg_hole != tp->copied_seq)) {
                        net_dbg_ratelimited("TCP(%s:%d): Application bug, race in MSG_PEEK\n",
@@ -1934,10 +1874,8 @@ do_prequeue:
                tcp_rcv_space_adjust(sk);
 
 skip_copy:
-               if (tp->urg_data && after(tp->copied_seq, tp->urg_seq)) {
+               if (tp->urg_data && after(tp->copied_seq, tp->urg_seq))
                        tp->urg_data = 0;
-                       tcp_fast_path_check(sk);
-               }
                if (used + offset < skb->len)
                        continue;
 
@@ -1955,25 +1893,6 @@ skip_copy:
                break;
        } while (len > 0);
 
-       if (user_recv) {
-               if (!skb_queue_empty(&tp->ucopy.prequeue)) {
-                       int chunk;
-
-                       tp->ucopy.len = copied > 0 ? len : 0;
-
-                       tcp_prequeue_process(sk);
-
-                       if (copied > 0 && (chunk = len - tp->ucopy.len) != 0) {
-                               NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, chunk);
-                               len -= chunk;
-                               copied += chunk;
-                       }
-               }
-
-               tp->ucopy.task = NULL;
-               tp->ucopy.len = 0;
-       }
-
        /* According to UNIX98, msg_name/msg_namelen are ignored
         * on connected socket. I was just happy when found this 8) --ANK
         */
@@ -2823,7 +2742,7 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
 {
        const struct tcp_sock *tp = tcp_sk(sk); /* iff sk_type == SOCK_STREAM */
        const struct inet_connection_sock *icsk = inet_csk(sk);
-       u32 now, intv;
+       u32 now;
        u64 rate64;
        bool slow;
        u32 rate;
@@ -2922,13 +2841,9 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
        info->tcpi_data_segs_out = tp->data_segs_out;
 
        info->tcpi_delivery_rate_app_limited = tp->rate_app_limited ? 1 : 0;
-       rate = READ_ONCE(tp->rate_delivered);
-       intv = READ_ONCE(tp->rate_interval_us);
-       if (rate && intv) {
-               rate64 = (u64)rate * tp->mss_cache * USEC_PER_SEC;
-               do_div(rate64, intv);
+       rate64 = tcp_compute_delivery_rate(tp);
+       if (rate64)
                info->tcpi_delivery_rate = rate64;
-       }
        unlock_sock_fast(sk, slow);
 }
 EXPORT_SYMBOL_GPL(tcp_get_info);
@@ -2938,8 +2853,12 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk)
        const struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *stats;
        struct tcp_info info;
+       u64 rate64;
+       u32 rate;
 
-       stats = alloc_skb(5 * nla_total_size_64bit(sizeof(u64)), GFP_ATOMIC);
+       stats = alloc_skb(7 * nla_total_size_64bit(sizeof(u64)) +
+                         3 * nla_total_size(sizeof(u32)) +
+                         2 * nla_total_size(sizeof(u8)), GFP_ATOMIC);
        if (!stats)
                return NULL;
 
@@ -2954,6 +2873,20 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk)
                          tp->data_segs_out, TCP_NLA_PAD);
        nla_put_u64_64bit(stats, TCP_NLA_TOTAL_RETRANS,
                          tp->total_retrans, TCP_NLA_PAD);
+
+       rate = READ_ONCE(sk->sk_pacing_rate);
+       rate64 = rate != ~0U ? rate : ~0ULL;
+       nla_put_u64_64bit(stats, TCP_NLA_PACING_RATE, rate64, TCP_NLA_PAD);
+
+       rate64 = tcp_compute_delivery_rate(tp);
+       nla_put_u64_64bit(stats, TCP_NLA_DELIVERY_RATE, rate64, TCP_NLA_PAD);
+
+       nla_put_u32(stats, TCP_NLA_SND_CWND, tp->snd_cwnd);
+       nla_put_u32(stats, TCP_NLA_REORDERING, tp->reordering);
+       nla_put_u32(stats, TCP_NLA_MIN_RTT, tcp_min_rtt(tp));
+
+       nla_put_u8(stats, TCP_NLA_RECUR_RETRANS, inet_csk(sk)->icsk_retransmits);
+       nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, !!tp->rate_app_limited);
        return stats;
 }
 
index dbcc935..69ee877 100644 (file)
@@ -112,7 +112,8 @@ struct bbr {
                cwnd_gain:10,   /* current gain for setting cwnd */
                full_bw_cnt:3,  /* number of rounds without large bw gains */
                cycle_idx:3,    /* current index in pacing_gain cycle array */
-               unused_b:6;
+               has_seen_rtt:1, /* have we seen an RTT sample yet? */
+               unused_b:5;
        u32     prior_cwnd;     /* prior cwnd upon entering loss recovery */
        u32     full_bw;        /* recent bw, to estimate if pipe is full */
 };
@@ -211,6 +212,35 @@ static u64 bbr_rate_bytes_per_sec(struct sock *sk, u64 rate, int gain)
        return rate >> BW_SCALE;
 }
 
+/* Convert a BBR bw and gain factor to a pacing rate in bytes per second. */
+static u32 bbr_bw_to_pacing_rate(struct sock *sk, u32 bw, int gain)
+{
+       u64 rate = bw;
+
+       rate = bbr_rate_bytes_per_sec(sk, rate, gain);
+       rate = min_t(u64, rate, sk->sk_max_pacing_rate);
+       return rate;
+}
+
+/* Initialize pacing rate to: high_gain * init_cwnd / RTT. */
+static void bbr_init_pacing_rate_from_rtt(struct sock *sk)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct bbr *bbr = inet_csk_ca(sk);
+       u64 bw;
+       u32 rtt_us;
+
+       if (tp->srtt_us) {              /* any RTT sample yet? */
+               rtt_us = max(tp->srtt_us >> 3, 1U);
+               bbr->has_seen_rtt = 1;
+       } else {                         /* no RTT sample yet */
+               rtt_us = USEC_PER_MSEC;  /* use nominal default RTT */
+       }
+       bw = (u64)tp->snd_cwnd * BW_UNIT;
+       do_div(bw, rtt_us);
+       sk->sk_pacing_rate = bbr_bw_to_pacing_rate(sk, bw, bbr_high_gain);
+}
+
 /* Pace using current bw estimate and a gain factor. In order to help drive the
  * network toward lower queues while maintaining high utilization and low
  * latency, the average pacing rate aims to be slightly (~1%) lower than the
@@ -220,12 +250,13 @@ static u64 bbr_rate_bytes_per_sec(struct sock *sk, u64 rate, int gain)
  */
 static void bbr_set_pacing_rate(struct sock *sk, u32 bw, int gain)
 {
+       struct tcp_sock *tp = tcp_sk(sk);
        struct bbr *bbr = inet_csk_ca(sk);
-       u64 rate = bw;
+       u32 rate = bbr_bw_to_pacing_rate(sk, bw, gain);
 
-       rate = bbr_rate_bytes_per_sec(sk, rate, gain);
-       rate = min_t(u64, rate, sk->sk_max_pacing_rate);
-       if (bbr->mode != BBR_STARTUP || rate > sk->sk_pacing_rate)
+       if (unlikely(!bbr->has_seen_rtt && tp->srtt_us))
+               bbr_init_pacing_rate_from_rtt(sk);
+       if (bbr_full_bw_reached(sk) || rate > sk->sk_pacing_rate)
                sk->sk_pacing_rate = rate;
 }
 
@@ -798,7 +829,6 @@ static void bbr_init(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct bbr *bbr = inet_csk_ca(sk);
-       u64 bw;
 
        bbr->prior_cwnd = 0;
        bbr->tso_segs_goal = 0;  /* default segs per skb until first ACK */
@@ -814,11 +844,8 @@ static void bbr_init(struct sock *sk)
 
        minmax_reset(&bbr->bw, bbr->rtt_cnt, 0);  /* init max bw to 0 */
 
-       /* Initialize pacing rate to: high_gain * init_cwnd / RTT. */
-       bw = (u64)tp->snd_cwnd * BW_UNIT;
-       do_div(bw, (tp->srtt_us >> 3) ? : USEC_PER_MSEC);
-       sk->sk_pacing_rate = 0;         /* force an update of sk_pacing_rate */
-       bbr_set_pacing_rate(sk, bw, bbr_high_gain);
+       bbr->has_seen_rtt = 0;
+       bbr_init_pacing_rate_from_rtt(sk);
 
        bbr->restore_cwnd = 0;
        bbr->round_start = 0;
index 2920e0c..af0a98d 100644 (file)
@@ -103,7 +103,6 @@ int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2;
 #define FLAG_DATA_SACKED       0x20 /* New SACK.                               */
 #define FLAG_ECE               0x40 /* ECE in this ACK                         */
 #define FLAG_LOST_RETRANS      0x80 /* This ACK marks some retransmission lost */
-#define FLAG_SLOWPATH          0x100 /* Do not skip RFC checks for window update.*/
 #define FLAG_ORIG_SACK_ACKED   0x200 /* Never retransmitted data are (s)acked  */
 #define FLAG_SND_UNA_ADVANCED  0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */
 #define FLAG_DSACKING_ACK      0x800 /* SACK blocks contained D-SACK info */
@@ -3367,12 +3366,6 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32
                if (tp->snd_wnd != nwin) {
                        tp->snd_wnd = nwin;
 
-                       /* Note, it is the only place, where
-                        * fast path is recovered for sending TCP.
-                        */
-                       tp->pred_flags = 0;
-                       tcp_fast_path_check(sk);
-
                        if (tcp_send_head(sk))
                                tcp_slow_start_after_idle_check(sk);
 
@@ -3554,6 +3547,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
        u32 lost = tp->lost;
        int acked = 0; /* Number of packets newly acked */
        int rexmit = REXMIT_NONE; /* Flag to (re)transmit to recover losses */
+       u32 ack_ev_flags = 0;
 
        sack_state.first_sackt = 0;
        sack_state.rate = &rs;
@@ -3597,42 +3591,26 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
        if (flag & FLAG_UPDATE_TS_RECENT)
                tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
 
-       if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
-               /* Window is constant, pure forward advance.
-                * No more checks are required.
-                * Note, we use the fact that SND.UNA>=SND.WL2.
-                */
-               tcp_update_wl(tp, ack_seq);
-               tcp_snd_una_update(tp, ack);
-               flag |= FLAG_WIN_UPDATE;
-
-               tcp_in_ack_event(sk, CA_ACK_WIN_UPDATE);
-
-               NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPHPACKS);
-       } else {
-               u32 ack_ev_flags = CA_ACK_SLOWPATH;
-
-               if (ack_seq != TCP_SKB_CB(skb)->end_seq)
-                       flag |= FLAG_DATA;
-               else
-                       NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPUREACKS);
+       if (ack_seq != TCP_SKB_CB(skb)->end_seq)
+               flag |= FLAG_DATA;
+       else
+               NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPUREACKS);
 
-               flag |= tcp_ack_update_window(sk, skb, ack, ack_seq);
+       flag |= tcp_ack_update_window(sk, skb, ack, ack_seq);
 
-               if (TCP_SKB_CB(skb)->sacked)
-                       flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
-                                                       &sack_state);
+       if (TCP_SKB_CB(skb)->sacked)
+               flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
+                                               &sack_state);
 
-               if (tcp_ecn_rcv_ecn_echo(tp, tcp_hdr(skb))) {
-                       flag |= FLAG_ECE;
-                       ack_ev_flags |= CA_ACK_ECE;
-               }
+       if (tcp_ecn_rcv_ecn_echo(tp, tcp_hdr(skb))) {
+               flag |= FLAG_ECE;
+               ack_ev_flags = CA_ACK_ECE;
+       }
 
-               if (flag & FLAG_WIN_UPDATE)
-                       ack_ev_flags |= CA_ACK_WIN_UPDATE;
+       if (flag & FLAG_WIN_UPDATE)
+               ack_ev_flags |= CA_ACK_WIN_UPDATE;
 
-               tcp_in_ack_event(sk, ack_ev_flags);
-       }
+       tcp_in_ack_event(sk, ack_ev_flags);
 
        /* We passed data and got it acked, remove any soft error
         * log. Something worked...
@@ -4398,8 +4376,6 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
                return;
        }
 
-       /* Disable header prediction. */
-       tp->pred_flags = 0;
        inet_csk_schedule_ack(sk);
 
        NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFOQUEUE);
@@ -4611,32 +4587,14 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                        goto out_of_window;
 
                /* Ok. In sequence. In window. */
-               if (tp->ucopy.task == current &&
-                   tp->copied_seq == tp->rcv_nxt && tp->ucopy.len &&
-                   sock_owned_by_user(sk) && !tp->urg_data) {
-                       int chunk = min_t(unsigned int, skb->len,
-                                         tp->ucopy.len);
-
-                       __set_current_state(TASK_RUNNING);
-
-                       if (!skb_copy_datagram_msg(skb, 0, tp->ucopy.msg, chunk)) {
-                               tp->ucopy.len -= chunk;
-                               tp->copied_seq += chunk;
-                               eaten = (chunk == skb->len);
-                               tcp_rcv_space_adjust(sk);
-                       }
-               }
-
-               if (eaten <= 0) {
 queue_and_out:
-                       if (eaten < 0) {
-                               if (skb_queue_len(&sk->sk_receive_queue) == 0)
-                                       sk_forced_mem_schedule(sk, skb->truesize);
-                               else if (tcp_try_rmem_schedule(sk, skb, skb->truesize))
-                                       goto drop;
-                       }
-                       eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen);
+               if (eaten < 0) {
+                       if (skb_queue_len(&sk->sk_receive_queue) == 0)
+                               sk_forced_mem_schedule(sk, skb->truesize);
+                       else if (tcp_try_rmem_schedule(sk, skb, skb->truesize))
+                               goto drop;
                }
+               eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen);
                tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq);
                if (skb->len)
                        tcp_event_data_recv(sk, skb);
@@ -4656,8 +4614,6 @@ queue_and_out:
                if (tp->rx_opt.num_sacks)
                        tcp_sack_remove(tp);
 
-               tcp_fast_path_check(sk);
-
                if (eaten > 0)
                        kfree_skb_partial(skb, fragstolen);
                if (!sock_flag(sk, SOCK_DEAD))
@@ -4983,7 +4939,6 @@ static int tcp_prune_queue(struct sock *sk)
        NET_INC_STATS(sock_net(sk), LINUX_MIB_RCVPRUNED);
 
        /* Massive buffer overcommit. */
-       tp->pred_flags = 0;
        return -1;
 }
 
@@ -5155,9 +5110,6 @@ static void tcp_check_urg(struct sock *sk, const struct tcphdr *th)
 
        tp->urg_data = TCP_URG_NOTYET;
        tp->urg_seq = ptr;
-
-       /* Disable header prediction. */
-       tp->pred_flags = 0;
 }
 
 /* This is the 'fast' part of urgent handling. */
@@ -5186,26 +5138,6 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, const struct tcphdr *t
        }
 }
 
-static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen)
-{
-       struct tcp_sock *tp = tcp_sk(sk);
-       int chunk = skb->len - hlen;
-       int err;
-
-       if (skb_csum_unnecessary(skb))
-               err = skb_copy_datagram_msg(skb, hlen, tp->ucopy.msg, chunk);
-       else
-               err = skb_copy_and_csum_datagram_msg(skb, hlen, tp->ucopy.msg);
-
-       if (!err) {
-               tp->ucopy.len -= chunk;
-               tp->copied_seq += chunk;
-               tcp_rcv_space_adjust(sk);
-       }
-
-       return err;
-}
-
 /* Accept RST for rcv_nxt - 1 after a FIN.
  * When tcp connections are abruptly terminated from Mac OSX (via ^C), a
  * FIN is sent followed by a RST packet. The RST is sent with the same
@@ -5336,201 +5268,29 @@ discard:
 
 /*
  *     TCP receive function for the ESTABLISHED state.
- *
- *     It is split into a fast path and a slow path. The fast path is
- *     disabled when:
- *     - A zero window was announced from us - zero window probing
- *        is only handled properly in the slow path.
- *     - Out of order segments arrived.
- *     - Urgent data is expected.
- *     - There is no buffer space left
- *     - Unexpected TCP flags/window values/header lengths are received
- *       (detected by checking the TCP header against pred_flags)
- *     - Data is sent in both directions. Fast path only supports pure senders
- *       or pure receivers (this means either the sequence number or the ack
- *       value must stay constant)
- *     - Unexpected TCP option.
- *
- *     When these conditions are not satisfied it drops into a standard
- *     receive procedure patterned after RFC793 to handle all cases.
- *     The first three cases are guaranteed by proper pred_flags setting,
- *     the rest is checked inline. Fast processing is turned on in
- *     tcp_data_queue when everything is OK.
  */
 void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
-                        const struct tcphdr *th, unsigned int len)
+                        const struct tcphdr *th)
 {
+       unsigned int len = skb->len;
        struct tcp_sock *tp = tcp_sk(sk);
 
        tcp_mstamp_refresh(tp);
        if (unlikely(!sk->sk_rx_dst))
                inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb);
-       /*
-        *      Header prediction.
-        *      The code loosely follows the one in the famous
-        *      "30 instruction TCP receive" Van Jacobson mail.
-        *
-        *      Van's trick is to deposit buffers into socket queue
-        *      on a device interrupt, to call tcp_recv function
-        *      on the receive process context and checksum and copy
-        *      the buffer to user space. smart...
-        *
-        *      Our current scheme is not silly either but we take the
-        *      extra cost of the net_bh soft interrupt processing...
-        *      We do checksum and copy also but from device to kernel.
-        */
 
        tp->rx_opt.saw_tstamp = 0;
 
-       /*      pred_flags is 0xS?10 << 16 + snd_wnd
-        *      if header_prediction is to be made
-        *      'S' will always be tp->tcp_header_len >> 2
-        *      '?' will be 0 for the fast path, otherwise pred_flags is 0 to
-        *  turn it off (when there are holes in the receive
-        *       space for instance)
-        *      PSH flag is ignored.
-        */
-
-       if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
-           TCP_SKB_CB(skb)->seq == tp->rcv_nxt &&
-           !after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) {
-               int tcp_header_len = tp->tcp_header_len;
-
-               /* Timestamp header prediction: tcp_header_len
-                * is automatically equal to th->doff*4 due to pred_flags
-                * match.
-                */
-
-               /* Check timestamp */
-               if (tcp_header_len == sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) {
-                       /* No? Slow path! */
-                       if (!tcp_parse_aligned_timestamp(tp, th))
-                               goto slow_path;
-
-                       /* If PAWS failed, check it more carefully in slow path */
-                       if ((s32)(tp->rx_opt.rcv_tsval - tp->rx_opt.ts_recent) < 0)
-                               goto slow_path;
-
-                       /* DO NOT update ts_recent here, if checksum fails
-                        * and timestamp was corrupted part, it will result
-                        * in a hung connection since we will drop all
-                        * future packets due to the PAWS test.
-                        */
-               }
-
-               if (len <= tcp_header_len) {
-                       /* Bulk data transfer: sender */
-                       if (len == tcp_header_len) {
-                               /* Predicted packet is in window by definition.
-                                * seq == rcv_nxt and rcv_wup <= rcv_nxt.
-                                * Hence, check seq<=rcv_wup reduces to:
-                                */
-                               if (tcp_header_len ==
-                                   (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) &&
-                                   tp->rcv_nxt == tp->rcv_wup)
-                                       tcp_store_ts_recent(tp);
-
-                               /* We know that such packets are checksummed
-                                * on entry.
-                                */
-                               tcp_ack(sk, skb, 0);
-                               __kfree_skb(skb);
-                               tcp_data_snd_check(sk);
-                               return;
-                       } else { /* Header too small */
-                               TCP_INC_STATS(sock_net(sk), TCP_MIB_INERRS);
-                               goto discard;
-                       }
-               } else {
-                       int eaten = 0;
-                       bool fragstolen = false;
-
-                       if (tp->ucopy.task == current &&
-                           tp->copied_seq == tp->rcv_nxt &&
-                           len - tcp_header_len <= tp->ucopy.len &&
-                           sock_owned_by_user(sk)) {
-                               __set_current_state(TASK_RUNNING);
-
-                               if (!tcp_copy_to_iovec(sk, skb, tcp_header_len)) {
-                                       /* Predicted packet is in window by definition.
-                                        * seq == rcv_nxt and rcv_wup <= rcv_nxt.
-                                        * Hence, check seq<=rcv_wup reduces to:
-                                        */
-                                       if (tcp_header_len ==
-                                           (sizeof(struct tcphdr) +
-                                            TCPOLEN_TSTAMP_ALIGNED) &&
-                                           tp->rcv_nxt == tp->rcv_wup)
-                                               tcp_store_ts_recent(tp);
-
-                                       tcp_rcv_rtt_measure_ts(sk, skb);
-
-                                       __skb_pull(skb, tcp_header_len);
-                                       tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq);
-                                       NET_INC_STATS(sock_net(sk),
-                                                       LINUX_MIB_TCPHPHITSTOUSER);
-                                       eaten = 1;
-                               }
-                       }
-                       if (!eaten) {
-                               if (tcp_checksum_complete(skb))
-                                       goto csum_error;
-
-                               if ((int)skb->truesize > sk->sk_forward_alloc)
-                                       goto step5;
-
-                               /* Predicted packet is in window by definition.
-                                * seq == rcv_nxt and rcv_wup <= rcv_nxt.
-                                * Hence, check seq<=rcv_wup reduces to:
-                                */
-                               if (tcp_header_len ==
-                                   (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) &&
-                                   tp->rcv_nxt == tp->rcv_wup)
-                                       tcp_store_ts_recent(tp);
-
-                               tcp_rcv_rtt_measure_ts(sk, skb);
-
-                               NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPHPHITS);
-
-                               /* Bulk data transfer: receiver */
-                               eaten = tcp_queue_rcv(sk, skb, tcp_header_len,
-                                                     &fragstolen);
-                       }
-
-                       tcp_event_data_recv(sk, skb);
-
-                       if (TCP_SKB_CB(skb)->ack_seq != tp->snd_una) {
-                               /* Well, only one small jumplet in fast path... */
-                               tcp_ack(sk, skb, FLAG_DATA);
-                               tcp_data_snd_check(sk);
-                               if (!inet_csk_ack_scheduled(sk))
-                                       goto no_ack;
-                       }
-
-                       __tcp_ack_snd_check(sk, 0);
-no_ack:
-                       if (eaten)
-                               kfree_skb_partial(skb, fragstolen);
-                       sk->sk_data_ready(sk);
-                       return;
-               }
-       }
-
-slow_path:
        if (len < (th->doff << 2) || tcp_checksum_complete(skb))
                goto csum_error;
 
        if (!th->ack && !th->rst && !th->syn)
                goto discard;
 
-       /*
-        *      Standard slow path.
-        */
-
        if (!tcp_validate_incoming(sk, skb, th, 1))
                return;
 
-step5:
-       if (tcp_ack(sk, skb, FLAG_SLOWPATH | FLAG_UPDATE_TS_RECENT) < 0)
+       if (tcp_ack(sk, skb, FLAG_UPDATE_TS_RECENT) < 0)
                goto discard;
 
        tcp_rcv_rtt_measure_ts(sk, skb);
@@ -5584,11 +5344,10 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
        if (sock_flag(sk, SOCK_KEEPOPEN))
                inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp));
 
-       if (!tp->rx_opt.snd_wscale)
-               __tcp_fast_path_on(tp, tp->snd_wnd);
-       else
-               tp->pred_flags = 0;
-
+       if (!sock_flag(sk, SOCK_DEAD)) {
+               sk->sk_state_change(sk);
+               sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT);
+       }
 }
 
 static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
@@ -5717,7 +5476,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
                tcp_ecn_rcv_synack(tp, th);
 
                tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
-               tcp_ack(sk, skb, FLAG_SLOWPATH);
+               tcp_ack(sk, skb, 0);
 
                /* Ok.. it's good. Set up sequence numbers and
                 * move to established.
@@ -5953,8 +5712,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)
                return 0;
 
        /* step 5: check the ACK field */
-       acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH |
-                                     FLAG_UPDATE_TS_RECENT |
+
+       acceptable = tcp_ack(sk, skb, FLAG_UPDATE_TS_RECENT |
                                      FLAG_NO_CHALLENGE_ACK) > 0;
 
        if (!acceptable) {
@@ -6022,7 +5781,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)
                tp->lsndtime = tcp_jiffies32;
 
                tcp_initialize_rcv_mss(sk);
-               tcp_fast_path_on(tp);
                break;
 
        case TCP_FIN_WAIT1: {
index a20e7f0..9b51663 100644 (file)
@@ -85,8 +85,6 @@
 #include <crypto/hash.h>
 #include <linux/scatterlist.h>
 
-int sysctl_tcp_low_latency __read_mostly;
-
 #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);
@@ -1458,7 +1456,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
                                sk->sk_rx_dst = NULL;
                        }
                }
-               tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len);
+               tcp_rcv_established(sk, skb, tcp_hdr(skb));
                return 0;
        }
 
@@ -1541,61 +1539,6 @@ void tcp_v4_early_demux(struct sk_buff *skb)
        }
 }
 
-/* Packet is added to VJ-style prequeue for processing in process
- * context, if a reader task is waiting. Apparently, this exciting
- * idea (VJ's mail "Re: query about TCP header on tcp-ip" of 07 Sep 93)
- * failed somewhere. Latency? Burstiness? Well, at least now we will
- * see, why it failed. 8)8)                              --ANK
- *
- */
-bool tcp_prequeue(struct sock *sk, struct sk_buff *skb)
-{
-       struct tcp_sock *tp = tcp_sk(sk);
-
-       if (sysctl_tcp_low_latency || !tp->ucopy.task)
-               return false;
-
-       if (skb->len <= tcp_hdrlen(skb) &&
-           skb_queue_len(&tp->ucopy.prequeue) == 0)
-               return false;
-
-       /* 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_safe(skb);
-
-       __skb_queue_tail(&tp->ucopy.prequeue, skb);
-       tp->ucopy.memory += skb->truesize;
-       if (skb_queue_len(&tp->ucopy.prequeue) >= 32 ||
-           tp->ucopy.memory + atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf) {
-               struct sk_buff *skb1;
-
-               BUG_ON(sock_owned_by_user(sk));
-               __NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPPREQUEUEDROPPED,
-                               skb_queue_len(&tp->ucopy.prequeue));
-
-               while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL)
-                       sk_backlog_rcv(sk, skb1);
-
-               tp->ucopy.memory = 0;
-       } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) {
-               wake_up_interruptible_sync_poll(sk_sleep(sk),
-                                          POLLIN | POLLRDNORM | POLLRDBAND);
-               if (!inet_csk_ack_scheduled(sk))
-                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
-                                                 (3 * tcp_rto_min(sk)) / 4,
-                                                 TCP_RTO_MAX);
-       }
-       return true;
-}
-EXPORT_SYMBOL(tcp_prequeue);
-
 bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
 {
        u32 limit = sk->sk_rcvbuf + sk->sk_sndbuf;
@@ -1770,8 +1713,7 @@ process:
        tcp_segs_in(tcp_sk(sk), skb);
        ret = 0;
        if (!sock_owned_by_user(sk)) {
-               if (!tcp_prequeue(sk, skb))
-                       ret = tcp_v4_do_rcv(sk, skb);
+               ret = tcp_v4_do_rcv(sk, skb);
        } else if (tcp_add_backlog(sk, skb)) {
                goto discard_and_relse;
        }
@@ -1936,9 +1878,6 @@ void tcp_v4_destroy_sock(struct sock *sk)
        }
 #endif
 
-       /* Clean prequeue, it must be empty really */
-       __skb_queue_purge(&tp->ucopy.prequeue);
-
        /* Clean up a referenced TCP bind bucket. */
        if (inet_csk(sk)->icsk_bind_hash)
                inet_put_port(sk);
index 0ff83c1..1537b87 100644 (file)
@@ -436,8 +436,6 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
                struct tcp_sock *newtp = tcp_sk(newsk);
 
                /* Now setup tcp_sock */
-               newtp->pred_flags = 0;
-
                newtp->rcv_wup = newtp->copied_seq =
                newtp->rcv_nxt = treq->rcv_isn + 1;
                newtp->segs_in = 1;
@@ -445,7 +443,6 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
                newtp->snd_sml = newtp->snd_una =
                newtp->snd_nxt = newtp->snd_up = treq->snt_isn + 1;
 
-               tcp_prequeue_init(newtp);
                INIT_LIST_HEAD(&newtp->tsq_node);
 
                tcp_init_wl(newtp, treq->rcv_isn);
index 886d874..d49bff5 100644 (file)
@@ -295,9 +295,7 @@ static u16 tcp_select_window(struct sock *sk)
        /* RFC1323 scaling applied */
        new_win >>= tp->rx_opt.rcv_wscale;
 
-       /* If we advertise zero window, disable fast path. */
        if (new_win == 0) {
-               tp->pred_flags = 0;
                if (old_win)
                        NET_INC_STATS(sock_net(sk),
                                      LINUX_MIB_TCPTOZEROWINDOWADV);
@@ -2202,9 +2200,10 @@ static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb,
 static void tcp_chrono_set(struct tcp_sock *tp, const enum tcp_chrono new)
 {
        const u32 now = tcp_jiffies32;
+       enum tcp_chrono old = tp->chrono_type;
 
-       if (tp->chrono_type > TCP_CHRONO_UNSPEC)
-               tp->chrono_stat[tp->chrono_type - 1] += now - tp->chrono_start;
+       if (old > TCP_CHRONO_UNSPEC)
+               tp->chrono_stat[old - 1] += now - tp->chrono_start;
        tp->chrono_start = now;
        tp->chrono_type = new;
 }
index f6c50af..697f4c6 100644 (file)
@@ -105,8 +105,9 @@ static inline int tcp_probe_avail(void)
  * Note: arguments must match tcp_rcv_established()!
  */
 static void jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
-                                const struct tcphdr *th, unsigned int len)
+                                const struct tcphdr *th)
 {
+       unsigned int len = skb->len;
        const struct tcp_sock *tp = tcp_sk(sk);
        const struct inet_sock *inet = inet_sk(sk);
 
@@ -145,7 +146,7 @@ static void jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                                BUG();
                        }
 
-                       p->length = skb->len;
+                       p->length = len;
                        p->snd_nxt = tp->snd_nxt;
                        p->snd_una = tp->snd_una;
                        p->snd_cwnd = tp->snd_cwnd;
index c0feeee..f753f9d 100644 (file)
@@ -239,7 +239,6 @@ static int tcp_write_timeout(struct sock *sk)
 /* Called with BH disabled */
 void tcp_delack_timer_handler(struct sock *sk)
 {
-       struct tcp_sock *tp = tcp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
 
        sk_mem_reclaim_partial(sk);
@@ -254,17 +253,6 @@ void tcp_delack_timer_handler(struct sock *sk)
        }
        icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER;
 
-       if (!skb_queue_empty(&tp->ucopy.prequeue)) {
-               struct sk_buff *skb;
-
-               __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSCHEDULERFAILED);
-
-               while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL)
-                       sk_backlog_rcv(sk, skb);
-
-               tp->ucopy.memory = 0;
-       }
-
        if (inet_csk_ack_scheduled(sk)) {
                if (!icsk->icsk_ack.pingpong) {
                        /* Delayed ACK missed: inflate ATO. */
index bec9caf..e5de843 100644 (file)
@@ -154,24 +154,6 @@ static inline void update_rtt_min(struct westwood *w)
 }
 
 /*
- * @westwood_fast_bw
- * It is called when we are in fast path. In particular it is called when
- * header prediction is successful. In such case in fact update is
- * straight forward and doesn't need any particular care.
- */
-static inline void westwood_fast_bw(struct sock *sk)
-{
-       const struct tcp_sock *tp = tcp_sk(sk);
-       struct westwood *w = inet_csk_ca(sk);
-
-       westwood_update_window(sk);
-
-       w->bk += tp->snd_una - w->snd_una;
-       w->snd_una = tp->snd_una;
-       update_rtt_min(w);
-}
-
-/*
  * @westwood_acked_count
  * This function evaluates cumul_ack for evaluating bk in case of
  * delayed or partial acks.
@@ -223,17 +205,12 @@ static u32 tcp_westwood_bw_rttmin(const struct sock *sk)
 
 static void tcp_westwood_ack(struct sock *sk, u32 ack_flags)
 {
-       if (ack_flags & CA_ACK_SLOWPATH) {
-               struct westwood *w = inet_csk_ca(sk);
-
-               westwood_update_window(sk);
-               w->bk += westwood_acked_count(sk);
+       struct westwood *w = inet_csk_ca(sk);
 
-               update_rtt_min(w);
-               return;
-       }
+       westwood_update_window(sk);
+       w->bk += westwood_acked_count(sk);
 
-       westwood_fast_bw(sk);
+       update_rtt_min(w);
 }
 
 static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event)
index 25294d4..e6276fa 100644 (file)
@@ -1163,34 +1163,32 @@ out:
        return ret;
 }
 
-#if BITS_PER_LONG == 64
+#define UDP_SKB_IS_STATELESS 0x80000000
+
 static void udp_set_dev_scratch(struct sk_buff *skb)
 {
-       struct udp_dev_scratch *scratch;
+       struct udp_dev_scratch *scratch = udp_skb_scratch(skb);
 
        BUILD_BUG_ON(sizeof(struct udp_dev_scratch) > sizeof(long));
-       scratch = (struct udp_dev_scratch *)&skb->dev_scratch;
-       scratch->truesize = skb->truesize;
+       scratch->_tsize_state = skb->truesize;
+#if BITS_PER_LONG == 64
        scratch->len = skb->len;
        scratch->csum_unnecessary = !!skb_csum_unnecessary(skb);
        scratch->is_linear = !skb_is_nonlinear(skb);
+#endif
+       if (likely(!skb->_skb_refdst))
+               scratch->_tsize_state |= UDP_SKB_IS_STATELESS;
 }
 
 static int udp_skb_truesize(struct sk_buff *skb)
 {
-       return ((struct udp_dev_scratch *)&skb->dev_scratch)->truesize;
-}
-#else
-static void udp_set_dev_scratch(struct sk_buff *skb)
-{
-       skb->dev_scratch = skb->truesize;
+       return udp_skb_scratch(skb)->_tsize_state & ~UDP_SKB_IS_STATELESS;
 }
 
-static int udp_skb_truesize(struct sk_buff *skb)
+static bool udp_skb_has_head_state(struct sk_buff *skb)
 {
-       return skb->dev_scratch;
+       return !(udp_skb_scratch(skb)->_tsize_state & UDP_SKB_IS_STATELESS);
 }
-#endif
 
 /* fully reclaim rmem/fwd memory allocated for skb */
 static void udp_rmem_release(struct sock *sk, int size, int partial,
@@ -1388,6 +1386,11 @@ void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len)
                unlock_sock_fast(sk, slow);
        }
 
+       /* In the more common cases we cleared the head states previously,
+        * see __udp_queue_rcv_skb().
+        */
+       if (unlikely(udp_skb_has_head_state(skb)))
+               skb_release_head_state(skb);
        consume_stateless_skb(skb);
 }
 EXPORT_SYMBOL_GPL(skb_consume_udp);
@@ -1779,8 +1782,12 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                sk_mark_napi_id_once(sk, skb);
        }
 
-       /* clear all pending head states while they are hot in the cache */
-       skb_release_head_state(skb);
+       /* At recvmsg() time we may access skb->dst or skb->sp depending on
+        * the IP options and the cmsg flags, elsewhere can we clear all
+        * pending head states while they are hot in the cache
+        */
+       if (likely(IPCB(skb)->opt.optlen == 0 && !skb_sec_path(skb)))
+               skb_release_head_state(skb);
 
        rc = __udp_enqueue_schedule_skb(sk, skb);
        if (rc < 0) {
@@ -1921,7 +1928,7 @@ drop:
 /* For TCP sockets, sk_rx_dst is protected by socket lock
  * For UDP, we use xchg() to guard against concurrent changes.
  */
-static void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
+void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
 {
        struct dst_entry *old;
 
@@ -1930,6 +1937,7 @@ static void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
                dst_release(old);
        }
 }
+EXPORT_SYMBOL(udp_sk_rx_dst_set);
 
 /*
  *     Multicasts and broadcasts go to each listener.
index 58bd39f..6539ff1 100644 (file)
@@ -82,7 +82,8 @@ void udp_tunnel_push_rx_port(struct net_device *dev, struct socket *sock,
        struct sock *sk = sock->sk;
        struct udp_tunnel_info ti;
 
-       if (!dev->netdev_ops->ndo_udp_tunnel_add)
+       if (!dev->netdev_ops->ndo_udp_tunnel_add ||
+           !(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT))
                return;
 
        ti.type = type;
@@ -93,6 +94,24 @@ void udp_tunnel_push_rx_port(struct net_device *dev, struct socket *sock,
 }
 EXPORT_SYMBOL_GPL(udp_tunnel_push_rx_port);
 
+void udp_tunnel_drop_rx_port(struct net_device *dev, struct socket *sock,
+                            unsigned short type)
+{
+       struct sock *sk = sock->sk;
+       struct udp_tunnel_info ti;
+
+       if (!dev->netdev_ops->ndo_udp_tunnel_del ||
+           !(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT))
+               return;
+
+       ti.type = type;
+       ti.sa_family = sk->sk_family;
+       ti.port = inet_sk(sk)->inet_sport;
+
+       dev->netdev_ops->ndo_udp_tunnel_del(dev, &ti);
+}
+EXPORT_SYMBOL_GPL(udp_tunnel_drop_rx_port);
+
 /* Notify netdevs that UDP port started listening */
 void udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type)
 {
@@ -109,6 +128,8 @@ void udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type)
        for_each_netdev_rcu(net, dev) {
                if (!dev->netdev_ops->ndo_udp_tunnel_add)
                        continue;
+               if (!(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT))
+                       continue;
                dev->netdev_ops->ndo_udp_tunnel_add(dev, &ti);
        }
        rcu_read_unlock();
@@ -131,6 +152,8 @@ void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type)
        for_each_netdev_rcu(net, dev) {
                if (!dev->netdev_ops->ndo_udp_tunnel_del)
                        continue;
+               if (!(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT))
+                       continue;
                dev->netdev_ops->ndo_udp_tunnel_del(dev, &ti);
        }
        rcu_read_unlock();
index a88b5b5..0a7c740 100644 (file)
@@ -210,7 +210,7 @@ lookup_protocol:
        np->mcast_hops  = IPV6_DEFAULT_MCASTHOPS;
        np->mc_loop     = 1;
        np->pmtudisc    = IPV6_PMTUDISC_WANT;
-       np->autoflowlabel = ip6_default_np_autolabel(sock_net(sk));
+       np->autoflowlabel = ip6_default_np_autolabel(net);
        sk->sk_ipv6only = net->ipv6.sysctl.bindv6only;
 
        /* Init the ipv4 part of the socket since we can have sockets
index 4996d73..3cec529 100644 (file)
@@ -756,6 +756,7 @@ static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
        if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
                goto drop;
 
+       IP6CB(skb)->flags |= IP6SKB_JUMBOGRAM;
        return true;
 
 drop:
index c6ec064..43ca864 100644 (file)
@@ -673,8 +673,6 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
                *prevhdr = NEXTHDR_FRAGMENT;
                tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
                if (!tmp_hdr) {
-                       IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
-                                     IPSTATS_MIB_FRAGFAILS);
                        err = -ENOMEM;
                        goto fail;
                }
@@ -789,8 +787,6 @@ slow_path:
                frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) +
                                 hroom + troom, GFP_ATOMIC);
                if (!frag) {
-                       IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
-                                     IPSTATS_MIB_FRAGFAILS);
                        err = -ENOMEM;
                        goto fail;
                }
index e9065b8..abb2c30 100644 (file)
@@ -78,7 +78,7 @@ EXPORT_SYMBOL(ipv6_select_ident);
 
 int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
 {
-       u16 offset = sizeof(struct ipv6hdr);
+       unsigned int offset = sizeof(struct ipv6hdr);
        unsigned int packet_len = skb_tail_pointer(skb) -
                skb_network_header(skb);
        int found_rhdr = 0;
@@ -86,6 +86,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
 
        while (offset <= packet_len) {
                struct ipv6_opt_hdr *exthdr;
+               unsigned int len;
 
                switch (**nexthdr) {
 
@@ -111,7 +112,10 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
 
                exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
                                                 offset);
-               offset += ipv6_optlen(exthdr);
+               len = ipv6_optlen(exthdr);
+               if (len + offset >= IPV6_MAXPLEN)
+                       return -EINVAL;
+               offset += len;
                *nexthdr = &exthdr->nexthdr;
        }
 
index 7b75b06..4e7817a 100644 (file)
@@ -216,6 +216,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
        treq->rcv_isn = ntohl(th->seq) - 1;
        treq->snt_isn = cookie;
        treq->ts_off = 0;
+       treq->txhash = net_tx_rndhash();
 
        /*
         * We need to lookup the dst_entry to get the correct window size.
index 2521690..ced5dcf 100644 (file)
@@ -1296,7 +1296,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                        }
                }
 
-               tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len);
+               tcp_rcv_established(sk, skb, tcp_hdr(skb));
                if (opt_skb)
                        goto ipv6_pktoptions;
                return 0;
@@ -1505,8 +1505,7 @@ process:
        tcp_segs_in(tcp_sk(sk), skb);
        ret = 0;
        if (!sock_owned_by_user(sk)) {
-               if (!tcp_prequeue(sk, skb))
-                       ret = tcp_v6_do_rcv(sk, skb);
+               ret = tcp_v6_do_rcv(sk, skb);
        } else if (tcp_add_backlog(sk, skb)) {
                goto discard_and_relse;
        }
index 4a3e656..578142b 100644 (file)
@@ -291,11 +291,7 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb,
                                          struct udp_table *udptable)
 {
        const struct ipv6hdr *iph = ipv6_hdr(skb);
-       struct sock *sk;
 
-       sk = skb_steal_sock(skb);
-       if (unlikely(sk))
-               return sk;
        return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport,
                                 &iph->daddr, dport, inet6_iif(skb),
                                 udptable, skb);
@@ -332,6 +328,15 @@ struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be
 EXPORT_SYMBOL_GPL(udp6_lib_lookup);
 #endif
 
+/* do not use the scratch area len for jumbogram: their length execeeds the
+ * scratch area space; note that the IP6CB flags is still in the first
+ * cacheline, so checking for jumbograms is cheap
+ */
+static int udp6_skb_len(struct sk_buff *skb)
+{
+       return unlikely(inet6_is_jumbogram(skb)) ? skb->len : udp_skb_len(skb);
+}
+
 /*
  *     This should be easy, if there is something there we
  *     return it, otherwise we block.
@@ -362,7 +367,7 @@ try_again:
        if (!skb)
                return err;
 
-       ulen = udp_skb_len(skb);
+       ulen = udp6_skb_len(skb);
        copied = len;
        if (copied > ulen - off)
                copied = ulen - off;
@@ -804,6 +809,24 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
        if (udp6_csum_init(skb, uh, proto))
                goto csum_error;
 
+       /* Check if the socket is already available, e.g. due to early demux */
+       sk = skb_steal_sock(skb);
+       if (sk) {
+               struct dst_entry *dst = skb_dst(skb);
+               int ret;
+
+               if (unlikely(sk->sk_rx_dst != dst))
+                       udp_sk_rx_dst_set(sk, dst);
+
+               ret = udpv6_queue_rcv_skb(sk, skb);
+               sock_put(sk);
+
+               /* a return value > 0 means to resubmit the input */
+               if (ret > 0)
+                       return ret;
+               return 0;
+       }
+
        /*
         *      Multicast receive code
         */
@@ -812,11 +835,6 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                                saddr, daddr, udptable, proto);
 
        /* Unicast */
-
-       /*
-        * check socket cache ... must talk to Alan about his plans
-        * for sock caches... i'll skip this for now.
-        */
        sk = __udp6_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
        if (sk) {
                int ret;
index c343ac6..c748e8a 100644 (file)
@@ -155,8 +155,8 @@ static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq,
        seq_printf(seq,
                   "   psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ",
                   psock->index,
-                  psock->strp.stats.rx_msgs,
-                  psock->strp.stats.rx_bytes,
+                  psock->strp.stats.msgs,
+                  psock->strp.stats.bytes,
                   psock->stats.tx_msgs,
                   psock->stats.tx_bytes,
                   psock->sk->sk_receive_queue.qlen,
@@ -170,22 +170,22 @@ static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq,
        if (psock->tx_stopped)
                seq_puts(seq, "TxStop ");
 
-       if (psock->strp.rx_stopped)
+       if (psock->strp.stopped)
                seq_puts(seq, "RxStop ");
 
        if (psock->tx_kcm)
                seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index);
 
-       if (!psock->strp.rx_paused && !psock->ready_rx_msg) {
+       if (!psock->strp.paused && !psock->ready_rx_msg) {
                if (psock->sk->sk_receive_queue.qlen) {
-                       if (psock->strp.rx_need_bytes)
+                       if (psock->strp.need_bytes)
                                seq_printf(seq, "RxWait=%u ",
-                                          psock->strp.rx_need_bytes);
+                                          psock->strp.need_bytes);
                        else
                                seq_printf(seq, "RxWait ");
                }
        } else  {
-               if (psock->strp.rx_paused)
+               if (psock->strp.paused)
                        seq_puts(seq, "RxPause ");
 
                if (psock->ready_rx_msg)
@@ -371,20 +371,20 @@ static int kcm_stats_seq_show(struct seq_file *seq, void *v)
        seq_printf(seq,
                   "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n",
                   "",
-                  strp_stats.rx_msgs,
-                  strp_stats.rx_bytes,
+                  strp_stats.msgs,
+                  strp_stats.bytes,
                   psock_stats.tx_msgs,
                   psock_stats.tx_bytes,
                   psock_stats.reserved,
                   psock_stats.unreserved,
-                  strp_stats.rx_aborts,
-                  strp_stats.rx_interrupted,
-                  strp_stats.rx_unrecov_intr,
-                  strp_stats.rx_mem_fail,
-                  strp_stats.rx_need_more_hdr,
-                  strp_stats.rx_bad_hdr_len,
-                  strp_stats.rx_msg_too_big,
-                  strp_stats.rx_msg_timeouts,
+                  strp_stats.aborts,
+                  strp_stats.interrupted,
+                  strp_stats.unrecov_intr,
+                  strp_stats.mem_fail,
+                  strp_stats.need_more_hdr,
+                  strp_stats.bad_hdr_len,
+                  strp_stats.msg_too_big,
+                  strp_stats.msg_timeouts,
                   psock_stats.tx_aborts);
 
        return 0;
index da49191..88ce732 100644 (file)
@@ -96,12 +96,12 @@ static void kcm_update_rx_mux_stats(struct kcm_mux *mux,
                                    struct kcm_psock *psock)
 {
        STRP_STATS_ADD(mux->stats.rx_bytes,
-                      psock->strp.stats.rx_bytes -
+                      psock->strp.stats.bytes -
                       psock->saved_rx_bytes);
        mux->stats.rx_msgs +=
-               psock->strp.stats.rx_msgs - psock->saved_rx_msgs;
-       psock->saved_rx_msgs = psock->strp.stats.rx_msgs;
-       psock->saved_rx_bytes = psock->strp.stats.rx_bytes;
+               psock->strp.stats.msgs - psock->saved_rx_msgs;
+       psock->saved_rx_msgs = psock->strp.stats.msgs;
+       psock->saved_rx_bytes = psock->strp.stats.bytes;
 }
 
 static void kcm_update_tx_mux_stats(struct kcm_mux *mux,
@@ -1118,7 +1118,7 @@ static int kcm_recvmsg(struct socket *sock, struct msghdr *msg,
        struct kcm_sock *kcm = kcm_sk(sk);
        int err = 0;
        long timeo;
-       struct strp_rx_msg *rxm;
+       struct strp_msg *stm;
        int copied = 0;
        struct sk_buff *skb;
 
@@ -1132,26 +1132,26 @@ static int kcm_recvmsg(struct socket *sock, struct msghdr *msg,
 
        /* Okay, have a message on the receive queue */
 
-       rxm = strp_rx_msg(skb);
+       stm = strp_msg(skb);
 
-       if (len > rxm->full_len)
-               len = rxm->full_len;
+       if (len > stm->full_len)
+               len = stm->full_len;
 
-       err = skb_copy_datagram_msg(skb, rxm->offset, msg, len);
+       err = skb_copy_datagram_msg(skb, stm->offset, msg, len);
        if (err < 0)
                goto out;
 
        copied = len;
        if (likely(!(flags & MSG_PEEK))) {
                KCM_STATS_ADD(kcm->stats.rx_bytes, copied);
-               if (copied < rxm->full_len) {
+               if (copied < stm->full_len) {
                        if (sock->type == SOCK_DGRAM) {
                                /* Truncated message */
                                msg->msg_flags |= MSG_TRUNC;
                                goto msg_finished;
                        }
-                       rxm->offset += copied;
-                       rxm->full_len -= copied;
+                       stm->offset += copied;
+                       stm->full_len -= copied;
                } else {
 msg_finished:
                        /* Finished with message */
@@ -1175,7 +1175,7 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
        struct sock *sk = sock->sk;
        struct kcm_sock *kcm = kcm_sk(sk);
        long timeo;
-       struct strp_rx_msg *rxm;
+       struct strp_msg *stm;
        int err = 0;
        ssize_t copied;
        struct sk_buff *skb;
@@ -1192,12 +1192,12 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
 
        /* Okay, have a message on the receive queue */
 
-       rxm = strp_rx_msg(skb);
+       stm = strp_msg(skb);
 
-       if (len > rxm->full_len)
-               len = rxm->full_len;
+       if (len > stm->full_len)
+               len = stm->full_len;
 
-       copied = skb_splice_bits(skb, sk, rxm->offset, pipe, len, flags);
+       copied = skb_splice_bits(skb, sk, stm->offset, pipe, len, flags);
        if (copied < 0) {
                err = copied;
                goto err_out;
@@ -1205,8 +1205,8 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
 
        KCM_STATS_ADD(kcm->stats.rx_bytes, copied);
 
-       rxm->offset += copied;
-       rxm->full_len -= copied;
+       stm->offset += copied;
+       stm->full_len -= copied;
 
        /* We have no way to return MSG_EOR. If all the bytes have been
         * read we still leave the message in the receive socket buffer.
index 552d606..974cf2a 100644 (file)
@@ -227,114 +227,6 @@ void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg,
 }
 EXPORT_SYMBOL(nf_unregister_net_hooks);
 
-static LIST_HEAD(nf_hook_list);
-
-static int _nf_register_hook(struct nf_hook_ops *reg)
-{
-       struct net *net, *last;
-       int ret;
-
-       for_each_net(net) {
-               ret = nf_register_net_hook(net, reg);
-               if (ret && ret != -ENOENT)
-                       goto rollback;
-       }
-       list_add_tail(&reg->list, &nf_hook_list);
-
-       return 0;
-rollback:
-       last = net;
-       for_each_net(net) {
-               if (net == last)
-                       break;
-               nf_unregister_net_hook(net, reg);
-       }
-       return ret;
-}
-
-int nf_register_hook(struct nf_hook_ops *reg)
-{
-       int ret;
-
-       rtnl_lock();
-       ret = _nf_register_hook(reg);
-       rtnl_unlock();
-
-       return ret;
-}
-EXPORT_SYMBOL(nf_register_hook);
-
-static void _nf_unregister_hook(struct nf_hook_ops *reg)
-{
-       struct net *net;
-
-       list_del(&reg->list);
-       for_each_net(net)
-               nf_unregister_net_hook(net, reg);
-}
-
-void nf_unregister_hook(struct nf_hook_ops *reg)
-{
-       rtnl_lock();
-       _nf_unregister_hook(reg);
-       rtnl_unlock();
-}
-EXPORT_SYMBOL(nf_unregister_hook);
-
-int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n)
-{
-       unsigned int i;
-       int err = 0;
-
-       for (i = 0; i < n; i++) {
-               err = nf_register_hook(&reg[i]);
-               if (err)
-                       goto err;
-       }
-       return err;
-
-err:
-       if (i > 0)
-               nf_unregister_hooks(reg, i);
-       return err;
-}
-EXPORT_SYMBOL(nf_register_hooks);
-
-/* Caller MUST take rtnl_lock() */
-int _nf_register_hooks(struct nf_hook_ops *reg, unsigned int n)
-{
-       unsigned int i;
-       int err = 0;
-
-       for (i = 0; i < n; i++) {
-               err = _nf_register_hook(&reg[i]);
-               if (err)
-                       goto err;
-       }
-       return err;
-
-err:
-       if (i > 0)
-               _nf_unregister_hooks(reg, i);
-       return err;
-}
-EXPORT_SYMBOL(_nf_register_hooks);
-
-void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n)
-{
-       while (n-- > 0)
-               nf_unregister_hook(&reg[n]);
-}
-EXPORT_SYMBOL(nf_unregister_hooks);
-
-/* Caller MUST take rtnl_lock */
-void _nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n)
-{
-       while (n-- > 0)
-               _nf_unregister_hook(&reg[n]);
-}
-EXPORT_SYMBOL(_nf_unregister_hooks);
-
 /* Returns 1 if okfn() needs to be executed by the caller,
  * -EPERM for NF_DROP, 0 otherwise.  Caller must hold rcu_read_lock. */
 int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
@@ -450,40 +342,9 @@ void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *);
 EXPORT_SYMBOL(nf_nat_decode_session_hook);
 #endif
 
-static int nf_register_hook_list(struct net *net)
-{
-       struct nf_hook_ops *elem;
-       int ret;
-
-       rtnl_lock();
-       list_for_each_entry(elem, &nf_hook_list, list) {
-               ret = nf_register_net_hook(net, elem);
-               if (ret && ret != -ENOENT)
-                       goto out_undo;
-       }
-       rtnl_unlock();
-       return 0;
-
-out_undo:
-       list_for_each_entry_continue_reverse(elem, &nf_hook_list, list)
-               nf_unregister_net_hook(net, elem);
-       rtnl_unlock();
-       return ret;
-}
-
-static void nf_unregister_hook_list(struct net *net)
-{
-       struct nf_hook_ops *elem;
-
-       rtnl_lock();
-       list_for_each_entry(elem, &nf_hook_list, list)
-               nf_unregister_net_hook(net, elem);
-       rtnl_unlock();
-}
-
 static int __net_init netfilter_net_init(struct net *net)
 {
-       int i, h, ret;
+       int i, h;
 
        for (i = 0; i < ARRAY_SIZE(net->nf.hooks); i++) {
                for (h = 0; h < NF_MAX_HOOKS; h++)
@@ -500,16 +361,12 @@ static int __net_init netfilter_net_init(struct net *net)
                return -ENOMEM;
        }
 #endif
-       ret = nf_register_hook_list(net);
-       if (ret)
-               remove_proc_entry("netfilter", net->proc_net);
 
-       return ret;
+       return 0;
 }
 
 static void __net_exit netfilter_net_exit(struct net *net)
 {
-       nf_unregister_hook_list(net);
        remove_proc_entry("netfilter", net->proc_net);
 }
 
index e03d16e..899c2c3 100644 (file)
@@ -422,7 +422,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
        h = nf_ct_expect_dst_hash(net, &expect->tuple);
        hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) {
                if (expect_matches(i, expect)) {
-                       if (nf_ct_remove_expect(expect))
+                       if (nf_ct_remove_expect(i))
                                break;
                } else if (expect_clash(i, expect)) {
                        ret = -EBUSY;
index 832c5a0..eb54178 100644 (file)
@@ -222,20 +222,21 @@ find_appropriate_src(struct net *net,
                .tuple = tuple,
                .zone = zone
        };
-       struct rhlist_head *hl;
+       struct rhlist_head *hl, *h;
 
        hl = rhltable_lookup(&nf_nat_bysource_table, &key,
                             nf_nat_bysource_params);
-       if (!hl)
-               return 0;
 
-       ct = container_of(hl, typeof(*ct), nat_bysource);
+       rhl_for_each_entry_rcu(ct, h, hl, nat_bysource) {
+               nf_ct_invert_tuplepr(result,
+                                    &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+               result->dst = tuple->dst;
 
-       nf_ct_invert_tuplepr(result,
-                            &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
-       result->dst = tuple->dst;
+               if (in_range(l3proto, l4proto, result, range))
+                       return 1;
+       }
 
-       return in_range(l3proto, l4proto, result, range);
+       return 0;
 }
 
 /* For [FUTURE] fragmentation handling, we want the least-used
index 92b05e1..733d3e4 100644 (file)
@@ -472,8 +472,7 @@ static void nfnetlink_rcv_skb_batch(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (msglen > skb->len)
                msglen = skb->len;
 
-       if (nlh->nlmsg_len < NLMSG_HDRLEN ||
-           skb->len < NLMSG_HDRLEN + sizeof(struct nfgenmsg))
+       if (skb->len < NLMSG_HDRLEN + sizeof(struct nfgenmsg))
                return;
 
        err = nla_parse(cda, NFNL_BATCH_MAX, attr, attrlen, nfnl_batch_policy,
@@ -500,7 +499,8 @@ static void nfnetlink_rcv(struct sk_buff *skb)
 {
        struct nlmsghdr *nlh = nlmsg_hdr(skb);
 
-       if (nlh->nlmsg_len < NLMSG_HDRLEN ||
+       if (skb->len < NLMSG_HDRLEN ||
+           nlh->nlmsg_len < NLMSG_HDRLEN ||
            skb->len < nlh->nlmsg_len)
                return;
 
index 1770c1d..e164823 100644 (file)
@@ -1003,14 +1003,10 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size)
        if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages)
                return NULL;
 
-       if (sz <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
-               info = kmalloc(sz, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
-       if (!info) {
-               info = __vmalloc(sz, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY,
-                                PAGE_KERNEL);
-               if (!info)
-                       return NULL;
-       }
+       info = kvmalloc(sz, GFP_KERNEL);
+       if (!info)
+               return NULL;
+
        memset(info, 0, sizeof(*info));
        info->size = size;
        return info;
index 3f6c4fa..245fa35 100644 (file)
@@ -106,7 +106,7 @@ static DEFINE_SPINLOCK(recent_lock);
 static DEFINE_MUTEX(recent_mutex);
 
 #ifdef CONFIG_PROC_FS
-static const struct file_operations recent_old_fops, recent_mt_fops;
+static const struct file_operations recent_mt_fops;
 #endif
 
 static u_int32_t hash_rnd __read_mostly;
index 08679eb..03859e3 100644 (file)
@@ -629,6 +629,34 @@ ovs_ct_find_existing(struct net *net, const struct nf_conntrack_zone *zone,
        return ct;
 }
 
+static
+struct nf_conn *ovs_ct_executed(struct net *net,
+                               const struct sw_flow_key *key,
+                               const struct ovs_conntrack_info *info,
+                               struct sk_buff *skb,
+                               bool *ct_executed)
+{
+       struct nf_conn *ct = NULL;
+
+       /* If no ct, check if we have evidence that an existing conntrack entry
+        * might be found for this skb.  This happens when we lose a skb->_nfct
+        * due to an upcall, or if the direction is being forced.  If the
+        * connection was not confirmed, it is not cached and needs to be run
+        * through conntrack again.
+        */
+       *ct_executed = (key->ct_state & OVS_CS_F_TRACKED) &&
+                      !(key->ct_state & OVS_CS_F_INVALID) &&
+                      (key->ct_zone == info->zone.id);
+
+       if (*ct_executed || (!key->ct_state && info->force)) {
+               ct = ovs_ct_find_existing(net, &info->zone, info->family, skb,
+                                         !!(key->ct_state &
+                                         OVS_CS_F_NAT_MASK));
+       }
+
+       return ct;
+}
+
 /* Determine whether skb->_nfct is equal to the result of conntrack lookup. */
 static bool skb_nfct_cached(struct net *net,
                            const struct sw_flow_key *key,
@@ -637,24 +665,17 @@ static bool skb_nfct_cached(struct net *net,
 {
        enum ip_conntrack_info ctinfo;
        struct nf_conn *ct;
+       bool ct_executed = true;
 
        ct = nf_ct_get(skb, &ctinfo);
-       /* If no ct, check if we have evidence that an existing conntrack entry
-        * might be found for this skb.  This happens when we lose a skb->_nfct
-        * due to an upcall.  If the connection was not confirmed, it is not
-        * cached and needs to be run through conntrack again.
-        */
-       if (!ct && key->ct_state & OVS_CS_F_TRACKED &&
-           !(key->ct_state & OVS_CS_F_INVALID) &&
-           key->ct_zone == info->zone.id) {
-               ct = ovs_ct_find_existing(net, &info->zone, info->family, skb,
-                                         !!(key->ct_state
-                                            & OVS_CS_F_NAT_MASK));
-               if (ct)
-                       nf_ct_get(skb, &ctinfo);
-       }
        if (!ct)
+               ct = ovs_ct_executed(net, key, info, skb, &ct_executed);
+
+       if (ct)
+               nf_ct_get(skb, &ctinfo);
+       else
                return false;
+
        if (!net_eq(net, read_pnet(&ct->ct_net)))
                return false;
        if (!nf_ct_zone_equal_any(info->ct, nf_ct_zone(ct)))
@@ -679,7 +700,7 @@ static bool skb_nfct_cached(struct net *net,
                return false;
        }
 
-       return true;
+       return ct_executed;
 }
 
 #ifdef CONFIG_NF_NAT_NEEDED
@@ -1289,8 +1310,8 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
 
        nla_for_each_nested(a, attr, rem) {
                int type = nla_type(a);
-               int maxlen = ovs_ct_attr_lens[type].maxlen;
-               int minlen = ovs_ct_attr_lens[type].minlen;
+               int maxlen;
+               int minlen;
 
                if (type > OVS_CT_ATTR_MAX) {
                        OVS_NLERR(log,
@@ -1298,6 +1319,9 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
                                  type, OVS_CT_ATTR_MAX);
                        return -EINVAL;
                }
+
+               maxlen = ovs_ct_attr_lens[type].maxlen;
+               minlen = ovs_ct_attr_lens[type].minlen;
                if (nla_len(a) < minlen || nla_len(a) > maxlen) {
                        OVS_NLERR(log,
                                  "Conntrack attr type has unexpected length (type=%d, length=%d, expected=%d)",
index ee035cb..5a17804 100644 (file)
@@ -212,6 +212,7 @@ static void prb_clear_rxhash(struct tpacket_kbdq_core *,
 static void prb_fill_vlan_info(struct tpacket_kbdq_core *,
                struct tpacket3_hdr *);
 static void packet_flush_mclist(struct sock *sk);
+static void packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb);
 
 struct packet_skb_cb {
        union {
@@ -258,6 +259,7 @@ static int packet_direct_xmit(struct sk_buff *skb)
        if (skb != orig_skb)
                goto drop;
 
+       packet_pick_tx_queue(dev, skb);
        txq = skb_get_tx_queue(dev, skb);
 
        local_bh_disable();
@@ -2745,8 +2747,6 @@ tpacket_error:
                        goto tpacket_error;
                }
 
-               packet_pick_tx_queue(dev, skb);
-
                skb->destructor = tpacket_destruct_skb;
                __packet_set_status(po, ph, TP_STATUS_SENDING);
                packet_inc_pending(&po->tx_ring);
@@ -2929,8 +2929,6 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
        skb->priority = sk->sk_priority;
        skb->mark = sockc.mark;
 
-       packet_pick_tx_queue(dev, skb);
-
        if (po->has_vnet_hdr) {
                err = virtio_net_hdr_to_skb(skb, &vnet_hdr, vio_le());
                if (err)
@@ -4329,7 +4327,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                register_prot_hook(sk);
        }
        spin_unlock(&po->bind_lock);
-       if (closing && (po->tp_version > TPACKET_V2)) {
+       if (pg_vec && (po->tp_version > TPACKET_V2)) {
                /* Because we don't support block-based V3 on tx-ring */
                if (!tx_ring)
                        prb_shutdown_retire_blk_timer(po, rb_queue);
index e81aa17..41b9f0f 100644 (file)
@@ -170,8 +170,8 @@ restart:
         * The acquire_in_xmit() check above ensures that only one
         * caller can increment c_send_gen at any time.
         */
-       cp->cp_send_gen++;
-       send_gen = cp->cp_send_gen;
+       send_gen = READ_ONCE(cp->cp_send_gen) + 1;
+       WRITE_ONCE(cp->cp_send_gen, send_gen);
 
        /*
         * rds_conn_shutdown() sets the conn state and then tests RDS_IN_XMIT,
@@ -431,7 +431,7 @@ over_batch:
                smp_mb();
                if ((test_bit(0, &conn->c_map_queued) ||
                     !list_empty(&cp->cp_send_queue)) &&
-                   send_gen == cp->cp_send_gen) {
+                       send_gen == READ_ONCE(cp->cp_send_gen)) {
                        rds_stats_inc(s_send_lock_queue_raced);
                        if (batch_count < send_batch_count)
                                goto restart;
index 69b9733..8c0db9b 100644 (file)
@@ -15,7 +15,7 @@
 #include <net/netns/generic.h>
 #include <net/sock.h>
 #include <net/af_rxrpc.h>
-#include <rxrpc/packet.h>
+#include "protocol.h"
 
 #if 0
 #define CHECK_SLAB_OKAY(X)                                  \
similarity index 78%
rename from include/rxrpc/packet.h
rename to net/rxrpc/protocol.h
index a2dcfb8..4bddcf3 100644 (file)
@@ -187,49 +187,4 @@ struct rxkad_response {
        __be32          ticket_len;     /* Kerberos ticket length  */
 } __packed;
 
-/*****************************************************************************/
-/*
- * RxRPC-level abort codes
- */
-#define RX_CALL_DEAD           -1      /* call/conn has been inactive and is shut down */
-#define RX_INVALID_OPERATION   -2      /* invalid operation requested / attempted */
-#define RX_CALL_TIMEOUT                -3      /* call timeout exceeded */
-#define RX_EOF                 -4      /* unexpected end of data on read op */
-#define RX_PROTOCOL_ERROR      -5      /* low-level protocol error */
-#define RX_USER_ABORT          -6      /* generic user abort */
-#define RX_ADDRINUSE           -7      /* UDP port in use */
-#define RX_DEBUGI_BADTYPE      -8      /* bad debugging packet type */
-
-/*
- * (un)marshalling abort codes (rxgen)
- */
-#define        RXGEN_CC_MARSHAL    -450
-#define        RXGEN_CC_UNMARSHAL  -451
-#define        RXGEN_SS_MARSHAL    -452
-#define        RXGEN_SS_UNMARSHAL  -453
-#define        RXGEN_DECODE        -454
-#define        RXGEN_OPCODE        -455
-#define        RXGEN_SS_XDRFREE    -456
-#define        RXGEN_CC_XDRFREE    -457
-
-/*
- * Rx kerberos security abort codes
- * - unfortunately we have no generalised security abort codes to say things
- *   like "unsupported security", so we have to use these instead and hope the
- *   other side understands
- */
-#define RXKADINCONSISTENCY     19270400        /* security module structure inconsistent */
-#define RXKADPACKETSHORT       19270401        /* packet too short for security challenge */
-#define RXKADLEVELFAIL         19270402        /* security level negotiation failed */
-#define RXKADTICKETLEN         19270403        /* ticket length too short or too long */
-#define RXKADOUTOFSEQUENCE     19270404        /* packet had bad sequence number */
-#define RXKADNOAUTH            19270405        /* caller not authorised */
-#define RXKADBADKEY            19270406        /* illegal key: bad parity or weak */
-#define RXKADBADTICKET         19270407        /* security object was passed a bad ticket */
-#define RXKADUNKNOWNKEY                19270408        /* ticket contained unknown key version number */
-#define RXKADEXPIRED           19270409        /* authentication expired */
-#define RXKADSEALEDINCON       19270410        /* sealed data inconsistent */
-#define RXKADDATALEN           19270411        /* user data too long */
-#define RXKADILLEGALLEVEL      19270412        /* caller not authorised to use encrypted conns */
-
 #endif /* _LINUX_RXRPC_PACKET_H */
index aed6cf2..f19b118 100644 (file)
@@ -110,6 +110,8 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
                           struct netlink_callback *cb)
 {
        int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
+       u32 act_flags = cb->args[2];
+       unsigned long jiffy_since = cb->args[3];
        struct nlattr *nest;
 
        spin_lock_bh(&hinfo->lock);
@@ -127,6 +129,11 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
                        if (index < s_i)
                                continue;
 
+                       if (jiffy_since &&
+                           time_after(jiffy_since,
+                                      (unsigned long)p->tcfa_tm.lastuse))
+                               continue;
+
                        nest = nla_nest_start(skb, n_i);
                        if (nest == NULL)
                                goto nla_put_failure;
@@ -138,14 +145,20 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
                        }
                        nla_nest_end(skb, nest);
                        n_i++;
-                       if (n_i >= TCA_ACT_MAX_PRIO)
+                       if (!(act_flags & TCA_FLAG_LARGE_DUMP_ON) &&
+                           n_i >= TCA_ACT_MAX_PRIO)
                                goto done;
                }
        }
 done:
+       if (index >= 0)
+               cb->args[0] = index + 1;
+
        spin_unlock_bh(&hinfo->lock);
-       if (n_i)
-               cb->args[0] += n_i;
+       if (n_i) {
+               if (act_flags & TCA_FLAG_LARGE_DUMP_ON)
+                       cb->args[1] = n_i;
+       }
        return n_i;
 
 nla_put_failure:
@@ -835,7 +848,7 @@ out_nlmsg_trim:
 }
 
 static int
-act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
+tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
               struct list_head *actions, int event)
 {
        struct sk_buff *skb;
@@ -1018,7 +1031,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
        }
 
        if (event == RTM_GETACTION)
-               ret = act_get_notify(net, portid, n, &actions, event);
+               ret = tcf_get_notify(net, portid, n, &actions, event);
        else { /* delete */
                ret = tcf_del_notify(net, n, &actions, portid);
                if (ret)
@@ -1068,11 +1081,18 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,
        return tcf_add_notify(net, n, &actions, portid);
 }
 
+static u32 tcaa_root_flags_allowed = TCA_FLAG_LARGE_DUMP_ON;
+static const struct nla_policy tcaa_policy[TCA_ROOT_MAX + 1] = {
+       [TCA_ROOT_FLAGS] = { .type = NLA_BITFIELD32,
+                            .validation_data = &tcaa_root_flags_allowed },
+       [TCA_ROOT_TIME_DELTA]      = { .type = NLA_U32 },
+};
+
 static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
                         struct netlink_ext_ack *extack)
 {
        struct net *net = sock_net(skb->sk);
-       struct nlattr *tca[TCA_ACT_MAX + 1];
+       struct nlattr *tca[TCA_ROOT_MAX + 1];
        u32 portid = skb ? NETLINK_CB(skb).portid : 0;
        int ret = 0, ovr = 0;
 
@@ -1080,7 +1100,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
            !netlink_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
-       ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL,
+       ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ROOT_MAX, NULL,
                          extack);
        if (ret < 0)
                return ret;
@@ -1121,16 +1141,12 @@ replay:
        return ret;
 }
 
-static struct nlattr *find_dump_kind(const struct nlmsghdr *n)
+static struct nlattr *find_dump_kind(struct nlattr **nla)
 {
        struct nlattr *tb1, *tb2[TCA_ACT_MAX + 1];
        struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
-       struct nlattr *nla[TCAA_MAX + 1];
        struct nlattr *kind;
 
-       if (nlmsg_parse(n, sizeof(struct tcamsg), nla, TCAA_MAX,
-                       NULL, NULL) < 0)
-               return NULL;
        tb1 = nla[TCA_ACT_TAB];
        if (tb1 == NULL)
                return NULL;
@@ -1157,8 +1173,20 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
        struct tc_action_ops *a_o;
        int ret = 0;
        struct tcamsg *t = (struct tcamsg *) nlmsg_data(cb->nlh);
-       struct nlattr *kind = find_dump_kind(cb->nlh);
+       struct nlattr *tb[TCA_ROOT_MAX + 1];
+       struct nlattr *count_attr = NULL;
+       unsigned long jiffy_since = 0;
+       struct nlattr *kind = NULL;
+       struct nla_bitfield32 bf;
+       u32 msecs_since = 0;
+       u32 act_count = 0;
+
+       ret = nlmsg_parse(cb->nlh, sizeof(struct tcamsg), tb, TCA_ROOT_MAX,
+                         tcaa_policy, NULL);
+       if (ret < 0)
+               return ret;
 
+       kind = find_dump_kind(tb);
        if (kind == NULL) {
                pr_info("tc_dump_action: action bad kind\n");
                return 0;
@@ -1168,14 +1196,32 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
        if (a_o == NULL)
                return 0;
 
+       cb->args[2] = 0;
+       if (tb[TCA_ROOT_FLAGS]) {
+               bf = nla_get_bitfield32(tb[TCA_ROOT_FLAGS]);
+               cb->args[2] = bf.value;
+       }
+
+       if (tb[TCA_ROOT_TIME_DELTA]) {
+               msecs_since = nla_get_u32(tb[TCA_ROOT_TIME_DELTA]);
+       }
+
        nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
                        cb->nlh->nlmsg_type, sizeof(*t), 0);
        if (!nlh)
                goto out_module_put;
+
+       if (msecs_since)
+               jiffy_since = jiffies - msecs_to_jiffies(msecs_since);
+
        t = nlmsg_data(nlh);
        t->tca_family = AF_UNSPEC;
        t->tca__pad1 = 0;
        t->tca__pad2 = 0;
+       cb->args[3] = jiffy_since;
+       count_attr = nla_reserve(skb, TCA_ROOT_COUNT, sizeof(u32));
+       if (!count_attr)
+               goto out_module_put;
 
        nest = nla_nest_start(skb, TCA_ACT_TAB);
        if (nest == NULL)
@@ -1188,6 +1234,9 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
        if (ret > 0) {
                nla_nest_end(skb, nest);
                ret = skb->len;
+               act_count = cb->args[1];
+               memcpy(nla_data(count_attr), &act_count, sizeof(u32));
+               cb->args[1] = 0;
        } else
                nlmsg_trim(skb, b);
 
index 147fde7..263d16e 100644 (file)
@@ -648,7 +648,7 @@ static int fq_resize(struct Qdisc *sch, u32 log)
                return 0;
 
        /* If XPS was setup, we can allocate memory on right NUMA node */
-       array = kvmalloc_node(sizeof(struct rb_root) << log, GFP_KERNEL | __GFP_REPEAT,
+       array = kvmalloc_node(sizeof(struct rb_root) << log, GFP_KERNEL | __GFP_RETRY_MAYFAIL,
                              netdev_queue_numa_node_read(sch->dev_queue));
        if (!array)
                return -ENOMEM;
index 1323d41..681b181 100644 (file)
@@ -221,7 +221,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
            asoc->outqueue.out_qlen == 0 &&
            list_empty(&asoc->outqueue.retransmit) &&
            msg_len > max_data)
-               first_len -= SCTP_PAD4(sizeof(sctp_sack_chunk_t));
+               first_len -= SCTP_PAD4(sizeof(struct sctp_sack_chunk));
 
        /* Encourage Cookie-ECHO bundling. */
        if (asoc->state < SCTP_STATE_COOKIE_ECHOED)
index e876270..d2a8adf 100644 (file)
@@ -1197,7 +1197,7 @@ sctp_flush_out:
 static void sctp_sack_update_unack_data(struct sctp_association *assoc,
                                        struct sctp_sackhdr *sack)
 {
-       sctp_sack_variable_t *frags;
+       union sctp_sack_variable *frags;
        __u16 unack_data;
        int i;
 
@@ -1224,7 +1224,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk)
        struct sctp_transport *transport;
        struct sctp_chunk *tchunk = NULL;
        struct list_head *lchunk, *transport_list, *temp;
-       sctp_sack_variable_t *frags = sack->variable;
+       union sctp_sack_variable *frags = sack->variable;
        __u32 sack_ctsn, ctsn, tsn;
        __u32 highest_tsn, highest_new_tsn;
        __u32 sack_a_rwnd;
@@ -1736,10 +1736,10 @@ static void sctp_mark_missing(struct sctp_outq *q,
 /* Is the given TSN acked by this packet?  */
 static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn)
 {
-       int i;
-       sctp_sack_variable_t *frags;
-       __u16 tsn_offset, blocks;
        __u32 ctsn = ntohl(sack->cum_tsn_ack);
+       union sctp_sack_variable *frags;
+       __u16 tsn_offset, blocks;
+       int i;
 
        if (TSN_lte(tsn, ctsn))
                goto pass;
index 06dc351..163004e 100644 (file)
@@ -69,7 +69,8 @@ static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
 static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
                                           __u8 type, __u8 flags, int paylen,
                                           gfp_t gfp);
-static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
+static struct sctp_cookie_param *sctp_pack_cookie(
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const struct sctp_chunk *init_chunk,
                                        int *cookie_len,
@@ -228,7 +229,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
        struct sctp_adaptation_ind_param aiparam;
        struct sctp_supported_ext_param ext_param;
        int num_ext = 0;
-       __u8 extensions[3];
+       __u8 extensions[4];
        struct sctp_paramhdr *auth_chunks = NULL,
                        *auth_hmacs = NULL;
 
@@ -387,13 +388,13 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        union sctp_params addrs;
        struct sctp_sock *sp;
        int addrs_len;
-       sctp_cookie_param_t *cookie;
+       struct sctp_cookie_param *cookie;
        int cookie_len;
        size_t chunksize;
        struct sctp_adaptation_ind_param aiparam;
        struct sctp_supported_ext_param ext_param;
        int num_ext = 0;
-       __u8 extensions[3];
+       __u8 extensions[4];
        struct sctp_paramhdr *auth_chunks = NULL,
                        *auth_hmacs = NULL,
                        *auth_random = NULL;
@@ -1595,14 +1596,15 @@ nodata:
 /* Build a cookie representing asoc.
  * This INCLUDES the param header needed to put the cookie in the INIT ACK.
  */
-static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
-                                     const struct sctp_association *asoc,
-                                     const struct sctp_chunk *init_chunk,
-                                     int *cookie_len,
-                                     const __u8 *raw_addrs, int addrs_len)
+static struct sctp_cookie_param *sctp_pack_cookie(
+                                       const struct sctp_endpoint *ep,
+                                       const struct sctp_association *asoc,
+                                       const struct sctp_chunk *init_chunk,
+                                       int *cookie_len,
+                                       const __u8 *raw_addrs, int addrs_len)
 {
-       sctp_cookie_param_t *retval;
        struct sctp_signed_cookie *cookie;
+       struct sctp_cookie_param *retval;
        int headersize, bodysize;
 
        /* Header size is static data prior to the actual cookie, including
index ae4c48c..dc0c2c4 100644 (file)
@@ -306,12 +306,10 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net,
                                        void *arg,
                                        sctp_cmd_seq_t *commands)
 {
-       struct sctp_chunk *chunk = arg;
-       struct sctp_chunk *repl;
+       struct sctp_chunk *chunk = arg, *repl, *err_chunk;
+       struct sctp_unrecognized_param *unk_param;
        struct sctp_association *new_asoc;
-       struct sctp_chunk *err_chunk;
        struct sctp_packet *packet;
-       sctp_unrecognized_param_t *unk_param;
        int len;
 
        /* 6.10 Bundling
@@ -435,7 +433,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net,
                 * construct the parameters in INIT ACK by copying the
                 * ERROR causes over.
                 */
-               unk_param = (sctp_unrecognized_param_t *)
+               unk_param = (struct sctp_unrecognized_param *)
                            ((__u8 *)(err_chunk->chunk_hdr) +
                            sizeof(struct sctp_chunkhdr));
                /* Replace the cause code with the "Unrecognized parameter"
@@ -518,7 +516,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net,
                return sctp_sf_violation_chunk(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the INIT-ACK chunk has a valid length */
-       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_initack_chunk_t)))
+       if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_initack_chunk)))
                return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
        /* Grab the INIT header.  */
@@ -1090,7 +1088,8 @@ sctp_disposition_t sctp_sf_beat_8_3(struct net *net,
                return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the HEARTBEAT chunk has a valid length. */
-       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t)))
+       if (!sctp_chunk_length_valid(chunk,
+                                    sizeof(struct sctp_heartbeat_chunk)))
                return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
@@ -1098,7 +1097,7 @@ sctp_disposition_t sctp_sf_beat_8_3(struct net *net,
         * respond with a HEARTBEAT ACK that contains the Heartbeat
         * Information field copied from the received HEARTBEAT chunk.
         */
-       chunk->subh.hb_hdr = (sctp_heartbeathdr_t *)chunk->skb->data;
+       chunk->subh.hb_hdr = (struct sctp_heartbeathdr *)chunk->skb->data;
        param_hdr = (struct sctp_paramhdr *)chunk->subh.hb_hdr;
        paylen = ntohs(chunk->chunk_hdr->length) - sizeof(struct sctp_chunkhdr);
 
@@ -1419,13 +1418,11 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
        const sctp_subtype_t type,
        void *arg, sctp_cmd_seq_t *commands)
 {
-       sctp_disposition_t retval;
-       struct sctp_chunk *chunk = arg;
-       struct sctp_chunk *repl;
+       struct sctp_chunk *chunk = arg, *repl, *err_chunk;
+       struct sctp_unrecognized_param *unk_param;
        struct sctp_association *new_asoc;
-       struct sctp_chunk *err_chunk;
        struct sctp_packet *packet;
-       sctp_unrecognized_param_t *unk_param;
+       sctp_disposition_t retval;
        int len;
 
        /* 6.10 Bundling
@@ -1555,7 +1552,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
                 * construct the parameters in INIT ACK by copying the
                 * ERROR causes over.
                 */
-               unk_param = (sctp_unrecognized_param_t *)
+               unk_param = (struct sctp_unrecognized_param *)
                            ((__u8 *)(err_chunk->chunk_hdr) +
                            sizeof(struct sctp_chunkhdr));
                /* Replace the cause code with the "Unrecognized parameter"
@@ -2167,7 +2164,7 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(
         * as we do not know its true length.  So, to be safe, discard the
         * packet.
         */
-       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+       if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_abort_chunk)))
                return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* ADD-IP: Special case for ABORT chunks
@@ -2209,7 +2206,7 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(struct net *net,
         * as we do not know its true length.  So, to be safe, discard the
         * packet.
         */
-       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+       if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_abort_chunk)))
                return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* ADD-IP: Special case for ABORT chunks
@@ -2473,7 +2470,7 @@ sctp_disposition_t sctp_sf_do_9_1_abort(struct net *net,
         * as we do not know its true length.  So, to be safe, discard the
         * packet.
         */
-       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+       if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_abort_chunk)))
                return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* ADD-IP: Special case for ABORT chunks
@@ -2549,7 +2546,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(struct net *net,
         * as we do not know its true length.  So, to be safe, discard the
         * packet.
         */
-       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+       if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_abort_chunk)))
                return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* See if we have an error cause code in the chunk.  */
@@ -3191,14 +3188,14 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(struct net *net,
                                        sctp_cmd_seq_t *commands)
 {
        struct sctp_chunk *chunk = arg;
-       sctp_sackhdr_t *sackh;
+       struct sctp_sackhdr *sackh;
        __u32 ctsn;
 
        if (!sctp_vtag_verify(chunk, asoc))
                return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the SACK chunk has a valid length. */
-       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_sack_chunk_t)))
+       if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_sack_chunk)))
                return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
@@ -4453,11 +4450,10 @@ static sctp_disposition_t sctp_sf_abort_violation(
                /* Treat INIT-ACK as a special case during COOKIE-WAIT. */
                if (chunk->chunk_hdr->type == SCTP_CID_INIT_ACK &&
                    !asoc->peer.i.init_tag) {
-                       sctp_initack_chunk_t *initack;
+                       struct sctp_initack_chunk *initack;
 
-                       initack = (sctp_initack_chunk_t *)chunk->chunk_hdr;
-                       if (!sctp_chunk_length_valid(chunk,
-                                                    sizeof(sctp_initack_chunk_t)))
+                       initack = (struct sctp_initack_chunk *)chunk->chunk_hdr;
+                       if (!sctp_chunk_length_valid(chunk, sizeof(*initack)))
                                abort->chunk_hdr->flags |= SCTP_CHUNK_FLAG_T;
                        else {
                                unsigned int inittag;
@@ -4520,7 +4516,7 @@ nomem:
  * Handle a protocol violation when the chunk length is invalid.
  * "Invalid" length is identified as smaller than the minimal length a
  * given chunk can be.  For example, a SACK chunk has invalid length
- * if its length is set to be smaller than the size of sctp_sack_chunk_t.
+ * if its length is set to be smaller than the size of struct sctp_sack_chunk.
  *
  * We inform the other end by sending an ABORT with a Protocol Violation
  * error code.
@@ -6106,9 +6102,9 @@ static struct sctp_packet *sctp_ootb_pkt_new(struct net *net,
                switch (chunk->chunk_hdr->type) {
                case SCTP_CID_INIT_ACK:
                {
-                       sctp_initack_chunk_t *initack;
+                       struct sctp_initack_chunk *initack;
 
-                       initack = (sctp_initack_chunk_t *)chunk->chunk_hdr;
+                       initack = (struct sctp_initack_chunk *)chunk->chunk_hdr;
                        vtag = ntohl(initack->init_hdr.init_tag);
                        break;
                }
index 3395485..c717ef0 100644 (file)
@@ -8,10 +8,6 @@ config SMC
          The Linux implementation of the SMC-R solution is designed as
          a separate socket family SMC.
 
-         Warning: SMC will expose all memory for remote reads and writes
-         once a connection is established.  Don't enable this option except
-         for tightly controlled lab environment.
-
          Select this option if you want to run SMC socket applications
 
 config SMC_DIAG
index 6793d73..8c6d24b 100644 (file)
@@ -338,6 +338,12 @@ static int smc_clnt_conf_first_link(struct smc_sock *smc, union ib_gid *gid)
                return SMC_CLC_DECL_INTERR;
 
        smc_wr_remember_qp_attr(link);
+
+       rc = smc_wr_reg_send(link,
+                            smc->conn.rmb_desc->mr_rx[SMC_SINGLE_LINK]);
+       if (rc)
+               return SMC_CLC_DECL_INTERR;
+
        /* send CONFIRM LINK response over RoCE fabric */
        rc = smc_llc_send_confirm_link(link,
                                       link->smcibdev->mac[link->ibport - 1],
@@ -430,12 +436,8 @@ static int smc_connect_rdma(struct smc_sock *smc)
 
        smc_conn_save_peer_info(smc, &aclc);
 
-       rc = smc_sndbuf_create(smc);
-       if (rc) {
-               reason_code = SMC_CLC_DECL_MEM;
-               goto decline_rdma_unlock;
-       }
-       rc = smc_rmb_create(smc);
+       /* create send buffer and rmb */
+       rc = smc_buf_create(smc);
        if (rc) {
                reason_code = SMC_CLC_DECL_MEM;
                goto decline_rdma_unlock;
@@ -459,7 +461,20 @@ static int smc_connect_rdma(struct smc_sock *smc)
                        reason_code = SMC_CLC_DECL_INTERR;
                        goto decline_rdma_unlock;
                }
+       } else {
+               struct smc_buf_desc *buf_desc = smc->conn.rmb_desc;
+
+               if (!buf_desc->reused) {
+                       /* register memory region for new rmb */
+                       rc = smc_wr_reg_send(link,
+                                            buf_desc->mr_rx[SMC_SINGLE_LINK]);
+                       if (rc) {
+                               reason_code = SMC_CLC_DECL_INTERR;
+                               goto decline_rdma_unlock;
+                       }
+               }
        }
+       smc_rmb_sync_sg_for_device(&smc->conn);
 
        rc = smc_clc_send_confirm(smc);
        if (rc)
@@ -692,6 +707,12 @@ static int smc_serv_conf_first_link(struct smc_sock *smc)
        int rc;
 
        link = &lgr->lnk[SMC_SINGLE_LINK];
+
+       rc = smc_wr_reg_send(link,
+                            smc->conn.rmb_desc->mr_rx[SMC_SINGLE_LINK]);
+       if (rc)
+               return SMC_CLC_DECL_INTERR;
+
        /* send CONFIRM LINK request to client over the RoCE fabric */
        rc = smc_llc_send_confirm_link(link,
                                       link->smcibdev->mac[link->ibport - 1],
@@ -779,11 +800,6 @@ static void smc_listen_work(struct work_struct *work)
        mutex_lock(&smc_create_lgr_pending);
        local_contact = smc_conn_create(new_smc, peeraddr.sin_addr.s_addr,
                                        smcibdev, ibport, &pclc.lcl, 0);
-       if (local_contact == SMC_REUSE_CONTACT)
-               /* lock no longer needed, free it due to following
-                * smc_clc_wait_msg() call
-                */
-               mutex_unlock(&smc_create_lgr_pending);
        if (local_contact < 0) {
                rc = local_contact;
                if (rc == -ENOMEM)
@@ -794,12 +810,8 @@ static void smc_listen_work(struct work_struct *work)
        }
        link = &new_smc->conn.lgr->lnk[SMC_SINGLE_LINK];
 
-       rc = smc_sndbuf_create(new_smc);
-       if (rc) {
-               reason_code = SMC_CLC_DECL_MEM;
-               goto decline_rdma;
-       }
-       rc = smc_rmb_create(new_smc);
+       /* create send buffer and rmb */
+       rc = smc_buf_create(new_smc);
        if (rc) {
                reason_code = SMC_CLC_DECL_MEM;
                goto decline_rdma;
@@ -808,6 +820,21 @@ static void smc_listen_work(struct work_struct *work)
        smc_close_init(new_smc);
        smc_rx_init(new_smc);
 
+       if (local_contact != SMC_FIRST_CONTACT) {
+               struct smc_buf_desc *buf_desc = new_smc->conn.rmb_desc;
+
+               if (!buf_desc->reused) {
+                       /* register memory region for new rmb */
+                       rc = smc_wr_reg_send(link,
+                                            buf_desc->mr_rx[SMC_SINGLE_LINK]);
+                       if (rc) {
+                               reason_code = SMC_CLC_DECL_INTERR;
+                               goto decline_rdma;
+                       }
+               }
+       }
+       smc_rmb_sync_sg_for_device(&new_smc->conn);
+
        rc = smc_clc_send_accept(new_smc, local_contact);
        if (rc)
                goto out_err;
@@ -853,8 +880,7 @@ out_connected:
        if (newsmcsk->sk_state == SMC_INIT)
                newsmcsk->sk_state = SMC_ACTIVE;
 enqueue:
-       if (local_contact == SMC_FIRST_CONTACT)
-               mutex_unlock(&smc_create_lgr_pending);
+       mutex_unlock(&smc_create_lgr_pending);
        lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
        if (lsmc->sk.sk_state == SMC_LISTEN) {
                smc_accept_enqueue(&lsmc->sk, newsmcsk);
index 03ec058..3934913 100644 (file)
@@ -204,13 +204,13 @@ int smc_clc_send_confirm(struct smc_sock *smc)
        memcpy(&cclc.lcl.mac, &link->smcibdev->mac[link->ibport - 1], ETH_ALEN);
        hton24(cclc.qpn, link->roce_qp->qp_num);
        cclc.rmb_rkey =
-               htonl(conn->rmb_desc->rkey[SMC_SINGLE_LINK]);
+               htonl(conn->rmb_desc->mr_rx[SMC_SINGLE_LINK]->rkey);
        cclc.conn_idx = 1; /* for now: 1 RMB = 1 RMBE */
        cclc.rmbe_alert_token = htonl(conn->alert_token_local);
        cclc.qp_mtu = min(link->path_mtu, link->peer_mtu);
        cclc.rmbe_size = conn->rmbe_size_short;
-       cclc.rmb_dma_addr =
-               cpu_to_be64((u64)conn->rmb_desc->dma_addr[SMC_SINGLE_LINK]);
+       cclc.rmb_dma_addr = cpu_to_be64(
+               (u64)sg_dma_address(conn->rmb_desc->sgt[SMC_SINGLE_LINK].sgl));
        hton24(cclc.psn, link->psn_initial);
 
        memcpy(cclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
@@ -256,13 +256,13 @@ int smc_clc_send_accept(struct smc_sock *new_smc, int srv_first_contact)
        memcpy(&aclc.lcl.mac, link->smcibdev->mac[link->ibport - 1], ETH_ALEN);
        hton24(aclc.qpn, link->roce_qp->qp_num);
        aclc.rmb_rkey =
-               htonl(conn->rmb_desc->rkey[SMC_SINGLE_LINK]);
+               htonl(conn->rmb_desc->mr_rx[SMC_SINGLE_LINK]->rkey);
        aclc.conn_idx = 1;                      /* as long as 1 RMB = 1 RMBE */
        aclc.rmbe_alert_token = htonl(conn->alert_token_local);
        aclc.qp_mtu = link->path_mtu;
        aclc.rmbe_size = conn->rmbe_size_short,
-       aclc.rmb_dma_addr =
-               cpu_to_be64((u64)conn->rmb_desc->dma_addr[SMC_SINGLE_LINK]);
+       aclc.rmb_dma_addr = cpu_to_be64(
+               (u64)sg_dma_address(conn->rmb_desc->sgt[SMC_SINGLE_LINK].sgl));
        hton24(aclc.psn, link->psn_initial);
        memcpy(aclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
 
index 3ac09a6..1a16d51 100644 (file)
@@ -175,7 +175,6 @@ static int smc_lgr_create(struct smc_sock *smc, __be32 peer_in_addr,
        rc = smc_wr_alloc_link_mem(lnk);
        if (rc)
                goto free_lgr;
-       init_waitqueue_head(&lnk->wr_tx_wait);
        rc = smc_ib_create_protection_domain(lnk);
        if (rc)
                goto free_link_mem;
@@ -207,17 +206,14 @@ out:
        return rc;
 }
 
-static void smc_sndbuf_unuse(struct smc_connection *conn)
+static void smc_buf_unuse(struct smc_connection *conn)
 {
        if (conn->sndbuf_desc) {
                conn->sndbuf_desc->used = 0;
                conn->sndbuf_size = 0;
        }
-}
-
-static void smc_rmb_unuse(struct smc_connection *conn)
-{
        if (conn->rmb_desc) {
+               conn->rmb_desc->reused = true;
                conn->rmb_desc->used = 0;
                conn->rmbe_size = 0;
        }
@@ -232,8 +228,7 @@ void smc_conn_free(struct smc_connection *conn)
                return;
        smc_cdc_tx_dismiss_slots(conn);
        smc_lgr_unregister_conn(conn);
-       smc_rmb_unuse(conn);
-       smc_sndbuf_unuse(conn);
+       smc_buf_unuse(conn);
 }
 
 static void smc_link_clear(struct smc_link *lnk)
@@ -246,48 +241,57 @@ static void smc_link_clear(struct smc_link *lnk)
        smc_wr_free_link_mem(lnk);
 }
 
-static void smc_lgr_free_sndbufs(struct smc_link_group *lgr)
+static void smc_buf_free(struct smc_buf_desc *buf_desc, struct smc_link *lnk,
+                        bool is_rmb)
 {
-       struct smc_buf_desc *sndbuf_desc, *bf_desc;
-       int i;
-
-       for (i = 0; i < SMC_RMBE_SIZES; i++) {
-               list_for_each_entry_safe(sndbuf_desc, bf_desc, &lgr->sndbufs[i],
-                                        list) {
-                       list_del(&sndbuf_desc->list);
-                       smc_ib_buf_unmap(lgr->lnk[SMC_SINGLE_LINK].smcibdev,
-                                        smc_uncompress_bufsize(i),
-                                        sndbuf_desc, DMA_TO_DEVICE);
-                       kfree(sndbuf_desc->cpu_addr);
-                       kfree(sndbuf_desc);
-               }
+       if (is_rmb) {
+               if (buf_desc->mr_rx[SMC_SINGLE_LINK])
+                       smc_ib_put_memory_region(
+                                       buf_desc->mr_rx[SMC_SINGLE_LINK]);
+               smc_ib_buf_unmap_sg(lnk->smcibdev, buf_desc,
+                                   DMA_FROM_DEVICE);
+       } else {
+               smc_ib_buf_unmap_sg(lnk->smcibdev, buf_desc,
+                                   DMA_TO_DEVICE);
        }
+       sg_free_table(&buf_desc->sgt[SMC_SINGLE_LINK]);
+       if (buf_desc->cpu_addr)
+               free_pages((unsigned long)buf_desc->cpu_addr, buf_desc->order);
+       kfree(buf_desc);
 }
 
-static void smc_lgr_free_rmbs(struct smc_link_group *lgr)
+static void __smc_lgr_free_bufs(struct smc_link_group *lgr, bool is_rmb)
 {
-       struct smc_buf_desc *rmb_desc, *bf_desc;
        struct smc_link *lnk = &lgr->lnk[SMC_SINGLE_LINK];
+       struct smc_buf_desc *buf_desc, *bf_desc;
+       struct list_head *buf_list;
        int i;
 
        for (i = 0; i < SMC_RMBE_SIZES; i++) {
-               list_for_each_entry_safe(rmb_desc, bf_desc, &lgr->rmbs[i],
+               if (is_rmb)
+                       buf_list = &lgr->rmbs[i];
+               else
+                       buf_list = &lgr->sndbufs[i];
+               list_for_each_entry_safe(buf_desc, bf_desc, buf_list,
                                         list) {
-                       list_del(&rmb_desc->list);
-                       smc_ib_buf_unmap(lnk->smcibdev,
-                                        smc_uncompress_bufsize(i),
-                                        rmb_desc, DMA_FROM_DEVICE);
-                       kfree(rmb_desc->cpu_addr);
-                       kfree(rmb_desc);
+                       list_del(&buf_desc->list);
+                       smc_buf_free(buf_desc, lnk, is_rmb);
                }
        }
 }
 
+static void smc_lgr_free_bufs(struct smc_link_group *lgr)
+{
+       /* free send buffers */
+       __smc_lgr_free_bufs(lgr, false);
+       /* free rmbs */
+       __smc_lgr_free_bufs(lgr, true);
+}
+
 /* remove a link group */
 void smc_lgr_free(struct smc_link_group *lgr)
 {
-       smc_lgr_free_rmbs(lgr);
-       smc_lgr_free_sndbufs(lgr);
+       smc_lgr_free_bufs(lgr);
        smc_link_clear(&lgr->lnk[SMC_SINGLE_LINK]);
        kfree(lgr);
 }
@@ -452,45 +456,25 @@ out:
        return rc ? rc : local_contact;
 }
 
-/* try to reuse a sndbuf description slot of the sndbufs list for a certain
- * buf_size; if not available, return NULL
+/* try to reuse a sndbuf or rmb description slot for a certain
+ * buffer size; if not available, return NULL
  */
 static inline
-struct smc_buf_desc *smc_sndbuf_get_slot(struct smc_link_group *lgr,
-                                        int compressed_bufsize)
+struct smc_buf_desc *smc_buf_get_slot(struct smc_link_group *lgr,
+                                     int compressed_bufsize,
+                                     rwlock_t *lock,
+                                     struct list_head *buf_list)
 {
-       struct smc_buf_desc *sndbuf_slot;
-
-       read_lock_bh(&lgr->sndbufs_lock);
-       list_for_each_entry(sndbuf_slot, &lgr->sndbufs[compressed_bufsize],
-                           list) {
-               if (cmpxchg(&sndbuf_slot->used, 0, 1) == 0) {
-                       read_unlock_bh(&lgr->sndbufs_lock);
-                       return sndbuf_slot;
-               }
-       }
-       read_unlock_bh(&lgr->sndbufs_lock);
-       return NULL;
-}
+       struct smc_buf_desc *buf_slot;
 
-/* try to reuse an rmb description slot of the rmbs list for a certain
- * rmbe_size; if not available, return NULL
- */
-static inline
-struct smc_buf_desc *smc_rmb_get_slot(struct smc_link_group *lgr,
-                                     int compressed_bufsize)
-{
-       struct smc_buf_desc *rmb_slot;
-
-       read_lock_bh(&lgr->rmbs_lock);
-       list_for_each_entry(rmb_slot, &lgr->rmbs[compressed_bufsize],
-                           list) {
-               if (cmpxchg(&rmb_slot->used, 0, 1) == 0) {
-                       read_unlock_bh(&lgr->rmbs_lock);
-                       return rmb_slot;
+       read_lock_bh(lock);
+       list_for_each_entry(buf_slot, buf_list, list) {
+               if (cmpxchg(&buf_slot->used, 0, 1) == 0) {
+                       read_unlock_bh(lock);
+                       return buf_slot;
                }
        }
-       read_unlock_bh(&lgr->rmbs_lock);
+       read_unlock_bh(lock);
        return NULL;
 }
 
@@ -503,136 +487,186 @@ static inline int smc_rmb_wnd_update_limit(int rmbe_size)
        return min_t(int, rmbe_size / 10, SOCK_MIN_SNDBUF / 2);
 }
 
-/* create the tx buffer for an SMC socket */
-int smc_sndbuf_create(struct smc_sock *smc)
+static struct smc_buf_desc *smc_new_buf_create(struct smc_link_group *lgr,
+                                              bool is_rmb, int bufsize)
 {
-       struct smc_connection *conn = &smc->conn;
-       struct smc_link_group *lgr = conn->lgr;
-       int tmp_bufsize, tmp_bufsize_short;
-       struct smc_buf_desc *sndbuf_desc;
+       struct smc_buf_desc *buf_desc;
+       struct smc_link *lnk;
        int rc;
 
-       /* use socket send buffer size (w/o overhead) as start value */
-       for (tmp_bufsize_short = smc_compress_bufsize(smc->sk.sk_sndbuf / 2);
-            tmp_bufsize_short >= 0; tmp_bufsize_short--) {
-               tmp_bufsize = smc_uncompress_bufsize(tmp_bufsize_short);
-               /* check for reusable sndbuf_slot in the link group */
-               sndbuf_desc = smc_sndbuf_get_slot(lgr, tmp_bufsize_short);
-               if (sndbuf_desc) {
-                       memset(sndbuf_desc->cpu_addr, 0, tmp_bufsize);
-                       break; /* found reusable slot */
-               }
-               /* try to alloc a new send buffer */
-               sndbuf_desc = kzalloc(sizeof(*sndbuf_desc), GFP_KERNEL);
-               if (!sndbuf_desc)
-                       break; /* give up with -ENOMEM */
-               sndbuf_desc->cpu_addr = kzalloc(tmp_bufsize,
-                                               GFP_KERNEL | __GFP_NOWARN |
-                                               __GFP_NOMEMALLOC |
-                                               __GFP_NORETRY);
-               if (!sndbuf_desc->cpu_addr) {
-                       kfree(sndbuf_desc);
-                       sndbuf_desc = NULL;
-                       /* if send buffer allocation has failed,
-                        * try a smaller one
-                        */
-                       continue;
-               }
-               rc = smc_ib_buf_map(lgr->lnk[SMC_SINGLE_LINK].smcibdev,
-                                   tmp_bufsize, sndbuf_desc,
-                                   DMA_TO_DEVICE);
+       /* try to alloc a new buffer */
+       buf_desc = kzalloc(sizeof(*buf_desc), GFP_KERNEL);
+       if (!buf_desc)
+               return ERR_PTR(-ENOMEM);
+
+       buf_desc->cpu_addr =
+               (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN |
+                                        __GFP_NOMEMALLOC |
+                                        __GFP_NORETRY | __GFP_ZERO,
+                                        get_order(bufsize));
+       if (!buf_desc->cpu_addr) {
+               kfree(buf_desc);
+               return ERR_PTR(-EAGAIN);
+       }
+       buf_desc->order = get_order(bufsize);
+
+       /* build the sg table from the pages */
+       lnk = &lgr->lnk[SMC_SINGLE_LINK];
+       rc = sg_alloc_table(&buf_desc->sgt[SMC_SINGLE_LINK], 1,
+                           GFP_KERNEL);
+       if (rc) {
+               smc_buf_free(buf_desc, lnk, is_rmb);
+               return ERR_PTR(rc);
+       }
+       sg_set_buf(buf_desc->sgt[SMC_SINGLE_LINK].sgl,
+                  buf_desc->cpu_addr, bufsize);
+
+       /* map sg table to DMA address */
+       rc = smc_ib_buf_map_sg(lnk->smcibdev, buf_desc,
+                              is_rmb ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       /* SMC protocol depends on mapping to one DMA address only */
+       if (rc != 1)  {
+               smc_buf_free(buf_desc, lnk, is_rmb);
+               return ERR_PTR(-EAGAIN);
+       }
+
+       /* create a new memory region for the RMB */
+       if (is_rmb) {
+               rc = smc_ib_get_memory_region(lnk->roce_pd,
+                                             IB_ACCESS_REMOTE_WRITE |
+                                             IB_ACCESS_LOCAL_WRITE,
+                                             buf_desc);
                if (rc) {
-                       kfree(sndbuf_desc->cpu_addr);
-                       kfree(sndbuf_desc);
-                       sndbuf_desc = NULL;
-                       continue; /* if mapping failed, try smaller one */
+                       smc_buf_free(buf_desc, lnk, is_rmb);
+                       return ERR_PTR(rc);
                }
-               sndbuf_desc->used = 1;
-               write_lock_bh(&lgr->sndbufs_lock);
-               list_add(&sndbuf_desc->list,
-                        &lgr->sndbufs[tmp_bufsize_short]);
-               write_unlock_bh(&lgr->sndbufs_lock);
-               break;
-       }
-       if (sndbuf_desc && sndbuf_desc->cpu_addr) {
-               conn->sndbuf_desc = sndbuf_desc;
-               conn->sndbuf_size = tmp_bufsize;
-               smc->sk.sk_sndbuf = tmp_bufsize * 2;
-               atomic_set(&conn->sndbuf_space, tmp_bufsize);
-               return 0;
-       } else {
-               return -ENOMEM;
        }
+
+       return buf_desc;
 }
 
-/* create the RMB for an SMC socket (even though the SMC protocol
- * allows more than one RMB-element per RMB, the Linux implementation
- * uses just one RMB-element per RMB, i.e. uses an extra RMB for every
- * connection in a link group
- */
-int smc_rmb_create(struct smc_sock *smc)
+static int __smc_buf_create(struct smc_sock *smc, bool is_rmb)
 {
        struct smc_connection *conn = &smc->conn;
        struct smc_link_group *lgr = conn->lgr;
-       int tmp_bufsize, tmp_bufsize_short;
-       struct smc_buf_desc *rmb_desc;
-       int rc;
+       struct smc_buf_desc *buf_desc = NULL;
+       struct list_head *buf_list;
+       int bufsize, bufsize_short;
+       int sk_buf_size;
+       rwlock_t *lock;
+
+       if (is_rmb)
+               /* use socket recv buffer size (w/o overhead) as start value */
+               sk_buf_size = smc->sk.sk_rcvbuf / 2;
+       else
+               /* use socket send buffer size (w/o overhead) as start value */
+               sk_buf_size = smc->sk.sk_sndbuf / 2;
+
+       for (bufsize_short = smc_compress_bufsize(smc->sk.sk_sndbuf / 2);
+            bufsize_short >= 0; bufsize_short--) {
+
+               if (is_rmb) {
+                       lock = &lgr->rmbs_lock;
+                       buf_list = &lgr->rmbs[bufsize_short];
+               } else {
+                       lock = &lgr->sndbufs_lock;
+                       buf_list = &lgr->sndbufs[bufsize_short];
+               }
+               bufsize = smc_uncompress_bufsize(bufsize_short);
+               if ((1 << get_order(bufsize)) > SG_MAX_SINGLE_ALLOC)
+                       continue;
 
-       /* use socket recv buffer size (w/o overhead) as start value */
-       for (tmp_bufsize_short = smc_compress_bufsize(smc->sk.sk_rcvbuf / 2);
-            tmp_bufsize_short >= 0; tmp_bufsize_short--) {
-               tmp_bufsize = smc_uncompress_bufsize(tmp_bufsize_short);
-               /* check for reusable rmb_slot in the link group */
-               rmb_desc = smc_rmb_get_slot(lgr, tmp_bufsize_short);
-               if (rmb_desc) {
-                       memset(rmb_desc->cpu_addr, 0, tmp_bufsize);
+               /* check for reusable slot in the link group */
+               buf_desc = smc_buf_get_slot(lgr, bufsize_short, lock, buf_list);
+               if (buf_desc) {
+                       memset(buf_desc->cpu_addr, 0, bufsize);
                        break; /* found reusable slot */
                }
-               /* try to alloc a new RMB */
-               rmb_desc = kzalloc(sizeof(*rmb_desc), GFP_KERNEL);
-               if (!rmb_desc)
-                       break; /* give up with -ENOMEM */
-               rmb_desc->cpu_addr = kzalloc(tmp_bufsize,
-                                            GFP_KERNEL | __GFP_NOWARN |
-                                            __GFP_NOMEMALLOC |
-                                            __GFP_NORETRY);
-               if (!rmb_desc->cpu_addr) {
-                       kfree(rmb_desc);
-                       rmb_desc = NULL;
-                       /* if RMB allocation has failed,
-                        * try a smaller one
-                        */
+
+               buf_desc = smc_new_buf_create(lgr, is_rmb, bufsize);
+               if (PTR_ERR(buf_desc) == -ENOMEM)
+                       break;
+               if (IS_ERR(buf_desc))
                        continue;
-               }
-               rc = smc_ib_buf_map(lgr->lnk[SMC_SINGLE_LINK].smcibdev,
-                                   tmp_bufsize, rmb_desc,
-                                   DMA_FROM_DEVICE);
-               if (rc) {
-                       kfree(rmb_desc->cpu_addr);
-                       kfree(rmb_desc);
-                       rmb_desc = NULL;
-                       continue; /* if mapping failed, try smaller one */
-               }
-               rmb_desc->rkey[SMC_SINGLE_LINK] =
-                       lgr->lnk[SMC_SINGLE_LINK].roce_pd->unsafe_global_rkey;
-               rmb_desc->used = 1;
-               write_lock_bh(&lgr->rmbs_lock);
-               list_add(&rmb_desc->list,
-                        &lgr->rmbs[tmp_bufsize_short]);
-               write_unlock_bh(&lgr->rmbs_lock);
-               break;
+
+               buf_desc->used = 1;
+               write_lock_bh(lock);
+               list_add(&buf_desc->list, buf_list);
+               write_unlock_bh(lock);
+               break; /* found */
        }
-       if (rmb_desc && rmb_desc->cpu_addr) {
-               conn->rmb_desc = rmb_desc;
-               conn->rmbe_size = tmp_bufsize;
-               conn->rmbe_size_short = tmp_bufsize_short;
-               smc->sk.sk_rcvbuf = tmp_bufsize * 2;
+
+       if (IS_ERR(buf_desc))
+               return -ENOMEM;
+
+       if (is_rmb) {
+               conn->rmb_desc = buf_desc;
+               conn->rmbe_size = bufsize;
+               conn->rmbe_size_short = bufsize_short;
+               smc->sk.sk_rcvbuf = bufsize * 2;
                atomic_set(&conn->bytes_to_rcv, 0);
-               conn->rmbe_update_limit = smc_rmb_wnd_update_limit(tmp_bufsize);
-               return 0;
+               conn->rmbe_update_limit = smc_rmb_wnd_update_limit(bufsize);
        } else {
-               return -ENOMEM;
+               conn->sndbuf_desc = buf_desc;
+               conn->sndbuf_size = bufsize;
+               smc->sk.sk_sndbuf = bufsize * 2;
+               atomic_set(&conn->sndbuf_space, bufsize);
        }
+       return 0;
+}
+
+void smc_sndbuf_sync_sg_for_cpu(struct smc_connection *conn)
+{
+       struct smc_link_group *lgr = conn->lgr;
+
+       smc_ib_sync_sg_for_cpu(lgr->lnk[SMC_SINGLE_LINK].smcibdev,
+                              conn->sndbuf_desc, DMA_TO_DEVICE);
+}
+
+void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn)
+{
+       struct smc_link_group *lgr = conn->lgr;
+
+       smc_ib_sync_sg_for_device(lgr->lnk[SMC_SINGLE_LINK].smcibdev,
+                                 conn->sndbuf_desc, DMA_TO_DEVICE);
+}
+
+void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn)
+{
+       struct smc_link_group *lgr = conn->lgr;
+
+       smc_ib_sync_sg_for_cpu(lgr->lnk[SMC_SINGLE_LINK].smcibdev,
+                              conn->rmb_desc, DMA_FROM_DEVICE);
+}
+
+void smc_rmb_sync_sg_for_device(struct smc_connection *conn)
+{
+       struct smc_link_group *lgr = conn->lgr;
+
+       smc_ib_sync_sg_for_device(lgr->lnk[SMC_SINGLE_LINK].smcibdev,
+                                 conn->rmb_desc, DMA_FROM_DEVICE);
+}
+
+/* create the send and receive buffer for an SMC socket;
+ * receive buffers are called RMBs;
+ * (even though the SMC protocol allows more than one RMB-element per RMB,
+ * the Linux implementation uses just one RMB-element per RMB, i.e. uses an
+ * extra RMB for every connection in a link group
+ */
+int smc_buf_create(struct smc_sock *smc)
+{
+       int rc;
+
+       /* create send buffer */
+       rc = __smc_buf_create(smc, false);
+       if (rc)
+               return rc;
+       /* create rmb */
+       rc = __smc_buf_create(smc, true);
+       if (rc)
+               smc_buf_free(smc->conn.sndbuf_desc,
+                            &smc->conn.lgr->lnk[SMC_SINGLE_LINK], false);
+       return rc;
 }
 
 static inline int smc_rmb_reserve_rtoken_idx(struct smc_link_group *lgr)
index b013cb4..19c44bf 100644 (file)
@@ -37,6 +37,14 @@ struct smc_wr_buf {
        u8      raw[SMC_WR_BUF_SIZE];
 };
 
+#define SMC_WR_REG_MR_WAIT_TIME        (5 * HZ)/* wait time for ib_wr_reg_mr result */
+
+enum smc_wr_reg_state {
+       POSTED,         /* ib_wr_reg_mr request posted */
+       CONFIRMED,      /* ib_wr_reg_mr response: successful */
+       FAILED          /* ib_wr_reg_mr response: failure */
+};
+
 struct smc_link {
        struct smc_ib_device    *smcibdev;      /* ib-device */
        u8                      ibport;         /* port - values 1 | 2 */
@@ -65,6 +73,10 @@ struct smc_link {
        u64                     wr_rx_id;       /* seq # of last recv WR */
        u32                     wr_rx_cnt;      /* number of WR recv buffers */
 
+       struct ib_reg_wr        wr_reg;         /* WR register memory region */
+       wait_queue_head_t       wr_reg_wait;    /* wait for wr_reg result */
+       enum smc_wr_reg_state   wr_reg_state;   /* state of wr_reg request */
+
        union ib_gid            gid;            /* gid matching used vlan id */
        u32                     peer_qpn;       /* QP number of peer */
        enum ib_mtu             path_mtu;       /* used mtu */
@@ -90,14 +102,15 @@ struct smc_link {
 /* tx/rx buffer list element for sndbufs list and rmbs list of a lgr */
 struct smc_buf_desc {
        struct list_head        list;
-       u64                     dma_addr[SMC_LINKS_PER_LGR_MAX];
-                                               /* mapped address of buffer */
        void                    *cpu_addr;      /* virtual address of buffer */
-       u32                     rkey[SMC_LINKS_PER_LGR_MAX];
-                                               /* for rmb only:
-                                                * rkey provided to peer
+       struct sg_table         sgt[SMC_LINKS_PER_LGR_MAX];/* virtual buffer */
+       struct ib_mr            *mr_rx[SMC_LINKS_PER_LGR_MAX];
+                                               /* for rmb only: memory region
+                                                * incl. rkey provided to peer
                                                 */
+       u32                     order;          /* allocation order */
        u32                     used;           /* currently used / unused */
+       bool                    reused;         /* new created / reused */
 };
 
 struct smc_rtoken {                            /* address/key of remote RMB */
@@ -173,9 +186,11 @@ struct smc_clc_msg_accept_confirm;
 
 void smc_lgr_free(struct smc_link_group *lgr);
 void smc_lgr_terminate(struct smc_link_group *lgr);
-int smc_sndbuf_create(struct smc_sock *smc);
-int smc_rmb_create(struct smc_sock *smc);
+int smc_buf_create(struct smc_sock *smc);
 int smc_rmb_rtoken_handling(struct smc_connection *conn,
                            struct smc_clc_msg_accept_confirm *clc);
-
+void smc_sndbuf_sync_sg_for_cpu(struct smc_connection *conn);
+void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn);
+void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn);
+void smc_rmb_sync_sg_for_device(struct smc_connection *conn);
 #endif
index b317155..547e0e1 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/random.h>
 #include <linux/workqueue.h>
+#include <linux/scatterlist.h>
 #include <rdma/ib_verbs.h>
 
 #include "smc_pnet.h"
@@ -192,8 +193,7 @@ int smc_ib_create_protection_domain(struct smc_link *lnk)
 {
        int rc;
 
-       lnk->roce_pd = ib_alloc_pd(lnk->smcibdev->ibdev,
-                                  IB_PD_UNSAFE_GLOBAL_RKEY);
+       lnk->roce_pd = ib_alloc_pd(lnk->smcibdev->ibdev, 0);
        rc = PTR_ERR_OR_ZERO(lnk->roce_pd);
        if (IS_ERR(lnk->roce_pd))
                lnk->roce_pd = NULL;
@@ -232,10 +232,10 @@ int smc_ib_create_queue_pair(struct smc_link *lnk)
                .recv_cq = lnk->smcibdev->roce_cq_recv,
                .srq = NULL,
                .cap = {
-                       .max_send_wr = SMC_WR_BUF_CNT,
                                /* include unsolicited rdma_writes as well,
                                 * there are max. 2 RDMA_WRITE per 1 WR_SEND
                                 */
+                       .max_send_wr = SMC_WR_BUF_CNT * 3,
                        .max_recv_wr = SMC_WR_BUF_CNT * 3,
                        .max_send_sge = SMC_IB_MAX_SEND_SGE,
                        .max_recv_sge = 1,
@@ -254,33 +254,117 @@ int smc_ib_create_queue_pair(struct smc_link *lnk)
        return rc;
 }
 
-/* map a new TX or RX buffer to DMA */
-int smc_ib_buf_map(struct smc_ib_device *smcibdev, int buf_size,
-                  struct smc_buf_desc *buf_slot,
-                  enum dma_data_direction data_direction)
+void smc_ib_put_memory_region(struct ib_mr *mr)
 {
-       int rc = 0;
+       ib_dereg_mr(mr);
+}
 
-       if (buf_slot->dma_addr[SMC_SINGLE_LINK])
-               return rc; /* already mapped */
-       buf_slot->dma_addr[SMC_SINGLE_LINK] =
-               ib_dma_map_single(smcibdev->ibdev, buf_slot->cpu_addr,
-                                 buf_size, data_direction);
-       if (ib_dma_mapping_error(smcibdev->ibdev,
-                                buf_slot->dma_addr[SMC_SINGLE_LINK]))
-               rc = -EIO;
-       return rc;
+static int smc_ib_map_mr_sg(struct smc_buf_desc *buf_slot)
+{
+       unsigned int offset = 0;
+       int sg_num;
+
+       /* map the largest prefix of a dma mapped SG list */
+       sg_num = ib_map_mr_sg(buf_slot->mr_rx[SMC_SINGLE_LINK],
+                             buf_slot->sgt[SMC_SINGLE_LINK].sgl,
+                             buf_slot->sgt[SMC_SINGLE_LINK].orig_nents,
+                             &offset, PAGE_SIZE);
+
+       return sg_num;
+}
+
+/* Allocate a memory region and map the dma mapped SG list of buf_slot */
+int smc_ib_get_memory_region(struct ib_pd *pd, int access_flags,
+                            struct smc_buf_desc *buf_slot)
+{
+       if (buf_slot->mr_rx[SMC_SINGLE_LINK])
+               return 0; /* already done */
+
+       buf_slot->mr_rx[SMC_SINGLE_LINK] =
+               ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, 1 << buf_slot->order);
+       if (IS_ERR(buf_slot->mr_rx[SMC_SINGLE_LINK])) {
+               int rc;
+
+               rc = PTR_ERR(buf_slot->mr_rx[SMC_SINGLE_LINK]);
+               buf_slot->mr_rx[SMC_SINGLE_LINK] = NULL;
+               return rc;
+       }
+
+       if (smc_ib_map_mr_sg(buf_slot) != 1)
+               return -EINVAL;
+
+       return 0;
 }
 
-void smc_ib_buf_unmap(struct smc_ib_device *smcibdev, int buf_size,
+/* synchronize buffer usage for cpu access */
+void smc_ib_sync_sg_for_cpu(struct smc_ib_device *smcibdev,
+                           struct smc_buf_desc *buf_slot,
+                           enum dma_data_direction data_direction)
+{
+       struct scatterlist *sg;
+       unsigned int i;
+
+       /* for now there is just one DMA address */
+       for_each_sg(buf_slot->sgt[SMC_SINGLE_LINK].sgl, sg,
+                   buf_slot->sgt[SMC_SINGLE_LINK].nents, i) {
+               if (!sg_dma_len(sg))
+                       break;
+               ib_dma_sync_single_for_cpu(smcibdev->ibdev,
+                                          sg_dma_address(sg),
+                                          sg_dma_len(sg),
+                                          data_direction);
+       }
+}
+
+/* synchronize buffer usage for device access */
+void smc_ib_sync_sg_for_device(struct smc_ib_device *smcibdev,
+                              struct smc_buf_desc *buf_slot,
+                              enum dma_data_direction data_direction)
+{
+       struct scatterlist *sg;
+       unsigned int i;
+
+       /* for now there is just one DMA address */
+       for_each_sg(buf_slot->sgt[SMC_SINGLE_LINK].sgl, sg,
+                   buf_slot->sgt[SMC_SINGLE_LINK].nents, i) {
+               if (!sg_dma_len(sg))
+                       break;
+               ib_dma_sync_single_for_device(smcibdev->ibdev,
+                                             sg_dma_address(sg),
+                                             sg_dma_len(sg),
+                                             data_direction);
+       }
+}
+
+/* Map a new TX or RX buffer SG-table to DMA */
+int smc_ib_buf_map_sg(struct smc_ib_device *smcibdev,
                      struct smc_buf_desc *buf_slot,
                      enum dma_data_direction data_direction)
 {
-       if (!buf_slot->dma_addr[SMC_SINGLE_LINK])
+       int mapped_nents;
+
+       mapped_nents = ib_dma_map_sg(smcibdev->ibdev,
+                                    buf_slot->sgt[SMC_SINGLE_LINK].sgl,
+                                    buf_slot->sgt[SMC_SINGLE_LINK].orig_nents,
+                                    data_direction);
+       if (!mapped_nents)
+               return -ENOMEM;
+
+       return mapped_nents;
+}
+
+void smc_ib_buf_unmap_sg(struct smc_ib_device *smcibdev,
+                        struct smc_buf_desc *buf_slot,
+                        enum dma_data_direction data_direction)
+{
+       if (!buf_slot->sgt[SMC_SINGLE_LINK].sgl->dma_address)
                return; /* already unmapped */
-       ib_dma_unmap_single(smcibdev->ibdev, *buf_slot->dma_addr, buf_size,
-                           data_direction);
-       buf_slot->dma_addr[SMC_SINGLE_LINK] = 0;
+
+       ib_dma_unmap_sg(smcibdev->ibdev,
+                       buf_slot->sgt[SMC_SINGLE_LINK].sgl,
+                       buf_slot->sgt[SMC_SINGLE_LINK].orig_nents,
+                       data_direction);
+       buf_slot->sgt[SMC_SINGLE_LINK].sgl->dma_address = 0;
 }
 
 static int smc_ib_fill_gid_and_mac(struct smc_ib_device *smcibdev, u8 ibport)
index b567152..9b927a3 100644 (file)
@@ -51,12 +51,12 @@ int smc_ib_register_client(void) __init;
 void smc_ib_unregister_client(void);
 bool smc_ib_port_active(struct smc_ib_device *smcibdev, u8 ibport);
 int smc_ib_remember_port_attr(struct smc_ib_device *smcibdev, u8 ibport);
-int smc_ib_buf_map(struct smc_ib_device *smcibdev, int buf_size,
-                  struct smc_buf_desc *buf_slot,
-                  enum dma_data_direction data_direction);
-void smc_ib_buf_unmap(struct smc_ib_device *smcibdev, int bufsize,
+int smc_ib_buf_map_sg(struct smc_ib_device *smcibdev,
                      struct smc_buf_desc *buf_slot,
                      enum dma_data_direction data_direction);
+void smc_ib_buf_unmap_sg(struct smc_ib_device *smcibdev,
+                        struct smc_buf_desc *buf_slot,
+                        enum dma_data_direction data_direction);
 void smc_ib_dealloc_protection_domain(struct smc_link *lnk);
 int smc_ib_create_protection_domain(struct smc_link *lnk);
 void smc_ib_destroy_queue_pair(struct smc_link *lnk);
@@ -65,6 +65,13 @@ int smc_ib_ready_link(struct smc_link *lnk);
 int smc_ib_modify_qp_rts(struct smc_link *lnk);
 int smc_ib_modify_qp_reset(struct smc_link *lnk);
 long smc_ib_setup_per_ibdev(struct smc_ib_device *smcibdev);
-
-
+int smc_ib_get_memory_region(struct ib_pd *pd, int access_flags,
+                            struct smc_buf_desc *buf_slot);
+void smc_ib_put_memory_region(struct ib_mr *mr);
+void smc_ib_sync_sg_for_cpu(struct smc_ib_device *smcibdev,
+                           struct smc_buf_desc *buf_slot,
+                           enum dma_data_direction data_direction);
+void smc_ib_sync_sg_for_device(struct smc_ib_device *smcibdev,
+                              struct smc_buf_desc *buf_slot,
+                              enum dma_data_direction data_direction);
 #endif
index f0c8b08..b17a333 100644 (file)
@@ -170,6 +170,7 @@ copy:
                                  copylen, conn->rmbe_size - cons.count);
                chunk_len_sum = chunk_len;
                chunk_off = cons.count;
+               smc_rmb_sync_sg_for_cpu(conn);
                for (chunk = 0; chunk < 2; chunk++) {
                        if (!(flags & MSG_TRUNC)) {
                                rc = memcpy_to_msg(msg, rcvbuf_base + chunk_off,
@@ -177,6 +178,7 @@ copy:
                                if (rc) {
                                        if (!read_done)
                                                read_done = -EFAULT;
+                                       smc_rmb_sync_sg_for_device(conn);
                                        goto out;
                                }
                        }
@@ -190,6 +192,7 @@ copy:
                        chunk_len_sum += chunk_len;
                        chunk_off = 0; /* modulo offset in recv ring buffer */
                }
+               smc_rmb_sync_sg_for_device(conn);
 
                /* update cursors */
                if (!(flags & MSG_PEEK)) {
index 21ec183..3c656be 100644 (file)
@@ -174,10 +174,12 @@ int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len)
                                  copylen, conn->sndbuf_size - tx_cnt_prep);
                chunk_len_sum = chunk_len;
                chunk_off = tx_cnt_prep;
+               smc_sndbuf_sync_sg_for_cpu(conn);
                for (chunk = 0; chunk < 2; chunk++) {
                        rc = memcpy_from_msg(sndbuf_base + chunk_off,
                                             msg, chunk_len);
                        if (rc) {
+                               smc_sndbuf_sync_sg_for_device(conn);
                                if (send_done)
                                        return send_done;
                                goto out_err;
@@ -192,6 +194,7 @@ int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len)
                        chunk_len_sum += chunk_len;
                        chunk_off = 0; /* modulo offset in send ring buffer */
                }
+               smc_sndbuf_sync_sg_for_device(conn);
                /* update cursors */
                smc_curs_add(conn->sndbuf_size, &prep, copylen);
                smc_curs_write(&conn->tx_curs_prep,
@@ -277,6 +280,7 @@ static int smc_tx_rdma_writes(struct smc_connection *conn)
        struct smc_link_group *lgr = conn->lgr;
        int to_send, rmbespace;
        struct smc_link *link;
+       dma_addr_t dma_addr;
        int num_sges;
        int rc;
 
@@ -334,12 +338,11 @@ static int smc_tx_rdma_writes(struct smc_connection *conn)
                src_len = conn->sndbuf_size - sent.count;
        }
        src_len_sum = src_len;
+       dma_addr = sg_dma_address(conn->sndbuf_desc->sgt[SMC_SINGLE_LINK].sgl);
        for (dstchunk = 0; dstchunk < 2; dstchunk++) {
                num_sges = 0;
                for (srcchunk = 0; srcchunk < 2; srcchunk++) {
-                       sges[srcchunk].addr =
-                               conn->sndbuf_desc->dma_addr[SMC_SINGLE_LINK] +
-                               src_off;
+                       sges[srcchunk].addr = dma_addr + src_off;
                        sges[srcchunk].length = src_len;
                        sges[srcchunk].lkey = link->roce_pd->local_dma_lkey;
                        num_sges++;
index 874ee9f..ab56bda 100644 (file)
@@ -68,6 +68,16 @@ static inline void smc_wr_tx_process_cqe(struct ib_wc *wc)
        int i;
 
        link = wc->qp->qp_context;
+
+       if (wc->opcode == IB_WC_REG_MR) {
+               if (wc->status)
+                       link->wr_reg_state = FAILED;
+               else
+                       link->wr_reg_state = CONFIRMED;
+               wake_up(&link->wr_reg_wait);
+               return;
+       }
+
        pnd_snd_idx = smc_wr_tx_find_pending_index(link, wc->wr_id);
        if (pnd_snd_idx == link->wr_tx_cnt)
                return;
@@ -243,6 +253,52 @@ int smc_wr_tx_send(struct smc_link *link, struct smc_wr_tx_pend_priv *priv)
        return rc;
 }
 
+/* Register a memory region and wait for result. */
+int smc_wr_reg_send(struct smc_link *link, struct ib_mr *mr)
+{
+       struct ib_send_wr *failed_wr = NULL;
+       int rc;
+
+       ib_req_notify_cq(link->smcibdev->roce_cq_send,
+                        IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
+       link->wr_reg_state = POSTED;
+       link->wr_reg.wr.wr_id = (u64)(uintptr_t)mr;
+       link->wr_reg.mr = mr;
+       link->wr_reg.key = mr->rkey;
+       failed_wr = &link->wr_reg.wr;
+       rc = ib_post_send(link->roce_qp, &link->wr_reg.wr, &failed_wr);
+       WARN_ON(failed_wr != &link->wr_reg.wr);
+       if (rc)
+               return rc;
+
+       rc = wait_event_interruptible_timeout(link->wr_reg_wait,
+                                             (link->wr_reg_state != POSTED),
+                                             SMC_WR_REG_MR_WAIT_TIME);
+       if (!rc) {
+               /* timeout - terminate connections */
+               struct smc_link_group *lgr;
+
+               lgr = container_of(link, struct smc_link_group,
+                                  lnk[SMC_SINGLE_LINK]);
+               smc_lgr_terminate(lgr);
+               return -EPIPE;
+       }
+       if (rc == -ERESTARTSYS)
+               return -EINTR;
+       switch (link->wr_reg_state) {
+       case CONFIRMED:
+               rc = 0;
+               break;
+       case FAILED:
+               rc = -EIO;
+               break;
+       case POSTED:
+               rc = -EPIPE;
+               break;
+       }
+       return rc;
+}
+
 void smc_wr_tx_dismiss_slots(struct smc_link *link, u8 wr_rx_hdr_type,
                             smc_wr_tx_filter filter,
                             smc_wr_tx_dismisser dismisser,
@@ -458,6 +514,11 @@ static void smc_wr_init_sge(struct smc_link *lnk)
                lnk->wr_rx_ibs[i].sg_list = &lnk->wr_rx_sges[i];
                lnk->wr_rx_ibs[i].num_sge = 1;
        }
+       lnk->wr_reg.wr.next = NULL;
+       lnk->wr_reg.wr.num_sge = 0;
+       lnk->wr_reg.wr.send_flags = IB_SEND_SIGNALED;
+       lnk->wr_reg.wr.opcode = IB_WR_REG_MR;
+       lnk->wr_reg.access = IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE;
 }
 
 void smc_wr_free_link(struct smc_link *lnk)
@@ -602,6 +663,8 @@ int smc_wr_create_link(struct smc_link *lnk)
        smc_wr_init_sge(lnk);
        memset(lnk->wr_tx_mask, 0,
               BITS_TO_LONGS(SMC_WR_BUF_CNT) * sizeof(*lnk->wr_tx_mask));
+       init_waitqueue_head(&lnk->wr_tx_wait);
+       init_waitqueue_head(&lnk->wr_reg_wait);
        return rc;
 
 dma_unmap:
index 0b9beed..45eb538 100644 (file)
@@ -102,5 +102,6 @@ void smc_wr_tx_dismiss_slots(struct smc_link *lnk, u8 wr_rx_hdr_type,
 int smc_wr_rx_register_handler(struct smc_wr_rx_handler *handler);
 int smc_wr_rx_post_init(struct smc_link *link);
 void smc_wr_rx_cq_handler(struct ib_cq *ib_cq, void *cq_context);
+int smc_wr_reg_send(struct smc_link *link, struct ib_mr *mr);
 
 #endif /* SMC_WR_H */
index 59e902b..b332d1e 100644 (file)
@@ -652,6 +652,20 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
 }
 EXPORT_SYMBOL(kernel_sendmsg);
 
+int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg,
+                         struct kvec *vec, size_t num, size_t size)
+{
+       struct socket *sock = sk->sk_socket;
+
+       if (!sock->ops->sendmsg_locked)
+               sock_no_sendmsg_locked(sk, msg, size);
+
+       iov_iter_kvec(&msg->msg_iter, WRITE | ITER_KVEC, vec, num, size);
+
+       return sock->ops->sendmsg_locked(sk, msg, msg_data_left(msg));
+}
+EXPORT_SYMBOL(kernel_sendmsg_locked);
+
 static bool skb_is_err_queue(const struct sk_buff *skb)
 {
        /* pkt_type of skbs enqueued on the error queue are set to
@@ -1910,22 +1924,18 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
                                 struct sockaddr __user **save_addr,
                                 struct iovec **iov)
 {
-       struct sockaddr __user *uaddr;
-       struct iovec __user *uiov;
-       size_t nr_segs;
+       struct user_msghdr msg;
        ssize_t err;
 
-       if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) ||
-           __get_user(uaddr, &umsg->msg_name) ||
-           __get_user(kmsg->msg_namelen, &umsg->msg_namelen) ||
-           __get_user(uiov, &umsg->msg_iov) ||
-           __get_user(nr_segs, &umsg->msg_iovlen) ||
-           __get_user(kmsg->msg_control, &umsg->msg_control) ||
-           __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
-           __get_user(kmsg->msg_flags, &umsg->msg_flags))
+       if (copy_from_user(&msg, umsg, sizeof(*umsg)))
                return -EFAULT;
 
-       if (!uaddr)
+       kmsg->msg_control = (void __force *)msg.msg_control;
+       kmsg->msg_controllen = msg.msg_controllen;
+       kmsg->msg_flags = msg.msg_flags;
+
+       kmsg->msg_namelen = msg.msg_namelen;
+       if (!msg.msg_name)
                kmsg->msg_namelen = 0;
 
        if (kmsg->msg_namelen < 0)
@@ -1935,11 +1945,12 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
                kmsg->msg_namelen = sizeof(struct sockaddr_storage);
 
        if (save_addr)
-               *save_addr = uaddr;
+               *save_addr = msg.msg_name;
 
-       if (uaddr && kmsg->msg_namelen) {
+       if (msg.msg_name && kmsg->msg_namelen) {
                if (!save_addr) {
-                       err = move_addr_to_kernel(uaddr, kmsg->msg_namelen,
+                       err = move_addr_to_kernel(msg.msg_name,
+                                                 kmsg->msg_namelen,
                                                  kmsg->msg_name);
                        if (err < 0)
                                return err;
@@ -1949,12 +1960,13 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
                kmsg->msg_namelen = 0;
        }
 
-       if (nr_segs > UIO_MAXIOV)
+       if (msg.msg_iovlen > UIO_MAXIOV)
                return -EMSGSIZE;
 
        kmsg->msg_iocb = NULL;
 
-       return import_iovec(save_addr ? READ : WRITE, uiov, nr_segs,
+       return import_iovec(save_addr ? READ : WRITE,
+                           msg.msg_iov, msg.msg_iovlen,
                            UIO_FASTIOV, iov, &kmsg->msg_iter);
 }
 
@@ -3378,6 +3390,19 @@ int kernel_sendpage(struct socket *sock, struct page *page, int offset,
 }
 EXPORT_SYMBOL(kernel_sendpage);
 
+int kernel_sendpage_locked(struct sock *sk, struct page *page, int offset,
+                          size_t size, int flags)
+{
+       struct socket *sock = sk->sk_socket;
+
+       if (sock->ops->sendpage_locked)
+               return sock->ops->sendpage_locked(sk, page, offset, size,
+                                                 flags);
+
+       return sock_no_sendpage_locked(sk, page, offset, size, flags);
+}
+EXPORT_SYMBOL(kernel_sendpage_locked);
+
 int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
 {
        mm_segment_t oldfs = get_fs();
@@ -3407,7 +3432,6 @@ u32 kernel_sock_ip_overhead(struct sock *sk)
        struct inet_sock *inet;
        struct ip_options_rcu *opt;
        u32 overhead = 0;
-       bool owned_by_user;
 #if IS_ENABLED(CONFIG_IPV6)
        struct ipv6_pinfo *np;
        struct ipv6_txoptions *optv6 = NULL;
@@ -3416,13 +3440,12 @@ u32 kernel_sock_ip_overhead(struct sock *sk)
        if (!sk)
                return overhead;
 
-       owned_by_user = sock_owned_by_user(sk);
        switch (sk->sk_family) {
        case AF_INET:
                inet = inet_sk(sk);
                overhead += sizeof(struct iphdr);
                opt = rcu_dereference_protected(inet->inet_opt,
-                                               owned_by_user);
+                                               sock_owned_by_user(sk));
                if (opt)
                        overhead += opt->opt.optlen;
                return overhead;
@@ -3432,7 +3455,7 @@ u32 kernel_sock_ip_overhead(struct sock *sk)
                overhead += sizeof(struct ipv6hdr);
                if (np)
                        optv6 = rcu_dereference_protected(np->opt,
-                                                         owned_by_user);
+                                                         sock_owned_by_user(sk));
                if (optv6)
                        overhead += (optv6->opt_flen + optv6->opt_nflen);
                return overhead;
index b5c279b..0d18fbc 100644 (file)
 
 static struct workqueue_struct *strp_wq;
 
-struct _strp_rx_msg {
-       /* Internal cb structure. struct strp_rx_msg must be first for passing
+struct _strp_msg {
+       /* Internal cb structure. struct strp_msg must be first for passing
         * to upper layer.
         */
-       struct strp_rx_msg strp;
+       struct strp_msg strp;
        int accum_len;
        int early_eaten;
 };
 
-static inline struct _strp_rx_msg *_strp_rx_msg(struct sk_buff *skb)
+static inline struct _strp_msg *_strp_msg(struct sk_buff *skb)
 {
-       return (struct _strp_rx_msg *)((void *)skb->cb +
+       return (struct _strp_msg *)((void *)skb->cb +
                offsetof(struct qdisc_skb_cb, data));
 }
 
 /* Lower lock held */
-static void strp_abort_rx_strp(struct strparser *strp, int err)
+static void strp_abort_strp(struct strparser *strp, int err)
 {
-       struct sock *csk = strp->sk;
-
        /* Unrecoverable error in receive */
 
-       del_timer(&strp->rx_msg_timer);
+       del_timer(&strp->msg_timer);
 
-       if (strp->rx_stopped)
+       if (strp->stopped)
                return;
 
-       strp->rx_stopped = 1;
+       strp->stopped = 1;
+
+       if (strp->sk) {
+               struct sock *sk = strp->sk;
 
-       /* Report an error on the lower socket */
-       csk->sk_err = err;
-       csk->sk_error_report(csk);
+               /* Report an error on the lower socket */
+               sk->sk_err = err;
+               sk->sk_error_report(sk);
+       }
 }
 
-static void strp_start_rx_timer(struct strparser *strp)
+static void strp_start_timer(struct strparser *strp, long timeo)
 {
-       if (strp->sk->sk_rcvtimeo)
-               mod_timer(&strp->rx_msg_timer, strp->sk->sk_rcvtimeo);
+       if (timeo)
+               mod_timer(&strp->msg_timer, timeo);
 }
 
 /* Lower lock held */
@@ -74,46 +76,55 @@ static void strp_parser_err(struct strparser *strp, int err,
                            read_descriptor_t *desc)
 {
        desc->error = err;
-       kfree_skb(strp->rx_skb_head);
-       strp->rx_skb_head = NULL;
+       kfree_skb(strp->skb_head);
+       strp->skb_head = NULL;
        strp->cb.abort_parser(strp, err);
 }
 
 static inline int strp_peek_len(struct strparser *strp)
 {
-       struct socket *sock = strp->sk->sk_socket;
+       if (strp->sk) {
+               struct socket *sock = strp->sk->sk_socket;
+
+               return sock->ops->peek_len(sock);
+       }
+
+       /* If we don't have an associated socket there's nothing to peek.
+        * Return int max to avoid stopping the strparser.
+        */
 
-       return sock->ops->peek_len(sock);
+       return INT_MAX;
 }
 
 /* Lower socket lock held */
-static int strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
-                    unsigned int orig_offset, size_t orig_len)
+static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
+                      unsigned int orig_offset, size_t orig_len,
+                      size_t max_msg_size, long timeo)
 {
        struct strparser *strp = (struct strparser *)desc->arg.data;
-       struct _strp_rx_msg *rxm;
+       struct _strp_msg *stm;
        struct sk_buff *head, *skb;
        size_t eaten = 0, cand_len;
        ssize_t extra;
        int err;
        bool cloned_orig = false;
 
-       if (strp->rx_paused)
+       if (strp->paused)
                return 0;
 
-       head = strp->rx_skb_head;
+       head = strp->skb_head;
        if (head) {
                /* Message already in progress */
 
-               rxm = _strp_rx_msg(head);
-               if (unlikely(rxm->early_eaten)) {
+               stm = _strp_msg(head);
+               if (unlikely(stm->early_eaten)) {
                        /* Already some number of bytes on the receive sock
-                        * data saved in rx_skb_head, just indicate they
+                        * data saved in skb_head, just indicate they
                         * are consumed.
                         */
-                       eaten = orig_len <= rxm->early_eaten ?
-                               orig_len : rxm->early_eaten;
-                       rxm->early_eaten -= eaten;
+                       eaten = orig_len <= stm->early_eaten ?
+                               orig_len : stm->early_eaten;
+                       stm->early_eaten -= eaten;
 
                        return eaten;
                }
@@ -126,12 +137,12 @@ static int strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
                         */
                        orig_skb = skb_clone(orig_skb, GFP_ATOMIC);
                        if (!orig_skb) {
-                               STRP_STATS_INCR(strp->stats.rx_mem_fail);
+                               STRP_STATS_INCR(strp->stats.mem_fail);
                                desc->error = -ENOMEM;
                                return 0;
                        }
                        if (!pskb_pull(orig_skb, orig_offset)) {
-                               STRP_STATS_INCR(strp->stats.rx_mem_fail);
+                               STRP_STATS_INCR(strp->stats.mem_fail);
                                kfree_skb(orig_skb);
                                desc->error = -ENOMEM;
                                return 0;
@@ -140,13 +151,13 @@ static int strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
                        orig_offset = 0;
                }
 
-               if (!strp->rx_skb_nextp) {
+               if (!strp->skb_nextp) {
                        /* We are going to append to the frags_list of head.
                         * Need to unshare the frag_list.
                         */
                        err = skb_unclone(head, GFP_ATOMIC);
                        if (err) {
-                               STRP_STATS_INCR(strp->stats.rx_mem_fail);
+                               STRP_STATS_INCR(strp->stats.mem_fail);
                                desc->error = err;
                                return 0;
                        }
@@ -165,20 +176,20 @@ static int strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
 
                                skb = alloc_skb(0, GFP_ATOMIC);
                                if (!skb) {
-                                       STRP_STATS_INCR(strp->stats.rx_mem_fail);
+                                       STRP_STATS_INCR(strp->stats.mem_fail);
                                        desc->error = -ENOMEM;
                                        return 0;
                                }
                                skb->len = head->len;
                                skb->data_len = head->len;
                                skb->truesize = head->truesize;
-                               *_strp_rx_msg(skb) = *_strp_rx_msg(head);
-                               strp->rx_skb_nextp = &head->next;
+                               *_strp_msg(skb) = *_strp_msg(head);
+                               strp->skb_nextp = &head->next;
                                skb_shinfo(skb)->frag_list = head;
-                               strp->rx_skb_head = skb;
+                               strp->skb_head = skb;
                                head = skb;
                        } else {
-                               strp->rx_skb_nextp =
+                               strp->skb_nextp =
                                    &skb_shinfo(head)->frag_list;
                        }
                }
@@ -188,112 +199,112 @@ static int strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
                /* Always clone since we will consume something */
                skb = skb_clone(orig_skb, GFP_ATOMIC);
                if (!skb) {
-                       STRP_STATS_INCR(strp->stats.rx_mem_fail);
+                       STRP_STATS_INCR(strp->stats.mem_fail);
                        desc->error = -ENOMEM;
                        break;
                }
 
                cand_len = orig_len - eaten;
 
-               head = strp->rx_skb_head;
+               head = strp->skb_head;
                if (!head) {
                        head = skb;
-                       strp->rx_skb_head = head;
-                       /* Will set rx_skb_nextp on next packet if needed */
-                       strp->rx_skb_nextp = NULL;
-                       rxm = _strp_rx_msg(head);
-                       memset(rxm, 0, sizeof(*rxm));
-                       rxm->strp.offset = orig_offset + eaten;
+                       strp->skb_head = head;
+                       /* Will set skb_nextp on next packet if needed */
+                       strp->skb_nextp = NULL;
+                       stm = _strp_msg(head);
+                       memset(stm, 0, sizeof(*stm));
+                       stm->strp.offset = orig_offset + eaten;
                } else {
                        /* Unclone since we may be appending to an skb that we
                         * already share a frag_list with.
                         */
                        err = skb_unclone(skb, GFP_ATOMIC);
                        if (err) {
-                               STRP_STATS_INCR(strp->stats.rx_mem_fail);
+                               STRP_STATS_INCR(strp->stats.mem_fail);
                                desc->error = err;
                                break;
                        }
 
-                       rxm = _strp_rx_msg(head);
-                       *strp->rx_skb_nextp = skb;
-                       strp->rx_skb_nextp = &skb->next;
+                       stm = _strp_msg(head);
+                       *strp->skb_nextp = skb;
+                       strp->skb_nextp = &skb->next;
                        head->data_len += skb->len;
                        head->len += skb->len;
                        head->truesize += skb->truesize;
                }
 
-               if (!rxm->strp.full_len) {
+               if (!stm->strp.full_len) {
                        ssize_t len;
 
                        len = (*strp->cb.parse_msg)(strp, head);
 
                        if (!len) {
                                /* Need more header to determine length */
-                               if (!rxm->accum_len) {
+                               if (!stm->accum_len) {
                                        /* Start RX timer for new message */
-                                       strp_start_rx_timer(strp);
+                                       strp_start_timer(strp, timeo);
                                }
-                               rxm->accum_len += cand_len;
+                               stm->accum_len += cand_len;
                                eaten += cand_len;
-                               STRP_STATS_INCR(strp->stats.rx_need_more_hdr);
+                               STRP_STATS_INCR(strp->stats.need_more_hdr);
                                WARN_ON(eaten != orig_len);
                                break;
                        } else if (len < 0) {
-                               if (len == -ESTRPIPE && rxm->accum_len) {
+                               if (len == -ESTRPIPE && stm->accum_len) {
                                        len = -ENODATA;
-                                       strp->rx_unrecov_intr = 1;
+                                       strp->unrecov_intr = 1;
                                } else {
-                                       strp->rx_interrupted = 1;
+                                       strp->interrupted = 1;
                                }
                                strp_parser_err(strp, len, desc);
                                break;
-                       } else if (len > strp->sk->sk_rcvbuf) {
+                       } else if (len > max_msg_size) {
                                /* Message length exceeds maximum allowed */
-                               STRP_STATS_INCR(strp->stats.rx_msg_too_big);
+                               STRP_STATS_INCR(strp->stats.msg_too_big);
                                strp_parser_err(strp, -EMSGSIZE, desc);
                                break;
                        } else if (len <= (ssize_t)head->len -
-                                         skb->len - rxm->strp.offset) {
+                                         skb->len - stm->strp.offset) {
                                /* Length must be into new skb (and also
                                 * greater than zero)
                                 */
-                               STRP_STATS_INCR(strp->stats.rx_bad_hdr_len);
+                               STRP_STATS_INCR(strp->stats.bad_hdr_len);
                                strp_parser_err(strp, -EPROTO, desc);
                                break;
                        }
 
-                       rxm->strp.full_len = len;
+                       stm->strp.full_len = len;
                }
 
-               extra = (ssize_t)(rxm->accum_len + cand_len) -
-                       rxm->strp.full_len;
+               extra = (ssize_t)(stm->accum_len + cand_len) -
+                       stm->strp.full_len;
 
                if (extra < 0) {
                        /* Message not complete yet. */
-                       if (rxm->strp.full_len - rxm->accum_len >
+                       if (stm->strp.full_len - stm->accum_len >
                            strp_peek_len(strp)) {
-                               /* Don't have the whole messages in the socket
-                                * buffer. Set strp->rx_need_bytes to wait for
+                               /* Don't have the whole message in the socket
+                                * buffer. Set strp->need_bytes to wait for
                                 * the rest of the message. Also, set "early
                                 * eaten" since we've already buffered the skb
                                 * but don't consume yet per strp_read_sock.
                                 */
 
-                               if (!rxm->accum_len) {
+                               if (!stm->accum_len) {
                                        /* Start RX timer for new message */
-                                       strp_start_rx_timer(strp);
+                                       strp_start_timer(strp, timeo);
                                }
 
-                               strp->rx_need_bytes = rxm->strp.full_len -
-                                                      rxm->accum_len;
-                               rxm->accum_len += cand_len;
-                               rxm->early_eaten = cand_len;
-                               STRP_STATS_ADD(strp->stats.rx_bytes, cand_len);
+                               strp->need_bytes = stm->strp.full_len -
+                                                      stm->accum_len;
+                               stm->accum_len += cand_len;
+                               stm->early_eaten = cand_len;
+                               STRP_STATS_ADD(strp->stats.bytes, cand_len);
                                desc->count = 0; /* Stop reading socket */
                                break;
                        }
-                       rxm->accum_len += cand_len;
+                       stm->accum_len += cand_len;
                        eaten += cand_len;
                        WARN_ON(eaten != orig_len);
                        break;
@@ -308,14 +319,14 @@ static int strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
                eaten += (cand_len - extra);
 
                /* Hurray, we have a new message! */
-               del_timer(&strp->rx_msg_timer);
-               strp->rx_skb_head = NULL;
-               STRP_STATS_INCR(strp->stats.rx_msgs);
+               del_timer(&strp->msg_timer);
+               strp->skb_head = NULL;
+               STRP_STATS_INCR(strp->stats.msgs);
 
                /* Give skb to upper layer */
                strp->cb.rcv_msg(strp, head);
 
-               if (unlikely(strp->rx_paused)) {
+               if (unlikely(strp->paused)) {
                        /* Upper layer paused strp */
                        break;
                }
@@ -324,11 +335,33 @@ static int strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
        if (cloned_orig)
                kfree_skb(orig_skb);
 
-       STRP_STATS_ADD(strp->stats.rx_bytes, eaten);
+       STRP_STATS_ADD(strp->stats.bytes, eaten);
 
        return eaten;
 }
 
+int strp_process(struct strparser *strp, struct sk_buff *orig_skb,
+                unsigned int orig_offset, size_t orig_len,
+                size_t max_msg_size, long timeo)
+{
+       read_descriptor_t desc; /* Dummy arg to strp_recv */
+
+       desc.arg.data = strp;
+
+       return __strp_recv(&desc, orig_skb, orig_offset, orig_len,
+                          max_msg_size, timeo);
+}
+EXPORT_SYMBOL_GPL(strp_process);
+
+static int strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
+                    unsigned int orig_offset, size_t orig_len)
+{
+       struct strparser *strp = (struct strparser *)desc->arg.data;
+
+       return __strp_recv(desc, orig_skb, orig_offset, orig_len,
+                          strp->sk->sk_rcvbuf, strp->sk->sk_rcvtimeo);
+}
+
 static int default_read_sock_done(struct strparser *strp, int err)
 {
        return err;
@@ -355,101 +388,129 @@ static int strp_read_sock(struct strparser *strp)
 /* Lower sock lock held */
 void strp_data_ready(struct strparser *strp)
 {
-       if (unlikely(strp->rx_stopped))
+       if (unlikely(strp->stopped))
                return;
 
-       /* This check is needed to synchronize with do_strp_rx_work.
-        * do_strp_rx_work acquires a process lock (lock_sock) whereas
+       /* This check is needed to synchronize with do_strp_work.
+        * do_strp_work acquires a process lock (lock_sock) whereas
         * the lock held here is bh_lock_sock. The two locks can be
         * held by different threads at the same time, but bh_lock_sock
         * allows a thread in BH context to safely check if the process
         * lock is held. In this case, if the lock is held, queue work.
         */
        if (sock_owned_by_user(strp->sk)) {
-               queue_work(strp_wq, &strp->rx_work);
+               queue_work(strp_wq, &strp->work);
                return;
        }
 
-       if (strp->rx_paused)
+       if (strp->paused)
                return;
 
-       if (strp->rx_need_bytes) {
-               if (strp_peek_len(strp) >= strp->rx_need_bytes)
-                       strp->rx_need_bytes = 0;
+       if (strp->need_bytes) {
+               if (strp_peek_len(strp) >= strp->need_bytes)
+                       strp->need_bytes = 0;
                else
                        return;
        }
 
        if (strp_read_sock(strp) == -ENOMEM)
-               queue_work(strp_wq, &strp->rx_work);
+               queue_work(strp_wq, &strp->work);
 }
 EXPORT_SYMBOL_GPL(strp_data_ready);
 
-static void do_strp_rx_work(struct strparser *strp)
+static void do_strp_work(struct strparser *strp)
 {
        read_descriptor_t rd_desc;
-       struct sock *csk = strp->sk;
 
        /* We need the read lock to synchronize with strp_data_ready. We
         * need the socket lock for calling strp_read_sock.
         */
-       lock_sock(csk);
+       strp->cb.lock(strp);
 
-       if (unlikely(strp->rx_stopped))
+       if (unlikely(strp->stopped))
                goto out;
 
-       if (strp->rx_paused)
+       if (strp->paused)
                goto out;
 
        rd_desc.arg.data = strp;
 
        if (strp_read_sock(strp) == -ENOMEM)
-               queue_work(strp_wq, &strp->rx_work);
+               queue_work(strp_wq, &strp->work);
 
 out:
-       release_sock(csk);
+       strp->cb.unlock(strp);
 }
 
-static void strp_rx_work(struct work_struct *w)
+static void strp_work(struct work_struct *w)
 {
-       do_strp_rx_work(container_of(w, struct strparser, rx_work));
+       do_strp_work(container_of(w, struct strparser, work));
 }
 
-static void strp_rx_msg_timeout(unsigned long arg)
+static void strp_msg_timeout(unsigned long arg)
 {
        struct strparser *strp = (struct strparser *)arg;
 
        /* Message assembly timed out */
-       STRP_STATS_INCR(strp->stats.rx_msg_timeouts);
-       lock_sock(strp->sk);
+       STRP_STATS_INCR(strp->stats.msg_timeouts);
+       strp->cb.lock(strp);
        strp->cb.abort_parser(strp, ETIMEDOUT);
+       strp->cb.unlock(strp);
+}
+
+static void strp_sock_lock(struct strparser *strp)
+{
+       lock_sock(strp->sk);
+}
+
+static void strp_sock_unlock(struct strparser *strp)
+{
        release_sock(strp->sk);
 }
 
-int strp_init(struct strparser *strp, struct sock *csk,
+int strp_init(struct strparser *strp, struct sock *sk,
              struct strp_callbacks *cb)
 {
-       struct socket *sock = csk->sk_socket;
 
        if (!cb || !cb->rcv_msg || !cb->parse_msg)
                return -EINVAL;
 
-       if (!sock->ops->read_sock || !sock->ops->peek_len)
-               return -EAFNOSUPPORT;
+       /* The sk (sock) arg determines the mode of the stream parser.
+        *
+        * If the sock is set then the strparser is in receive callback mode.
+        * The upper layer calls strp_data_ready to kick receive processing
+        * and strparser calls the read_sock function on the socket to
+        * get packets.
+        *
+        * If the sock is not set then the strparser is in general mode.
+        * The upper layer calls strp_process for each skb to be parsed.
+        */
 
-       memset(strp, 0, sizeof(*strp));
+       if (sk) {
+               struct socket *sock = sk->sk_socket;
 
-       strp->sk = csk;
+               if (!sock->ops->read_sock || !sock->ops->peek_len)
+                       return -EAFNOSUPPORT;
+       } else {
+               if (!cb->lock || !cb->unlock)
+                       return -EINVAL;
+       }
 
-       setup_timer(&strp->rx_msg_timer, strp_rx_msg_timeout,
-                   (unsigned long)strp);
+       memset(strp, 0, sizeof(*strp));
 
-       INIT_WORK(&strp->rx_work, strp_rx_work);
+       strp->sk = sk;
 
+       strp->cb.lock = cb->lock ? : strp_sock_lock;
+       strp->cb.unlock = cb->unlock ? : strp_sock_unlock;
        strp->cb.rcv_msg = cb->rcv_msg;
        strp->cb.parse_msg = cb->parse_msg;
        strp->cb.read_sock_done = cb->read_sock_done ? : default_read_sock_done;
-       strp->cb.abort_parser = cb->abort_parser ? : strp_abort_rx_strp;
+       strp->cb.abort_parser = cb->abort_parser ? : strp_abort_strp;
+
+       setup_timer(&strp->msg_timer, strp_msg_timeout,
+                   (unsigned long)strp);
+
+       INIT_WORK(&strp->work, strp_work);
 
        return 0;
 }
@@ -457,12 +518,12 @@ EXPORT_SYMBOL_GPL(strp_init);
 
 void strp_unpause(struct strparser *strp)
 {
-       strp->rx_paused = 0;
+       strp->paused = 0;
 
-       /* Sync setting rx_paused with RX work */
+       /* Sync setting paused with RX work */
        smp_mb();
 
-       queue_work(strp_wq, &strp->rx_work);
+       queue_work(strp_wq, &strp->work);
 }
 EXPORT_SYMBOL_GPL(strp_unpause);
 
@@ -471,27 +532,27 @@ EXPORT_SYMBOL_GPL(strp_unpause);
  */
 void strp_done(struct strparser *strp)
 {
-       WARN_ON(!strp->rx_stopped);
+       WARN_ON(!strp->stopped);
 
-       del_timer_sync(&strp->rx_msg_timer);
-       cancel_work_sync(&strp->rx_work);
+       del_timer_sync(&strp->msg_timer);
+       cancel_work_sync(&strp->work);
 
-       if (strp->rx_skb_head) {
-               kfree_skb(strp->rx_skb_head);
-               strp->rx_skb_head = NULL;
+       if (strp->skb_head) {
+               kfree_skb(strp->skb_head);
+               strp->skb_head = NULL;
        }
 }
 EXPORT_SYMBOL_GPL(strp_done);
 
 void strp_stop(struct strparser *strp)
 {
-       strp->rx_stopped = 1;
+       strp->stopped = 1;
 }
 EXPORT_SYMBOL_GPL(strp_stop);
 
 void strp_check_rcv(struct strparser *strp)
 {
-       queue_work(strp_wq, &strp->rx_work);
+       queue_work(strp_wq, &strp->work);
 }
 EXPORT_SYMBOL_GPL(strp_check_rcv);
 
index fb39284..12649c9 100644 (file)
@@ -34,6 +34,7 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
+#include <crypto/algapi.h>
 #include <crypto/hash.h>
 #include <crypto/skcipher.h>
 #include <linux/err.h>
@@ -927,7 +928,7 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf,
        if (ret)
                goto out_err;
 
-       if (memcmp(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) {
+       if (crypto_memneq(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) {
                ret = GSS_S_BAD_SIG;
                goto out_err;
        }
index f0c6a8c..46b295e 100644 (file)
@@ -55,15 +55,15 @@ enum {
 #define PROC(proc, name)                               \
 [GSSX_##proc] = {                                      \
        .p_proc   = GSSX_##proc,                        \
-       .p_encode = (kxdreproc_t)gssx_enc_##name,       \
-       .p_decode = (kxdrdproc_t)gssx_dec_##name,       \
+       .p_encode = gssx_enc_##name,    \
+       .p_decode = gssx_dec_##name,    \
        .p_arglen = GSSX_ARG_##name##_sz,               \
        .p_replen = GSSX_RES_##name##_sz,               \
        .p_statidx = GSSX_##proc,                       \
        .p_name   = #proc,                              \
 }
 
-static struct rpc_procinfo gssp_procedures[] = {
+static const struct rpc_procinfo gssp_procedures[] = {
        PROC(INDICATE_MECHS, indicate_mechs),
         PROC(GET_CALL_CONTEXT, get_call_context),
         PROC(IMPORT_AND_CANON_NAME, import_and_canon_name),
@@ -364,11 +364,12 @@ void gssp_free_upcall_data(struct gssp_upcall_data *data)
 /*
  * Initialization stuff
  */
-
+static unsigned int gssp_version1_counts[ARRAY_SIZE(gssp_procedures)];
 static const struct rpc_version gssp_version1 = {
        .number         = GSSPROXY_VERS_1,
        .nrprocs        = ARRAY_SIZE(gssp_procedures),
        .procs          = gssp_procedures,
+       .counts         = gssp_version1_counts,
 };
 
 static const struct rpc_version *gssp_version[] = {
index 25d9a9c..c4778ca 100644 (file)
@@ -44,7 +44,7 @@ static int gssx_dec_bool(struct xdr_stream *xdr, u32 *v)
 }
 
 static int gssx_enc_buffer(struct xdr_stream *xdr,
-                          gssx_buffer *buf)
+                          const gssx_buffer *buf)
 {
        __be32 *p;
 
@@ -56,7 +56,7 @@ static int gssx_enc_buffer(struct xdr_stream *xdr,
 }
 
 static int gssx_enc_in_token(struct xdr_stream *xdr,
-                            struct gssp_in_token *in)
+                            const struct gssp_in_token *in)
 {
        __be32 *p;
 
@@ -130,7 +130,7 @@ static int gssx_dec_option(struct xdr_stream *xdr,
 }
 
 static int dummy_enc_opt_array(struct xdr_stream *xdr,
-                               struct gssx_option_array *oa)
+                               const struct gssx_option_array *oa)
 {
        __be32 *p;
 
@@ -348,7 +348,7 @@ static int gssx_dec_status(struct xdr_stream *xdr,
 }
 
 static int gssx_enc_call_ctx(struct xdr_stream *xdr,
-                            struct gssx_call_ctx *ctx)
+                            const struct gssx_call_ctx *ctx)
 {
        struct gssx_option opt;
        __be32 *p;
@@ -733,8 +733,9 @@ static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb)
 
 void gssx_enc_accept_sec_context(struct rpc_rqst *req,
                                 struct xdr_stream *xdr,
-                                struct gssx_arg_accept_sec_context *arg)
+                                const void *data)
 {
+       const struct gssx_arg_accept_sec_context *arg = data;
        int err;
 
        err = gssx_enc_call_ctx(xdr, &arg->call_ctx);
@@ -789,8 +790,9 @@ done:
 
 int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
                                struct xdr_stream *xdr,
-                               struct gssx_res_accept_sec_context *res)
+                               void *data)
 {
+       struct gssx_res_accept_sec_context *res = data;
        u32 value_follows;
        int err;
        struct page *scratch;
index 9d88c62..146c310 100644 (file)
@@ -179,10 +179,10 @@ struct gssx_res_accept_sec_context {
 #define gssx_dec_init_sec_context NULL
 void gssx_enc_accept_sec_context(struct rpc_rqst *req,
                                 struct xdr_stream *xdr,
-                                struct gssx_arg_accept_sec_context *args);
+                                const void *data);
 int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
                                struct xdr_stream *xdr,
-                               struct gssx_res_accept_sec_context *res);
+                               void *data);
 #define gssx_enc_release_handle NULL
 #define gssx_dec_release_handle NULL
 #define gssx_enc_get_mic NULL
index a54a7a3..7b1ee5a 100644 (file)
@@ -838,6 +838,14 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g
        struct xdr_netobj mic;
        struct xdr_buf integ_buf;
 
+       /* NFS READ normally uses splice to send data in-place. However
+        * the data in cache can change after the reply's MIC is computed
+        * but before the RPC reply is sent. To prevent the client from
+        * rejecting the server-computed MIC in this somewhat rare case,
+        * do not use splice with the GSS integrity service.
+        */
+       clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
+
        /* Did we already verify the signature on the original pass through? */
        if (rqstp->rq_deferred)
                return 0;
index b5cb921..2e49d1f 100644 (file)
@@ -1517,14 +1517,16 @@ static void
 call_start(struct rpc_task *task)
 {
        struct rpc_clnt *clnt = task->tk_client;
+       int idx = task->tk_msg.rpc_proc->p_statidx;
 
        dprintk("RPC: %5u call_start %s%d proc %s (%s)\n", task->tk_pid,
                        clnt->cl_program->name, clnt->cl_vers,
                        rpc_proc_name(task),
                        (RPC_IS_ASYNC(task) ? "async" : "sync"));
 
-       /* Increment call count */
-       task->tk_msg.rpc_proc->p_count++;
+       /* Increment call count (version might not be valid for ping) */
+       if (clnt->cl_program->version[clnt->cl_vers])
+               clnt->cl_program->version[clnt->cl_vers]->counts[idx]++;
        clnt->cl_stats->rpccnt++;
        task->tk_action = call_reserve;
 }
@@ -1672,7 +1674,7 @@ call_allocate(struct rpc_task *task)
        unsigned int slack = task->tk_rqstp->rq_cred->cr_auth->au_cslack;
        struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_xprt *xprt = req->rq_xprt;
-       struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
+       const struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
        int status;
 
        dprint_status(task);
@@ -2476,16 +2478,18 @@ out_overflow:
        goto out_garbage;
 }
 
-static void rpcproc_encode_null(void *rqstp, struct xdr_stream *xdr, void *obj)
+static void rpcproc_encode_null(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+               const void *obj)
 {
 }
 
-static int rpcproc_decode_null(void *rqstp, struct xdr_stream *xdr, void *obj)
+static int rpcproc_decode_null(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+               void *obj)
 {
        return 0;
 }
 
-static struct rpc_procinfo rpcproc_null = {
+static const struct rpc_procinfo rpcproc_null = {
        .p_encode = rpcproc_encode_null,
        .p_decode = rpcproc_decode_null,
 };
index 5b30603..ea0676f 100644 (file)
@@ -128,13 +128,13 @@ struct rpcbind_args {
        int                     r_status;
 };
 
-static struct rpc_procinfo rpcb_procedures2[];
-static struct rpc_procinfo rpcb_procedures3[];
-static struct rpc_procinfo rpcb_procedures4[];
+static const struct rpc_procinfo rpcb_procedures2[];
+static const struct rpc_procinfo rpcb_procedures3[];
+static const struct rpc_procinfo rpcb_procedures4[];
 
 struct rpcb_info {
        u32                     rpc_vers;
-       struct rpc_procinfo *   rpc_proc;
+       const struct rpc_procinfo *rpc_proc;
 };
 
 static const struct rpcb_info rpcb_next_version[];
@@ -620,7 +620,8 @@ int rpcb_v4_register(struct net *net, const u32 program, const u32 version,
        return -EAFNOSUPPORT;
 }
 
-static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, struct rpc_procinfo *proc)
+static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt,
+               struct rpcbind_args *map, const struct rpc_procinfo *proc)
 {
        struct rpc_message msg = {
                .rpc_proc = proc,
@@ -671,7 +672,7 @@ static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt)
 void rpcb_getport_async(struct rpc_task *task)
 {
        struct rpc_clnt *clnt;
-       struct rpc_procinfo *proc;
+       const struct rpc_procinfo *proc;
        u32 bind_version;
        struct rpc_xprt *xprt;
        struct rpc_clnt *rpcb_clnt;
@@ -843,8 +844,9 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
  */
 
 static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr,
-                            const struct rpcbind_args *rpcb)
+                            const void *data)
 {
+       const struct rpcbind_args *rpcb = data;
        __be32 *p;
 
        dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n",
@@ -860,8 +862,9 @@ static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr,
 }
 
 static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr,
-                           struct rpcbind_args *rpcb)
+                           void *data)
 {
+       struct rpcbind_args *rpcb = data;
        unsigned long port;
        __be32 *p;
 
@@ -882,8 +885,9 @@ static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr,
 }
 
 static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr,
-                       unsigned int *boolp)
+                       void *data)
 {
+       unsigned int *boolp = data;
        __be32 *p;
 
        p = xdr_inline_decode(xdr, 4);
@@ -917,8 +921,9 @@ static void encode_rpcb_string(struct xdr_stream *xdr, const char *string,
 }
 
 static void rpcb_enc_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
-                            const struct rpcbind_args *rpcb)
+                            const void *data)
 {
+       const struct rpcbind_args *rpcb = data;
        __be32 *p;
 
        dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n",
@@ -937,8 +942,9 @@ static void rpcb_enc_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
 }
 
 static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
-                           struct rpcbind_args *rpcb)
+                           void *data)
 {
+       struct rpcbind_args *rpcb = data;
        struct sockaddr_storage address;
        struct sockaddr *sap = (struct sockaddr *)&address;
        __be32 *p;
@@ -989,11 +995,11 @@ out_fail:
  * since the Linux kernel RPC code requires only these.
  */
 
-static struct rpc_procinfo rpcb_procedures2[] = {
+static const struct rpc_procinfo rpcb_procedures2[] = {
        [RPCBPROC_SET] = {
                .p_proc         = RPCBPROC_SET,
-               .p_encode       = (kxdreproc_t)rpcb_enc_mapping,
-               .p_decode       = (kxdrdproc_t)rpcb_dec_set,
+               .p_encode       = rpcb_enc_mapping,
+               .p_decode       = rpcb_dec_set,
                .p_arglen       = RPCB_mappingargs_sz,
                .p_replen       = RPCB_setres_sz,
                .p_statidx      = RPCBPROC_SET,
@@ -1002,8 +1008,8 @@ static struct rpc_procinfo rpcb_procedures2[] = {
        },
        [RPCBPROC_UNSET] = {
                .p_proc         = RPCBPROC_UNSET,
-               .p_encode       = (kxdreproc_t)rpcb_enc_mapping,
-               .p_decode       = (kxdrdproc_t)rpcb_dec_set,
+               .p_encode       = rpcb_enc_mapping,
+               .p_decode       = rpcb_dec_set,
                .p_arglen       = RPCB_mappingargs_sz,
                .p_replen       = RPCB_setres_sz,
                .p_statidx      = RPCBPROC_UNSET,
@@ -1012,8 +1018,8 @@ static struct rpc_procinfo rpcb_procedures2[] = {
        },
        [RPCBPROC_GETPORT] = {
                .p_proc         = RPCBPROC_GETPORT,
-               .p_encode       = (kxdreproc_t)rpcb_enc_mapping,
-               .p_decode       = (kxdrdproc_t)rpcb_dec_getport,
+               .p_encode       = rpcb_enc_mapping,
+               .p_decode       = rpcb_dec_getport,
                .p_arglen       = RPCB_mappingargs_sz,
                .p_replen       = RPCB_getportres_sz,
                .p_statidx      = RPCBPROC_GETPORT,
@@ -1022,11 +1028,11 @@ static struct rpc_procinfo rpcb_procedures2[] = {
        },
 };
 
-static struct rpc_procinfo rpcb_procedures3[] = {
+static const struct rpc_procinfo rpcb_procedures3[] = {
        [RPCBPROC_SET] = {
                .p_proc         = RPCBPROC_SET,
-               .p_encode       = (kxdreproc_t)rpcb_enc_getaddr,
-               .p_decode       = (kxdrdproc_t)rpcb_dec_set,
+               .p_encode       = rpcb_enc_getaddr,
+               .p_decode       = rpcb_dec_set,
                .p_arglen       = RPCB_getaddrargs_sz,
                .p_replen       = RPCB_setres_sz,
                .p_statidx      = RPCBPROC_SET,
@@ -1035,8 +1041,8 @@ static struct rpc_procinfo rpcb_procedures3[] = {
        },
        [RPCBPROC_UNSET] = {
                .p_proc         = RPCBPROC_UNSET,
-               .p_encode       = (kxdreproc_t)rpcb_enc_getaddr,
-               .p_decode       = (kxdrdproc_t)rpcb_dec_set,
+               .p_encode       = rpcb_enc_getaddr,
+               .p_decode       = rpcb_dec_set,
                .p_arglen       = RPCB_getaddrargs_sz,
                .p_replen       = RPCB_setres_sz,
                .p_statidx      = RPCBPROC_UNSET,
@@ -1045,8 +1051,8 @@ static struct rpc_procinfo rpcb_procedures3[] = {
        },
        [RPCBPROC_GETADDR] = {
                .p_proc         = RPCBPROC_GETADDR,
-               .p_encode       = (kxdreproc_t)rpcb_enc_getaddr,
-               .p_decode       = (kxdrdproc_t)rpcb_dec_getaddr,
+               .p_encode       = rpcb_enc_getaddr,
+               .p_decode       = rpcb_dec_getaddr,
                .p_arglen       = RPCB_getaddrargs_sz,
                .p_replen       = RPCB_getaddrres_sz,
                .p_statidx      = RPCBPROC_GETADDR,
@@ -1055,11 +1061,11 @@ static struct rpc_procinfo rpcb_procedures3[] = {
        },
 };
 
-static struct rpc_procinfo rpcb_procedures4[] = {
+static const struct rpc_procinfo rpcb_procedures4[] = {
        [RPCBPROC_SET] = {
                .p_proc         = RPCBPROC_SET,
-               .p_encode       = (kxdreproc_t)rpcb_enc_getaddr,
-               .p_decode       = (kxdrdproc_t)rpcb_dec_set,
+               .p_encode       = rpcb_enc_getaddr,
+               .p_decode       = rpcb_dec_set,
                .p_arglen       = RPCB_getaddrargs_sz,
                .p_replen       = RPCB_setres_sz,
                .p_statidx      = RPCBPROC_SET,
@@ -1068,8 +1074,8 @@ static struct rpc_procinfo rpcb_procedures4[] = {
        },
        [RPCBPROC_UNSET] = {
                .p_proc         = RPCBPROC_UNSET,
-               .p_encode       = (kxdreproc_t)rpcb_enc_getaddr,
-               .p_decode       = (kxdrdproc_t)rpcb_dec_set,
+               .p_encode       = rpcb_enc_getaddr,
+               .p_decode       = rpcb_dec_set,
                .p_arglen       = RPCB_getaddrargs_sz,
                .p_replen       = RPCB_setres_sz,
                .p_statidx      = RPCBPROC_UNSET,
@@ -1078,8 +1084,8 @@ static struct rpc_procinfo rpcb_procedures4[] = {
        },
        [RPCBPROC_GETADDR] = {
                .p_proc         = RPCBPROC_GETADDR,
-               .p_encode       = (kxdreproc_t)rpcb_enc_getaddr,
-               .p_decode       = (kxdrdproc_t)rpcb_dec_getaddr,
+               .p_encode       = rpcb_enc_getaddr,
+               .p_decode       = rpcb_dec_getaddr,
                .p_arglen       = RPCB_getaddrargs_sz,
                .p_replen       = RPCB_getaddrres_sz,
                .p_statidx      = RPCBPROC_GETADDR,
@@ -1112,22 +1118,28 @@ static const struct rpcb_info rpcb_next_version6[] = {
        },
 };
 
+static unsigned int rpcb_version2_counts[ARRAY_SIZE(rpcb_procedures2)];
 static const struct rpc_version rpcb_version2 = {
        .number         = RPCBVERS_2,
        .nrprocs        = ARRAY_SIZE(rpcb_procedures2),
-       .procs          = rpcb_procedures2
+       .procs          = rpcb_procedures2,
+       .counts         = rpcb_version2_counts,
 };
 
+static unsigned int rpcb_version3_counts[ARRAY_SIZE(rpcb_procedures3)];
 static const struct rpc_version rpcb_version3 = {
        .number         = RPCBVERS_3,
        .nrprocs        = ARRAY_SIZE(rpcb_procedures3),
-       .procs          = rpcb_procedures3
+       .procs          = rpcb_procedures3,
+       .counts         = rpcb_version3_counts,
 };
 
+static unsigned int rpcb_version4_counts[ARRAY_SIZE(rpcb_procedures4)];
 static const struct rpc_version rpcb_version4 = {
        .number         = RPCBVERS_4,
        .nrprocs        = ARRAY_SIZE(rpcb_procedures4),
-       .procs          = rpcb_procedures4
+       .procs          = rpcb_procedures4,
+       .counts         = rpcb_version4_counts,
 };
 
 static const struct rpc_version *rpcb_version[] = {
index caeb01a..1e67133 100644 (file)
@@ -55,8 +55,7 @@ static int rpc_proc_show(struct seq_file *seq, void *v) {
                seq_printf(seq, "proc%u %u",
                                        vers->number, vers->nrprocs);
                for (j = 0; j < vers->nrprocs; j++)
-                       seq_printf(seq, " %u",
-                                       vers->procs[j].p_count);
+                       seq_printf(seq, " %u", vers->counts[j]);
                seq_putc(seq, '\n');
        }
        return 0;
@@ -78,9 +77,9 @@ static const struct file_operations rpc_proc_fops = {
 /*
  * Get RPC server stats
  */
-void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
+void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp)
+{
        const struct svc_program *prog = statp->program;
-       const struct svc_procedure *proc;
        const struct svc_version *vers;
        unsigned int i, j;
 
@@ -99,11 +98,12 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
                        statp->rpcbadclnt);
 
        for (i = 0; i < prog->pg_nvers; i++) {
-               if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc))
+               vers = prog->pg_vers[i];
+               if (!vers)
                        continue;
                seq_printf(seq, "proc%d %u", i, vers->vs_nproc);
-               for (j = 0; j < vers->vs_nproc; j++, proc++)
-                       seq_printf(seq, " %u", proc->pc_count);
+               for (j = 0; j < vers->vs_nproc; j++)
+                       seq_printf(seq, " %u", vers->vs_count[j]);
                seq_putc(seq, '\n');
        }
 }
@@ -192,7 +192,7 @@ void rpc_count_iostats(const struct rpc_task *task, struct rpc_iostats *stats)
 EXPORT_SYMBOL_GPL(rpc_count_iostats);
 
 static void _print_name(struct seq_file *seq, unsigned int op,
-                       struct rpc_procinfo *procs)
+                       const struct rpc_procinfo *procs)
 {
        if (procs[op].p_name)
                seq_printf(seq, "\t%12s: ", procs[op].p_name);
index bc0f5a0..85ce0db 100644 (file)
@@ -1008,7 +1008,7 @@ int svc_register(const struct svc_serv *serv, struct net *net,
                 const unsigned short port)
 {
        struct svc_program      *progp;
-       struct svc_version      *vers;
+       const struct svc_version *vers;
        unsigned int            i;
        int                     error = 0;
 
@@ -1151,10 +1151,9 @@ static int
 svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
 {
        struct svc_program      *progp;
-       struct svc_version      *versp = NULL;  /* compiler food */
-       struct svc_procedure    *procp = NULL;
+       const struct svc_version *versp = NULL; /* compiler food */
+       const struct svc_procedure *procp = NULL;
        struct svc_serv         *serv = rqstp->rq_server;
-       kxdrproc_t              xdr;
        __be32                  *statp;
        u32                     prog, vers, proc;
        __be32                  auth_stat, rpc_stat;
@@ -1166,7 +1165,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        if (argv->iov_len < 6*4)
                goto err_short_len;
 
-       /* Will be turned off only in gss privacy case: */
+       /* Will be turned off by GSS integrity and privacy services */
        set_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
        /* Will be turned off only when NFSv4 Sessions are used */
        set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
@@ -1262,7 +1261,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        svc_putnl(resv, RPC_SUCCESS);
 
        /* Bump per-procedure stats counter */
-       procp->pc_count++;
+       versp->vs_count[proc]++;
 
        /* Initialize storage for argp and resp */
        memset(rqstp->rq_argp, 0, procp->pc_argsize);
@@ -1276,28 +1275,30 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
 
        /* Call the function that processes the request. */
        if (!versp->vs_dispatch) {
-               /* Decode arguments */
-               xdr = procp->pc_decode;
-               if (xdr && !xdr(rqstp, argv->iov_base, rqstp->rq_argp))
+               /*
+                * Decode arguments
+                * XXX: why do we ignore the return value?
+                */
+               if (procp->pc_decode &&
+                   !procp->pc_decode(rqstp, argv->iov_base))
                        goto err_garbage;
 
-               *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
+               *statp = procp->pc_func(rqstp);
 
                /* Encode reply */
                if (*statp == rpc_drop_reply ||
                    test_bit(RQ_DROPME, &rqstp->rq_flags)) {
                        if (procp->pc_release)
-                               procp->pc_release(rqstp, NULL, rqstp->rq_resp);
+                               procp->pc_release(rqstp);
                        goto dropit;
                }
                if (*statp == rpc_autherr_badcred) {
                        if (procp->pc_release)
-                               procp->pc_release(rqstp, NULL, rqstp->rq_resp);
+                               procp->pc_release(rqstp);
                        goto err_bad_auth;
                }
-               if (*statp == rpc_success &&
-                   (xdr = procp->pc_encode) &&
-                   !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) {
+               if (*statp == rpc_success && procp->pc_encode &&
+                   !procp->pc_encode(rqstp, resv->iov_base + resv->iov_len)) {
                        dprintk("svc: failed to encode reply\n");
                        /* serv->sv_stats->rpcsystemerr++; */
                        *statp = rpc_system_err;
@@ -1307,7 +1308,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
                if (!versp->vs_dispatch(rqstp, statp)) {
                        /* Release reply info */
                        if (procp->pc_release)
-                               procp->pc_release(rqstp, NULL, rqstp->rq_resp);
+                               procp->pc_release(rqstp);
                        goto dropit;
                }
        }
@@ -1318,7 +1319,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
 
        /* Release reply info */
        if (procp->pc_release)
-               procp->pc_release(rqstp, NULL, rqstp->rq_resp);
+               procp->pc_release(rqstp);
 
        if (procp->pc_encode == NULL)
                goto dropit;
index 7bfe1fb..d16a8b4 100644 (file)
@@ -659,11 +659,13 @@ static int svc_alloc_arg(struct svc_rqst *rqstp)
        int i;
 
        /* now allocate needed pages.  If we get a failure, sleep briefly */
-       pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
-       WARN_ON_ONCE(pages >= RPCSVC_MAXPAGES);
-       if (pages >= RPCSVC_MAXPAGES)
+       pages = (serv->sv_max_mesg + 2 * PAGE_SIZE) >> PAGE_SHIFT;
+       if (pages > RPCSVC_MAXPAGES) {
+               pr_warn_once("svc: warning: pages=%u > RPCSVC_MAXPAGES=%lu\n",
+                            pages, RPCSVC_MAXPAGES);
                /* use as many pages as possible */
-               pages = RPCSVC_MAXPAGES - 1;
+               pages = RPCSVC_MAXPAGES;
+       }
        for (i = 0; i < pages ; i++)
                while (rqstp->rq_pages[i] == NULL) {
                        struct page *p = alloc_page(GFP_KERNEL);
index 3e63c5e..4654a99 100644 (file)
@@ -1047,13 +1047,15 @@ out:
        return ret;
 }
 
-static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt, gfp_t gfp_flags)
+static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt)
 {
        struct rpc_rqst *req = ERR_PTR(-EAGAIN);
 
        if (!atomic_add_unless(&xprt->num_reqs, 1, xprt->max_reqs))
                goto out;
-       req = kzalloc(sizeof(struct rpc_rqst), gfp_flags);
+       spin_unlock(&xprt->reserve_lock);
+       req = kzalloc(sizeof(struct rpc_rqst), GFP_NOFS);
+       spin_lock(&xprt->reserve_lock);
        if (req != NULL)
                goto out;
        atomic_dec(&xprt->num_reqs);
@@ -1081,7 +1083,7 @@ void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
                list_del(&req->rq_list);
                goto out_init_req;
        }
-       req = xprt_dynamic_alloc_slot(xprt, GFP_NOWAIT|__GFP_NOWARN);
+       req = xprt_dynamic_alloc_slot(xprt);
        if (!IS_ERR(req))
                goto out_init_req;
        switch (PTR_ERR(req)) {
index c1ae814..b8213dd 100644 (file)
@@ -3,6 +3,6 @@ obj-$(CONFIG_SUNRPC_XPRT_RDMA) += rpcrdma.o
 rpcrdma-y := transport.o rpc_rdma.o verbs.o \
        fmr_ops.o frwr_ops.o \
        svc_rdma.o svc_rdma_backchannel.o svc_rdma_transport.o \
-       svc_rdma_marshal.o svc_rdma_sendto.o svc_rdma_recvfrom.o \
-       svc_rdma_rw.o module.o
+       svc_rdma_sendto.o svc_rdma_recvfrom.o svc_rdma_rw.o \
+       module.o
 rpcrdma-$(CONFIG_SUNRPC_BACKCHANNEL) += backchannel.o
index 59e6402..d3f84bb 100644 (file)
@@ -91,7 +91,7 @@ __fmr_unmap(struct rpcrdma_mw *mw)
 
        list_add(&mw->fmr.fm_mr->list, &l);
        rc = ib_unmap_fmr(&l);
-       list_del_init(&mw->fmr.fm_mr->list);
+       list_del(&mw->fmr.fm_mr->list);
        return rc;
 }
 
@@ -213,13 +213,11 @@ fmr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
                    offset_in_page((seg-1)->mr_offset + (seg-1)->mr_len))
                        break;
        }
-       mw->mw_nents = i;
        mw->mw_dir = rpcrdma_data_dir(writing);
-       if (i == 0)
-               goto out_dmamap_err;
 
-       if (!ib_dma_map_sg(r_xprt->rx_ia.ri_device,
-                          mw->mw_sg, mw->mw_nents, mw->mw_dir))
+       mw->mw_nents = ib_dma_map_sg(r_xprt->rx_ia.ri_device,
+                                    mw->mw_sg, i, mw->mw_dir);
+       if (!mw->mw_nents)
                goto out_dmamap_err;
 
        for (i = 0, dma_pages = mw->fmr.fm_physaddrs; i < mw->mw_nents; i++)
@@ -237,16 +235,18 @@ fmr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
        return mw->mw_nents;
 
 out_dmamap_err:
-       pr_err("rpcrdma: failed to dma map sg %p sg_nents %u\n",
-              mw->mw_sg, mw->mw_nents);
-       rpcrdma_defer_mr_recovery(mw);
+       pr_err("rpcrdma: failed to DMA map sg %p sg_nents %d\n",
+              mw->mw_sg, i);
+       rpcrdma_put_mw(r_xprt, mw);
        return -EIO;
 
 out_maperr:
        pr_err("rpcrdma: ib_map_phys_fmr %u@0x%llx+%i (%d) status %i\n",
               len, (unsigned long long)dma_pages[0],
               pageoff, mw->mw_nents, rc);
-       rpcrdma_defer_mr_recovery(mw);
+       ib_dma_unmap_sg(r_xprt->rx_ia.ri_device,
+                       mw->mw_sg, mw->mw_nents, mw->mw_dir);
+       rpcrdma_put_mw(r_xprt, mw);
        return -EIO;
 }
 
@@ -255,24 +255,26 @@ out_maperr:
  * Sleeps until it is safe for the host CPU to access the
  * previously mapped memory regions.
  *
- * Caller ensures that req->rl_registered is not empty.
+ * Caller ensures that @mws is not empty before the call. This
+ * function empties the list.
  */
 static void
-fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
+fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mws)
 {
-       struct rpcrdma_mw *mw, *tmp;
+       struct rpcrdma_mw *mw;
        LIST_HEAD(unmap_list);
        int rc;
 
-       dprintk("RPC:       %s: req %p\n", __func__, req);
-
        /* ORDER: Invalidate all of the req's MRs first
         *
         * ib_unmap_fmr() is slow, so use a single call instead
         * of one call per mapped FMR.
         */
-       list_for_each_entry(mw, &req->rl_registered, mw_list)
+       list_for_each_entry(mw, mws, mw_list) {
+               dprintk("RPC:       %s: unmapping fmr %p\n",
+                       __func__, &mw->fmr);
                list_add_tail(&mw->fmr.fm_mr->list, &unmap_list);
+       }
        r_xprt->rx_stats.local_inv_needed++;
        rc = ib_unmap_fmr(&unmap_list);
        if (rc)
@@ -281,9 +283,11 @@ fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
        /* ORDER: Now DMA unmap all of the req's MRs, and return
         * them to the free MW list.
         */
-       list_for_each_entry_safe(mw, tmp, &req->rl_registered, mw_list) {
-               list_del_init(&mw->mw_list);
-               list_del_init(&mw->fmr.fm_mr->list);
+       while (!list_empty(mws)) {
+               mw = rpcrdma_pop_mw(mws);
+               dprintk("RPC:       %s: DMA unmapping fmr %p\n",
+                       __func__, &mw->fmr);
+               list_del(&mw->fmr.fm_mr->list);
                ib_dma_unmap_sg(r_xprt->rx_ia.ri_device,
                                mw->mw_sg, mw->mw_nents, mw->mw_dir);
                rpcrdma_put_mw(r_xprt, mw);
@@ -294,8 +298,9 @@ fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
 out_reset:
        pr_err("rpcrdma: ib_unmap_fmr failed (%i)\n", rc);
 
-       list_for_each_entry_safe(mw, tmp, &req->rl_registered, mw_list) {
-               list_del_init(&mw->fmr.fm_mr->list);
+       while (!list_empty(mws)) {
+               mw = rpcrdma_pop_mw(mws);
+               list_del(&mw->fmr.fm_mr->list);
                fmr_op_recover_mr(mw);
        }
 }
index f81dd93..6aea36a 100644 (file)
@@ -277,7 +277,7 @@ __frwr_sendcompletion_flush(struct ib_wc *wc, const char *wr)
 }
 
 /**
- * frwr_wc_fastreg - Invoked by RDMA provider for each polled FastReg WC
+ * frwr_wc_fastreg - Invoked by RDMA provider for a flushed FastReg WC
  * @cq:        completion queue (ignored)
  * @wc:        completed WR
  *
@@ -298,7 +298,7 @@ frwr_wc_fastreg(struct ib_cq *cq, struct ib_wc *wc)
 }
 
 /**
- * frwr_wc_localinv - Invoked by RDMA provider for each polled LocalInv WC
+ * frwr_wc_localinv - Invoked by RDMA provider for a flushed LocalInv WC
  * @cq:        completion queue (ignored)
  * @wc:        completed WR
  *
@@ -319,7 +319,7 @@ frwr_wc_localinv(struct ib_cq *cq, struct ib_wc *wc)
 }
 
 /**
- * frwr_wc_localinv - Invoked by RDMA provider for each polled LocalInv WC
+ * frwr_wc_localinv_wake - Invoked by RDMA provider for a signaled LocalInv WC
  * @cq:        completion queue (ignored)
  * @wc:        completed WR
  *
@@ -355,7 +355,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
        struct ib_mr *mr;
        struct ib_reg_wr *reg_wr;
        struct ib_send_wr *bad_wr;
-       int rc, i, n, dma_nents;
+       int rc, i, n;
        u8 key;
 
        mw = NULL;
@@ -391,14 +391,10 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
                    offset_in_page((seg-1)->mr_offset + (seg-1)->mr_len))
                        break;
        }
-       mw->mw_nents = i;
        mw->mw_dir = rpcrdma_data_dir(writing);
-       if (i == 0)
-               goto out_dmamap_err;
 
-       dma_nents = ib_dma_map_sg(ia->ri_device,
-                                 mw->mw_sg, mw->mw_nents, mw->mw_dir);
-       if (!dma_nents)
+       mw->mw_nents = ib_dma_map_sg(ia->ri_device, mw->mw_sg, i, mw->mw_dir);
+       if (!mw->mw_nents)
                goto out_dmamap_err;
 
        n = ib_map_mr_sg(mr, mw->mw_sg, mw->mw_nents, NULL, PAGE_SIZE);
@@ -436,13 +432,14 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
        return mw->mw_nents;
 
 out_dmamap_err:
-       pr_err("rpcrdma: failed to dma map sg %p sg_nents %u\n",
-              mw->mw_sg, mw->mw_nents);
-       rpcrdma_defer_mr_recovery(mw);
+       pr_err("rpcrdma: failed to DMA map sg %p sg_nents %d\n",
+              mw->mw_sg, i);
+       frmr->fr_state = FRMR_IS_INVALID;
+       rpcrdma_put_mw(r_xprt, mw);
        return -EIO;
 
 out_mapmr_err:
-       pr_err("rpcrdma: failed to map mr %p (%u/%u)\n",
+       pr_err("rpcrdma: failed to map mr %p (%d/%d)\n",
               frmr->fr_mr, n, mw->mw_nents);
        rpcrdma_defer_mr_recovery(mw);
        return -EIO;
@@ -458,21 +455,19 @@ out_senderr:
  * Sleeps until it is safe for the host CPU to access the
  * previously mapped memory regions.
  *
- * Caller ensures that req->rl_registered is not empty.
+ * Caller ensures that @mws is not empty before the call. This
+ * function empties the list.
  */
 static void
-frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
+frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mws)
 {
        struct ib_send_wr *first, **prev, *last, *bad_wr;
-       struct rpcrdma_rep *rep = req->rl_reply;
        struct rpcrdma_ia *ia = &r_xprt->rx_ia;
        struct rpcrdma_frmr *f;
        struct rpcrdma_mw *mw;
        int count, rc;
 
-       dprintk("RPC:       %s: req %p\n", __func__, req);
-
-       /* ORDER: Invalidate all of the req's MRs first
+       /* ORDER: Invalidate all of the MRs first
         *
         * Chain the LOCAL_INV Work Requests and post them with
         * a single ib_post_send() call.
@@ -480,11 +475,10 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
        f = NULL;
        count = 0;
        prev = &first;
-       list_for_each_entry(mw, &req->rl_registered, mw_list) {
+       list_for_each_entry(mw, mws, mw_list) {
                mw->frmr.fr_state = FRMR_IS_INVALID;
 
-               if ((rep->rr_wc_flags & IB_WC_WITH_INVALIDATE) &&
-                   (mw->mw_handle == rep->rr_inv_rkey))
+               if (mw->mw_flags & RPCRDMA_MW_F_RI)
                        continue;
 
                f = &mw->frmr;
@@ -524,18 +518,19 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
         * unless ri_id->qp is a valid pointer.
         */
        r_xprt->rx_stats.local_inv_needed++;
+       bad_wr = NULL;
        rc = ib_post_send(ia->ri_id->qp, first, &bad_wr);
+       if (bad_wr != first)
+               wait_for_completion(&f->fr_linv_done);
        if (rc)
                goto reset_mrs;
 
-       wait_for_completion(&f->fr_linv_done);
-
-       /* ORDER: Now DMA unmap all of the req's MRs, and return
+       /* ORDER: Now DMA unmap all of the MRs, and return
         * them to the free MW list.
         */
 unmap:
-       while (!list_empty(&req->rl_registered)) {
-               mw = rpcrdma_pop_mw(&req->rl_registered);
+       while (!list_empty(mws)) {
+               mw = rpcrdma_pop_mw(mws);
                dprintk("RPC:       %s: DMA unmapping frmr %p\n",
                        __func__, &mw->frmr);
                ib_dma_unmap_sg(ia->ri_device,
@@ -546,17 +541,19 @@ unmap:
 
 reset_mrs:
        pr_err("rpcrdma: FRMR invalidate ib_post_send returned %i\n", rc);
-       rdma_disconnect(ia->ri_id);
 
        /* Find and reset the MRs in the LOCAL_INV WRs that did not
-        * get posted. This is synchronous, and slow.
+        * get posted.
         */
-       list_for_each_entry(mw, &req->rl_registered, mw_list) {
-               f = &mw->frmr;
-               if (mw->mw_handle == bad_wr->ex.invalidate_rkey) {
-                       __frwr_reset_mr(ia, mw);
-                       bad_wr = bad_wr->next;
-               }
+       rpcrdma_init_cqcount(&r_xprt->rx_ep, -count);
+       while (bad_wr) {
+               f = container_of(bad_wr, struct rpcrdma_frmr,
+                                fr_invwr);
+               mw = container_of(f, struct rpcrdma_mw, frmr);
+
+               __frwr_reset_mr(ia, mw);
+
+               bad_wr = bad_wr->next;
        }
        goto unmap;
 }
index 694e9b1..ca4d6e4 100644 (file)
@@ -141,7 +141,7 @@ static bool rpcrdma_args_inline(struct rpcrdma_xprt *r_xprt,
 
        if (xdr->page_len) {
                remaining = xdr->page_len;
-               offset = xdr->page_base & ~PAGE_MASK;
+               offset = offset_in_page(xdr->page_base);
                count = 0;
                while (remaining) {
                        remaining -= min_t(unsigned int,
@@ -222,7 +222,7 @@ rpcrdma_convert_iovs(struct rpcrdma_xprt *r_xprt, struct xdr_buf *xdrbuf,
 
        len = xdrbuf->page_len;
        ppages = xdrbuf->pages + (xdrbuf->page_base >> PAGE_SHIFT);
-       page_base = xdrbuf->page_base & ~PAGE_MASK;
+       page_base = offset_in_page(xdrbuf->page_base);
        p = 0;
        while (len && n < RPCRDMA_MAX_SEGS) {
                if (!ppages[p]) {
@@ -540,7 +540,7 @@ rpcrdma_prepare_msg_sges(struct rpcrdma_ia *ia, struct rpcrdma_req *req,
                        goto out;
 
                page = virt_to_page(xdr->tail[0].iov_base);
-               page_base = (unsigned long)xdr->tail[0].iov_base & ~PAGE_MASK;
+               page_base = offset_in_page(xdr->tail[0].iov_base);
 
                /* If the content in the page list is an odd length,
                 * xdr_write_pages() has added a pad at the beginning
@@ -557,7 +557,7 @@ rpcrdma_prepare_msg_sges(struct rpcrdma_ia *ia, struct rpcrdma_req *req,
         */
        if (xdr->page_len) {
                ppages = xdr->pages + (xdr->page_base >> PAGE_SHIFT);
-               page_base = xdr->page_base & ~PAGE_MASK;
+               page_base = offset_in_page(xdr->page_base);
                remaining = xdr->page_len;
                while (remaining) {
                        sge_no++;
@@ -587,7 +587,7 @@ rpcrdma_prepare_msg_sges(struct rpcrdma_ia *ia, struct rpcrdma_req *req,
         */
        if (xdr->tail[0].iov_len) {
                page = virt_to_page(xdr->tail[0].iov_base);
-               page_base = (unsigned long)xdr->tail[0].iov_base & ~PAGE_MASK;
+               page_base = offset_in_page(xdr->tail[0].iov_base);
                len = xdr->tail[0].iov_len;
 
 map_tail:
@@ -734,6 +734,9 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst)
                rpclen = 0;
        }
 
+       req->rl_xid = rqst->rq_xid;
+       rpcrdma_insert_req(&r_xprt->rx_buf, req);
+
        /* This implementation supports the following combinations
         * of chunk lists in one RPC-over-RDMA Call message:
         *
@@ -875,9 +878,9 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
        srcp += curlen;
        copy_len -= curlen;
 
-       page_base = rqst->rq_rcv_buf.page_base;
-       ppages = rqst->rq_rcv_buf.pages + (page_base >> PAGE_SHIFT);
-       page_base &= ~PAGE_MASK;
+       ppages = rqst->rq_rcv_buf.pages +
+               (rqst->rq_rcv_buf.page_base >> PAGE_SHIFT);
+       page_base = offset_in_page(rqst->rq_rcv_buf.page_base);
        fixup_copy_count = 0;
        if (copy_len && rqst->rq_rcv_buf.page_len) {
                int pagelist_len;
@@ -928,6 +931,24 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
        return fixup_copy_count;
 }
 
+/* Caller must guarantee @rep remains stable during this call.
+ */
+static void
+rpcrdma_mark_remote_invalidation(struct list_head *mws,
+                                struct rpcrdma_rep *rep)
+{
+       struct rpcrdma_mw *mw;
+
+       if (!(rep->rr_wc_flags & IB_WC_WITH_INVALIDATE))
+               return;
+
+       list_for_each_entry(mw, mws, mw_list)
+               if (mw->mw_handle == rep->rr_inv_rkey) {
+                       mw->mw_flags = RPCRDMA_MW_F_RI;
+                       break; /* only one invalidated MR per RPC */
+               }
+}
+
 #if defined(CONFIG_SUNRPC_BACKCHANNEL)
 /* By convention, backchannel calls arrive via rdma_msg type
  * messages, and never populate the chunk lists. This makes
@@ -969,14 +990,16 @@ rpcrdma_reply_handler(struct work_struct *work)
 {
        struct rpcrdma_rep *rep =
                        container_of(work, struct rpcrdma_rep, rr_work);
+       struct rpcrdma_xprt *r_xprt = rep->rr_rxprt;
+       struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
+       struct rpc_xprt *xprt = &r_xprt->rx_xprt;
        struct rpcrdma_msg *headerp;
        struct rpcrdma_req *req;
        struct rpc_rqst *rqst;
-       struct rpcrdma_xprt *r_xprt = rep->rr_rxprt;
-       struct rpc_xprt *xprt = &r_xprt->rx_xprt;
        __be32 *iptr;
        int rdmalen, status, rmerr;
        unsigned long cwnd;
+       struct list_head mws;
 
        dprintk("RPC:       %s: incoming rep %p\n", __func__, rep);
 
@@ -994,27 +1017,45 @@ rpcrdma_reply_handler(struct work_struct *work)
        /* Match incoming rpcrdma_rep to an rpcrdma_req to
         * get context for handling any incoming chunks.
         */
-       spin_lock_bh(&xprt->transport_lock);
-       rqst = xprt_lookup_rqst(xprt, headerp->rm_xid);
-       if (!rqst)
+       spin_lock(&buf->rb_lock);
+       req = rpcrdma_lookup_req_locked(&r_xprt->rx_buf,
+                                       headerp->rm_xid);
+       if (!req)
                goto out_nomatch;
-
-       req = rpcr_to_rdmar(rqst);
        if (req->rl_reply)
                goto out_duplicate;
 
-       /* Sanity checking has passed. We are now committed
-        * to complete this transaction.
+       list_replace_init(&req->rl_registered, &mws);
+       rpcrdma_mark_remote_invalidation(&mws, rep);
+
+       /* Avoid races with signals and duplicate replies
+        * by marking this req as matched.
         */
-       list_del_init(&rqst->rq_list);
-       spin_unlock_bh(&xprt->transport_lock);
+       req->rl_reply = rep;
+       spin_unlock(&buf->rb_lock);
+
        dprintk("RPC:       %s: reply %p completes request %p (xid 0x%08x)\n",
                __func__, rep, req, be32_to_cpu(headerp->rm_xid));
 
-       /* from here on, the reply is no longer an orphan */
-       req->rl_reply = rep;
-       xprt->reestablish_timeout = 0;
+       /* Invalidate and unmap the data payloads before waking the
+        * waiting application. This guarantees the memory regions
+        * are properly fenced from the server before the application
+        * accesses the data. It also ensures proper send flow control:
+        * waking the next RPC waits until this RPC has relinquished
+        * all its Send Queue entries.
+        */
+       if (!list_empty(&mws))
+               r_xprt->rx_ia.ri_ops->ro_unmap_sync(r_xprt, &mws);
 
+       /* Perform XID lookup, reconstruction of the RPC reply, and
+        * RPC completion while holding the transport lock to ensure
+        * the rep, rqst, and rq_task pointers remain stable.
+        */
+       spin_lock_bh(&xprt->transport_lock);
+       rqst = xprt_lookup_rqst(xprt, headerp->rm_xid);
+       if (!rqst)
+               goto out_norqst;
+       xprt->reestablish_timeout = 0;
        if (headerp->rm_vers != rpcrdma_version)
                goto out_badversion;
 
@@ -1024,12 +1065,9 @@ rpcrdma_reply_handler(struct work_struct *work)
        case rdma_msg:
                /* never expect read chunks */
                /* never expect reply chunks (two ways to check) */
-               /* never expect write chunks without having offered RDMA */
                if (headerp->rm_body.rm_chunks[0] != xdr_zero ||
                    (headerp->rm_body.rm_chunks[1] == xdr_zero &&
-                    headerp->rm_body.rm_chunks[2] != xdr_zero) ||
-                   (headerp->rm_body.rm_chunks[1] != xdr_zero &&
-                    list_empty(&req->rl_registered)))
+                    headerp->rm_body.rm_chunks[2] != xdr_zero))
                        goto badheader;
                if (headerp->rm_body.rm_chunks[1] != xdr_zero) {
                        /* count any expected write chunks in read reply */
@@ -1066,8 +1104,7 @@ rpcrdma_reply_handler(struct work_struct *work)
                /* never expect read or write chunks, always reply chunks */
                if (headerp->rm_body.rm_chunks[0] != xdr_zero ||
                    headerp->rm_body.rm_chunks[1] != xdr_zero ||
-                   headerp->rm_body.rm_chunks[2] != xdr_one ||
-                   list_empty(&req->rl_registered))
+                   headerp->rm_body.rm_chunks[2] != xdr_one)
                        goto badheader;
                iptr = (__be32 *)((unsigned char *)headerp +
                                                        RPCRDMA_HDRLEN_MIN);
@@ -1093,17 +1130,6 @@ badheader:
        }
 
 out:
-       /* Invalidate and flush the data payloads before waking the
-        * waiting application. This guarantees the memory region is
-        * properly fenced from the server before the application
-        * accesses the data. It also ensures proper send flow
-        * control: waking the next RPC waits until this RPC has
-        * relinquished all its Send Queue entries.
-        */
-       if (!list_empty(&req->rl_registered))
-               r_xprt->rx_ia.ri_ops->ro_unmap_sync(r_xprt, req);
-
-       spin_lock_bh(&xprt->transport_lock);
        cwnd = xprt->cwnd;
        xprt->cwnd = atomic_read(&r_xprt->rx_buf.rb_credits) << RPC_CWNDSHIFT;
        if (xprt->cwnd > cwnd)
@@ -1112,7 +1138,7 @@ out:
        xprt_complete_rqst(rqst->rq_task, status);
        spin_unlock_bh(&xprt->transport_lock);
        dprintk("RPC:       %s: xprt_complete_rqst(0x%p, 0x%p, %d)\n",
-                       __func__, xprt, rqst, status);
+               __func__, xprt, rqst, status);
        return;
 
 out_badstatus:
@@ -1161,26 +1187,37 @@ out_rdmaerr:
        r_xprt->rx_stats.bad_reply_count++;
        goto out;
 
-/* If no pending RPC transaction was matched, post a replacement
- * receive buffer before returning.
+/* The req was still available, but by the time the transport_lock
+ * was acquired, the rqst and task had been released. Thus the RPC
+ * has already been terminated.
  */
+out_norqst:
+       spin_unlock_bh(&xprt->transport_lock);
+       rpcrdma_buffer_put(req);
+       dprintk("RPC:       %s: race, no rqst left for req %p\n",
+               __func__, req);
+       return;
+
 out_shortreply:
        dprintk("RPC:       %s: short/invalid reply\n", __func__);
        goto repost;
 
 out_nomatch:
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&buf->rb_lock);
        dprintk("RPC:       %s: no match for incoming xid 0x%08x len %d\n",
                __func__, be32_to_cpu(headerp->rm_xid),
                rep->rr_len);
        goto repost;
 
 out_duplicate:
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&buf->rb_lock);
        dprintk("RPC:       %s: "
                "duplicate reply %p to RPC request %p: xid 0x%08x\n",
                __func__, rep, req, be32_to_cpu(headerp->rm_xid));
 
+/* If no pending RPC transaction was matched, post a replacement
+ * receive buffer before returning.
+ */
 repost:
        r_xprt->rx_stats.bad_reply_count++;
        if (rpcrdma_ep_post_recv(&r_xprt->rx_ia, rep))
diff --git a/net/sunrpc/xprtrdma/svc_rdma_marshal.c b/net/sunrpc/xprtrdma/svc_rdma_marshal.c
deleted file mode 100644 (file)
index bdcf7d8..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (c) 2016 Oracle. All rights reserved.
- * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the BSD-type
- * license below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *      Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *
- *      Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials provided
- *      with the distribution.
- *
- *      Neither the name of the Network Appliance, Inc. 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.
- *
- * Author: Tom Tucker <tom@opengridcomputing.com>
- */
-
-#include <linux/sunrpc/xdr.h>
-#include <linux/sunrpc/debug.h>
-#include <asm/unaligned.h>
-#include <linux/sunrpc/rpc_rdma.h>
-#include <linux/sunrpc/svc_rdma.h>
-
-#define RPCDBG_FACILITY        RPCDBG_SVCXPRT
-
-static __be32 *xdr_check_read_list(__be32 *p, __be32 *end)
-{
-       __be32 *next;
-
-       while (*p++ != xdr_zero) {
-               next = p + rpcrdma_readchunk_maxsz - 1;
-               if (next > end)
-                       return NULL;
-               p = next;
-       }
-       return p;
-}
-
-static __be32 *xdr_check_write_list(__be32 *p, __be32 *end)
-{
-       __be32 *next;
-
-       while (*p++ != xdr_zero) {
-               next = p + 1 + be32_to_cpup(p) * rpcrdma_segment_maxsz;
-               if (next > end)
-                       return NULL;
-               p = next;
-       }
-       return p;
-}
-
-static __be32 *xdr_check_reply_chunk(__be32 *p, __be32 *end)
-{
-       __be32 *next;
-
-       if (*p++ != xdr_zero) {
-               next = p + 1 + be32_to_cpup(p) * rpcrdma_segment_maxsz;
-               if (next > end)
-                       return NULL;
-               p = next;
-       }
-       return p;
-}
-
-/**
- * svc_rdma_xdr_decode_req - Parse incoming RPC-over-RDMA header
- * @rq_arg: Receive buffer
- *
- * On entry, xdr->head[0].iov_base points to first byte in the
- * RPC-over-RDMA header.
- *
- * On successful exit, head[0] points to first byte past the
- * RPC-over-RDMA header. For RDMA_MSG, this is the RPC message.
- * The length of the RPC-over-RDMA header is returned.
- */
-int svc_rdma_xdr_decode_req(struct xdr_buf *rq_arg)
-{
-       __be32 *p, *end, *rdma_argp;
-       unsigned int hdr_len;
-
-       /* Verify that there's enough bytes for header + something */
-       if (rq_arg->len <= RPCRDMA_HDRLEN_ERR)
-               goto out_short;
-
-       rdma_argp = rq_arg->head[0].iov_base;
-       if (*(rdma_argp + 1) != rpcrdma_version)
-               goto out_version;
-
-       switch (*(rdma_argp + 3)) {
-       case rdma_msg:
-       case rdma_nomsg:
-               break;
-
-       case rdma_done:
-               goto out_drop;
-
-       case rdma_error:
-               goto out_drop;
-
-       default:
-               goto out_proc;
-       }
-
-       end = (__be32 *)((unsigned long)rdma_argp + rq_arg->len);
-       p = xdr_check_read_list(rdma_argp + 4, end);
-       if (!p)
-               goto out_inval;
-       p = xdr_check_write_list(p, end);
-       if (!p)
-               goto out_inval;
-       p = xdr_check_reply_chunk(p, end);
-       if (!p)
-               goto out_inval;
-       if (p > end)
-               goto out_inval;
-
-       rq_arg->head[0].iov_base = p;
-       hdr_len = (unsigned long)p - (unsigned long)rdma_argp;
-       rq_arg->head[0].iov_len -= hdr_len;
-       return hdr_len;
-
-out_short:
-       dprintk("svcrdma: header too short = %d\n", rq_arg->len);
-       return -EINVAL;
-
-out_version:
-       dprintk("svcrdma: bad xprt version: %u\n",
-               be32_to_cpup(rdma_argp + 1));
-       return -EPROTONOSUPPORT;
-
-out_drop:
-       dprintk("svcrdma: dropping RDMA_DONE/ERROR message\n");
-       return 0;
-
-out_proc:
-       dprintk("svcrdma: bad rdma procedure (%u)\n",
-               be32_to_cpup(rdma_argp + 3));
-       return -EINVAL;
-
-out_inval:
-       dprintk("svcrdma: failed to parse transport header\n");
-       return -EINVAL;
-}
index 27a99bf..ad4bd62 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2016, 2017 Oracle. All rights reserved.
  * Copyright (c) 2014 Open Grid Computing, Inc. All rights reserved.
  * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
  *
  * Author: Tom Tucker <tom@opengridcomputing.com>
  */
 
-#include <linux/sunrpc/debug.h>
-#include <linux/sunrpc/rpc_rdma.h>
-#include <linux/spinlock.h>
+/* Operation
+ *
+ * The main entry point is svc_rdma_recvfrom. This is called from
+ * svc_recv when the transport indicates there is incoming data to
+ * be read. "Data Ready" is signaled when an RDMA Receive completes,
+ * or when a set of RDMA Reads complete.
+ *
+ * An svc_rqst is passed in. This structure contains an array of
+ * free pages (rq_pages) that will contain the incoming RPC message.
+ *
+ * Short messages are moved directly into svc_rqst::rq_arg, and
+ * the RPC Call is ready to be processed by the Upper Layer.
+ * svc_rdma_recvfrom returns the length of the RPC Call message,
+ * completing the reception of the RPC Call.
+ *
+ * However, when an incoming message has Read chunks,
+ * svc_rdma_recvfrom must post RDMA Reads to pull the RPC Call's
+ * data payload from the client. svc_rdma_recvfrom sets up the
+ * RDMA Reads using pages in svc_rqst::rq_pages, which are
+ * transferred to an svc_rdma_op_ctxt for the duration of the
+ * I/O. svc_rdma_recvfrom then returns zero, since the RPC message
+ * is still not yet ready.
+ *
+ * When the Read chunk payloads have become available on the
+ * server, "Data Ready" is raised again, and svc_recv calls
+ * svc_rdma_recvfrom again. This second call may use a different
+ * svc_rqst than the first one, thus any information that needs
+ * to be preserved across these two calls is kept in an
+ * svc_rdma_op_ctxt.
+ *
+ * The second call to svc_rdma_recvfrom performs final assembly
+ * of the RPC Call message, using the RDMA Read sink pages kept in
+ * the svc_rdma_op_ctxt. The xdr_buf is copied from the
+ * svc_rdma_op_ctxt to the second svc_rqst. The second call returns
+ * the length of the completed RPC Call message.
+ *
+ * Page Management
+ *
+ * Pages under I/O must be transferred from the first svc_rqst to an
+ * svc_rdma_op_ctxt before the first svc_rdma_recvfrom call returns.
+ *
+ * The first svc_rqst supplies pages for RDMA Reads. These are moved
+ * from rqstp::rq_pages into ctxt::pages. The consumed elements of
+ * the rq_pages array are set to NULL and refilled with the first
+ * svc_rdma_recvfrom call returns.
+ *
+ * During the second svc_rdma_recvfrom call, RDMA Read sink pages
+ * are transferred from the svc_rdma_op_ctxt to the second svc_rqst
+ * (see rdma_read_complete() below).
+ */
+
 #include <asm/unaligned.h>
 #include <rdma/ib_verbs.h>
 #include <rdma/rdma_cm.h>
+
+#include <linux/spinlock.h>
+
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/debug.h>
+#include <linux/sunrpc/rpc_rdma.h>
 #include <linux/sunrpc/svc_rdma.h>
 
 #define RPCDBG_FACILITY        RPCDBG_SVCXPRT
@@ -59,7 +114,6 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
                               struct svc_rdma_op_ctxt *ctxt,
                               u32 byte_count)
 {
-       struct rpcrdma_msg *rmsgp;
        struct page *page;
        u32 bc;
        int sge_no;
@@ -83,20 +137,12 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
        rqstp->rq_arg.page_len = bc;
        rqstp->rq_arg.page_base = 0;
 
-       /* RDMA_NOMSG: RDMA READ data should land just after RDMA RECV data */
-       rmsgp = (struct rpcrdma_msg *)rqstp->rq_arg.head[0].iov_base;
-       if (rmsgp->rm_type == rdma_nomsg)
-               rqstp->rq_arg.pages = &rqstp->rq_pages[0];
-       else
-               rqstp->rq_arg.pages = &rqstp->rq_pages[1];
-
        sge_no = 1;
        while (bc && sge_no < ctxt->count) {
                page = ctxt->pages[sge_no];
                put_page(rqstp->rq_pages[sge_no]);
                rqstp->rq_pages[sge_no] = page;
                bc -= min_t(u32, bc, ctxt->sge[sge_no].length);
-               rqstp->rq_arg.buflen += ctxt->sge[sge_no].length;
                sge_no++;
        }
        rqstp->rq_respages = &rqstp->rq_pages[sge_no];
@@ -115,406 +161,208 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
        rqstp->rq_arg.tail[0].iov_len = 0;
 }
 
-/* Issue an RDMA_READ using the local lkey to map the data sink */
-int rdma_read_chunk_lcl(struct svcxprt_rdma *xprt,
-                       struct svc_rqst *rqstp,
-                       struct svc_rdma_op_ctxt *head,
-                       int *page_no,
-                       u32 *page_offset,
-                       u32 rs_handle,
-                       u32 rs_length,
-                       u64 rs_offset,
-                       bool last)
-{
-       struct ib_rdma_wr read_wr;
-       int pages_needed = PAGE_ALIGN(*page_offset + rs_length) >> PAGE_SHIFT;
-       struct svc_rdma_op_ctxt *ctxt = svc_rdma_get_context(xprt);
-       int ret, read, pno;
-       u32 pg_off = *page_offset;
-       u32 pg_no = *page_no;
-
-       ctxt->direction = DMA_FROM_DEVICE;
-       ctxt->read_hdr = head;
-       pages_needed = min_t(int, pages_needed, xprt->sc_max_sge_rd);
-       read = min_t(int, (pages_needed << PAGE_SHIFT) - *page_offset,
-                    rs_length);
-
-       for (pno = 0; pno < pages_needed; pno++) {
-               int len = min_t(int, rs_length, PAGE_SIZE - pg_off);
-
-               head->arg.pages[pg_no] = rqstp->rq_arg.pages[pg_no];
-               head->arg.page_len += len;
-
-               head->arg.len += len;
-               if (!pg_off)
-                       head->count++;
-               rqstp->rq_respages = &rqstp->rq_arg.pages[pg_no+1];
-               rqstp->rq_next_page = rqstp->rq_respages + 1;
-               ctxt->sge[pno].addr =
-                       ib_dma_map_page(xprt->sc_cm_id->device,
-                                       head->arg.pages[pg_no], pg_off,
-                                       PAGE_SIZE - pg_off,
-                                       DMA_FROM_DEVICE);
-               ret = ib_dma_mapping_error(xprt->sc_cm_id->device,
-                                          ctxt->sge[pno].addr);
-               if (ret)
-                       goto err;
-               svc_rdma_count_mappings(xprt, ctxt);
-
-               ctxt->sge[pno].lkey = xprt->sc_pd->local_dma_lkey;
-               ctxt->sge[pno].length = len;
-               ctxt->count++;
-
-               /* adjust offset and wrap to next page if needed */
-               pg_off += len;
-               if (pg_off == PAGE_SIZE) {
-                       pg_off = 0;
-                       pg_no++;
-               }
-               rs_length -= len;
-       }
-
-       if (last && rs_length == 0)
-               set_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
-       else
-               clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
-
-       memset(&read_wr, 0, sizeof(read_wr));
-       ctxt->cqe.done = svc_rdma_wc_read;
-       read_wr.wr.wr_cqe = &ctxt->cqe;
-       read_wr.wr.opcode = IB_WR_RDMA_READ;
-       read_wr.wr.send_flags = IB_SEND_SIGNALED;
-       read_wr.rkey = rs_handle;
-       read_wr.remote_addr = rs_offset;
-       read_wr.wr.sg_list = ctxt->sge;
-       read_wr.wr.num_sge = pages_needed;
-
-       ret = svc_rdma_send(xprt, &read_wr.wr);
-       if (ret) {
-               pr_err("svcrdma: Error %d posting RDMA_READ\n", ret);
-               set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
-               goto err;
-       }
+/* This accommodates the largest possible Write chunk,
+ * in one segment.
+ */
+#define MAX_BYTES_WRITE_SEG    ((u32)(RPCSVC_MAXPAGES << PAGE_SHIFT))
 
-       /* return current location in page array */
-       *page_no = pg_no;
-       *page_offset = pg_off;
-       ret = read;
-       atomic_inc(&rdma_stat_read);
-       return ret;
- err:
-       svc_rdma_unmap_dma(ctxt);
-       svc_rdma_put_context(ctxt, 0);
-       return ret;
-}
+/* This accommodates the largest possible Position-Zero
+ * Read chunk or Reply chunk, in one segment.
+ */
+#define MAX_BYTES_SPECIAL_SEG  ((u32)((RPCSVC_MAXPAGES + 2) << PAGE_SHIFT))
 
-/* Issue an RDMA_READ using an FRMR to map the data sink */
-int rdma_read_chunk_frmr(struct svcxprt_rdma *xprt,
-                        struct svc_rqst *rqstp,
-                        struct svc_rdma_op_ctxt *head,
-                        int *page_no,
-                        u32 *page_offset,
-                        u32 rs_handle,
-                        u32 rs_length,
-                        u64 rs_offset,
-                        bool last)
+/* Sanity check the Read list.
+ *
+ * Implementation limits:
+ * - This implementation supports only one Read chunk.
+ *
+ * Sanity checks:
+ * - Read list does not overflow buffer.
+ * - Segment size limited by largest NFS data payload.
+ *
+ * The segment count is limited to how many segments can
+ * fit in the transport header without overflowing the
+ * buffer. That's about 40 Read segments for a 1KB inline
+ * threshold.
+ *
+ * Returns pointer to the following Write list.
+ */
+static __be32 *xdr_check_read_list(__be32 *p, const __be32 *end)
 {
-       struct ib_rdma_wr read_wr;
-       struct ib_send_wr inv_wr;
-       struct ib_reg_wr reg_wr;
-       u8 key;
-       int nents = PAGE_ALIGN(*page_offset + rs_length) >> PAGE_SHIFT;
-       struct svc_rdma_op_ctxt *ctxt = svc_rdma_get_context(xprt);
-       struct svc_rdma_fastreg_mr *frmr = svc_rdma_get_frmr(xprt);
-       int ret, read, pno, dma_nents, n;
-       u32 pg_off = *page_offset;
-       u32 pg_no = *page_no;
-
-       if (IS_ERR(frmr))
-               return -ENOMEM;
-
-       ctxt->direction = DMA_FROM_DEVICE;
-       ctxt->frmr = frmr;
-       nents = min_t(unsigned int, nents, xprt->sc_frmr_pg_list_len);
-       read = min_t(int, (nents << PAGE_SHIFT) - *page_offset, rs_length);
-
-       frmr->direction = DMA_FROM_DEVICE;
-       frmr->access_flags = (IB_ACCESS_LOCAL_WRITE|IB_ACCESS_REMOTE_WRITE);
-       frmr->sg_nents = nents;
-
-       for (pno = 0; pno < nents; pno++) {
-               int len = min_t(int, rs_length, PAGE_SIZE - pg_off);
-
-               head->arg.pages[pg_no] = rqstp->rq_arg.pages[pg_no];
-               head->arg.page_len += len;
-               head->arg.len += len;
-               if (!pg_off)
-                       head->count++;
-
-               sg_set_page(&frmr->sg[pno], rqstp->rq_arg.pages[pg_no],
-                           len, pg_off);
-
-               rqstp->rq_respages = &rqstp->rq_arg.pages[pg_no+1];
-               rqstp->rq_next_page = rqstp->rq_respages + 1;
-
-               /* adjust offset and wrap to next page if needed */
-               pg_off += len;
-               if (pg_off == PAGE_SIZE) {
-                       pg_off = 0;
-                       pg_no++;
+       u32 position;
+       bool first;
+
+       first = true;
+       while (*p++ != xdr_zero) {
+               if (first) {
+                       position = be32_to_cpup(p++);
+                       first = false;
+               } else if (be32_to_cpup(p++) != position) {
+                       return NULL;
                }
-               rs_length -= len;
-       }
+               p++;    /* handle */
+               if (be32_to_cpup(p++) > MAX_BYTES_SPECIAL_SEG)
+                       return NULL;
+               p += 2; /* offset */
 
-       if (last && rs_length == 0)
-               set_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
-       else
-               clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
-
-       dma_nents = ib_dma_map_sg(xprt->sc_cm_id->device,
-                                 frmr->sg, frmr->sg_nents,
-                                 frmr->direction);
-       if (!dma_nents) {
-               pr_err("svcrdma: failed to dma map sg %p\n",
-                      frmr->sg);
-               return -ENOMEM;
+               if (p > end)
+                       return NULL;
        }
+       return p;
+}
 
-       n = ib_map_mr_sg(frmr->mr, frmr->sg, frmr->sg_nents, NULL, PAGE_SIZE);
-       if (unlikely(n != frmr->sg_nents)) {
-               pr_err("svcrdma: failed to map mr %p (%d/%d elements)\n",
-                      frmr->mr, n, frmr->sg_nents);
-               return n < 0 ? n : -EINVAL;
-       }
+/* The segment count is limited to how many segments can
+ * fit in the transport header without overflowing the
+ * buffer. That's about 60 Write segments for a 1KB inline
+ * threshold.
+ */
+static __be32 *xdr_check_write_chunk(__be32 *p, const __be32 *end,
+                                    u32 maxlen)
+{
+       u32 i, segcount;
 
-       /* Bump the key */
-       key = (u8)(frmr->mr->lkey & 0x000000FF);
-       ib_update_fast_reg_key(frmr->mr, ++key);
-
-       ctxt->sge[0].addr = frmr->mr->iova;
-       ctxt->sge[0].lkey = frmr->mr->lkey;
-       ctxt->sge[0].length = frmr->mr->length;
-       ctxt->count = 1;
-       ctxt->read_hdr = head;
-
-       /* Prepare REG WR */
-       ctxt->reg_cqe.done = svc_rdma_wc_reg;
-       reg_wr.wr.wr_cqe = &ctxt->reg_cqe;
-       reg_wr.wr.opcode = IB_WR_REG_MR;
-       reg_wr.wr.send_flags = IB_SEND_SIGNALED;
-       reg_wr.wr.num_sge = 0;
-       reg_wr.mr = frmr->mr;
-       reg_wr.key = frmr->mr->lkey;
-       reg_wr.access = frmr->access_flags;
-       reg_wr.wr.next = &read_wr.wr;
-
-       /* Prepare RDMA_READ */
-       memset(&read_wr, 0, sizeof(read_wr));
-       ctxt->cqe.done = svc_rdma_wc_read;
-       read_wr.wr.wr_cqe = &ctxt->cqe;
-       read_wr.wr.send_flags = IB_SEND_SIGNALED;
-       read_wr.rkey = rs_handle;
-       read_wr.remote_addr = rs_offset;
-       read_wr.wr.sg_list = ctxt->sge;
-       read_wr.wr.num_sge = 1;
-       if (xprt->sc_dev_caps & SVCRDMA_DEVCAP_READ_W_INV) {
-               read_wr.wr.opcode = IB_WR_RDMA_READ_WITH_INV;
-               read_wr.wr.ex.invalidate_rkey = ctxt->frmr->mr->lkey;
-       } else {
-               read_wr.wr.opcode = IB_WR_RDMA_READ;
-               read_wr.wr.next = &inv_wr;
-               /* Prepare invalidate */
-               memset(&inv_wr, 0, sizeof(inv_wr));
-               ctxt->inv_cqe.done = svc_rdma_wc_inv;
-               inv_wr.wr_cqe = &ctxt->inv_cqe;
-               inv_wr.opcode = IB_WR_LOCAL_INV;
-               inv_wr.send_flags = IB_SEND_SIGNALED | IB_SEND_FENCE;
-               inv_wr.ex.invalidate_rkey = frmr->mr->lkey;
-       }
+       segcount = be32_to_cpup(p++);
+       for (i = 0; i < segcount; i++) {
+               p++;    /* handle */
+               if (be32_to_cpup(p++) > maxlen)
+                       return NULL;
+               p += 2; /* offset */
 
-       /* Post the chain */
-       ret = svc_rdma_send(xprt, &reg_wr.wr);
-       if (ret) {
-               pr_err("svcrdma: Error %d posting RDMA_READ\n", ret);
-               set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
-               goto err;
+               if (p > end)
+                       return NULL;
        }
 
-       /* return current location in page array */
-       *page_no = pg_no;
-       *page_offset = pg_off;
-       ret = read;
-       atomic_inc(&rdma_stat_read);
-       return ret;
- err:
-       svc_rdma_put_context(ctxt, 0);
-       svc_rdma_put_frmr(xprt, frmr);
-       return ret;
-}
-
-static unsigned int
-rdma_rcl_chunk_count(struct rpcrdma_read_chunk *ch)
-{
-       unsigned int count;
-
-       for (count = 0; ch->rc_discrim != xdr_zero; ch++)
-               count++;
-       return count;
+       return p;
 }
 
-/* If there was additional inline content, append it to the end of arg.pages.
- * Tail copy has to be done after the reader function has determined how many
- * pages are needed for RDMA READ.
+/* Sanity check the Write list.
+ *
+ * Implementation limits:
+ * - This implementation supports only one Write chunk.
+ *
+ * Sanity checks:
+ * - Write list does not overflow buffer.
+ * - Segment size limited by largest NFS data payload.
+ *
+ * Returns pointer to the following Reply chunk.
  */
-static int
-rdma_copy_tail(struct svc_rqst *rqstp, struct svc_rdma_op_ctxt *head,
-              u32 position, u32 byte_count, u32 page_offset, int page_no)
+static __be32 *xdr_check_write_list(__be32 *p, const __be32 *end)
 {
-       char *srcp, *destp;
-
-       srcp = head->arg.head[0].iov_base + position;
-       byte_count = head->arg.head[0].iov_len - position;
-       if (byte_count > PAGE_SIZE) {
-               dprintk("svcrdma: large tail unsupported\n");
-               return 0;
-       }
-
-       /* Fit as much of the tail on the current page as possible */
-       if (page_offset != PAGE_SIZE) {
-               destp = page_address(rqstp->rq_arg.pages[page_no]);
-               destp += page_offset;
-               while (byte_count--) {
-                       *destp++ = *srcp++;
-                       page_offset++;
-                       if (page_offset == PAGE_SIZE && byte_count)
-                               goto more;
-               }
-               goto done;
+       u32 chcount;
+
+       chcount = 0;
+       while (*p++ != xdr_zero) {
+               p = xdr_check_write_chunk(p, end, MAX_BYTES_WRITE_SEG);
+               if (!p)
+                       return NULL;
+               if (chcount++ > 1)
+                       return NULL;
        }
-
-more:
-       /* Fit the rest on the next page */
-       page_no++;
-       destp = page_address(rqstp->rq_arg.pages[page_no]);
-       while (byte_count--)
-               *destp++ = *srcp++;
-
-       rqstp->rq_respages = &rqstp->rq_arg.pages[page_no+1];
-       rqstp->rq_next_page = rqstp->rq_respages + 1;
-
-done:
-       byte_count = head->arg.head[0].iov_len - position;
-       head->arg.page_len += byte_count;
-       head->arg.len += byte_count;
-       head->arg.buflen += byte_count;
-       return 1;
+       return p;
 }
 
-/* Returns the address of the first read chunk or <nul> if no read chunk
- * is present
+/* Sanity check the Reply chunk.
+ *
+ * Sanity checks:
+ * - Reply chunk does not overflow buffer.
+ * - Segment size limited by largest NFS data payload.
+ *
+ * Returns pointer to the following RPC header.
  */
-static struct rpcrdma_read_chunk *
-svc_rdma_get_read_chunk(struct rpcrdma_msg *rmsgp)
+static __be32 *xdr_check_reply_chunk(__be32 *p, const __be32 *end)
 {
-       struct rpcrdma_read_chunk *ch =
-               (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
-
-       if (ch->rc_discrim == xdr_zero)
-               return NULL;
-       return ch;
+       if (*p++ != xdr_zero) {
+               p = xdr_check_write_chunk(p, end, MAX_BYTES_SPECIAL_SEG);
+               if (!p)
+                       return NULL;
+       }
+       return p;
 }
 
-static int rdma_read_chunks(struct svcxprt_rdma *xprt,
-                           struct rpcrdma_msg *rmsgp,
-                           struct svc_rqst *rqstp,
-                           struct svc_rdma_op_ctxt *head)
+/* On entry, xdr->head[0].iov_base points to first byte in the
+ * RPC-over-RDMA header.
+ *
+ * On successful exit, head[0] points to first byte past the
+ * RPC-over-RDMA header. For RDMA_MSG, this is the RPC message.
+ * The length of the RPC-over-RDMA header is returned.
+ *
+ * Assumptions:
+ * - The transport header is entirely contained in the head iovec.
+ */
+static int svc_rdma_xdr_decode_req(struct xdr_buf *rq_arg)
 {
-       int page_no, ret;
-       struct rpcrdma_read_chunk *ch;
-       u32 handle, page_offset, byte_count;
-       u32 position;
-       u64 rs_offset;
-       bool last;
-
-       /* If no read list is present, return 0 */
-       ch = svc_rdma_get_read_chunk(rmsgp);
-       if (!ch)
-               return 0;
+       __be32 *p, *end, *rdma_argp;
+       unsigned int hdr_len;
+       char *proc;
+
+       /* Verify that there's enough bytes for header + something */
+       if (rq_arg->len <= RPCRDMA_HDRLEN_ERR)
+               goto out_short;
+
+       rdma_argp = rq_arg->head[0].iov_base;
+       if (*(rdma_argp + 1) != rpcrdma_version)
+               goto out_version;
+
+       switch (*(rdma_argp + 3)) {
+       case rdma_msg:
+               proc = "RDMA_MSG";
+               break;
+       case rdma_nomsg:
+               proc = "RDMA_NOMSG";
+               break;
+
+       case rdma_done:
+               goto out_drop;
 
-       if (rdma_rcl_chunk_count(ch) > RPCSVC_MAXPAGES)
-               return -EINVAL;
-
-       /* The request is completed when the RDMA_READs complete. The
-        * head context keeps all the pages that comprise the
-        * request.
-        */
-       head->arg.head[0] = rqstp->rq_arg.head[0];
-       head->arg.tail[0] = rqstp->rq_arg.tail[0];
-       head->hdr_count = head->count;
-       head->arg.page_base = 0;
-       head->arg.page_len = 0;
-       head->arg.len = rqstp->rq_arg.len;
-       head->arg.buflen = rqstp->rq_arg.buflen;
-
-       /* RDMA_NOMSG: RDMA READ data should land just after RDMA RECV data */
-       position = be32_to_cpu(ch->rc_position);
-       if (position == 0) {
-               head->arg.pages = &head->pages[0];
-               page_offset = head->byte_len;
-       } else {
-               head->arg.pages = &head->pages[head->count];
-               page_offset = 0;
-       }
+       case rdma_error:
+               goto out_drop;
 
-       ret = 0;
-       page_no = 0;
-       for (; ch->rc_discrim != xdr_zero; ch++) {
-               if (be32_to_cpu(ch->rc_position) != position)
-                       goto err;
-
-               handle = be32_to_cpu(ch->rc_target.rs_handle),
-               byte_count = be32_to_cpu(ch->rc_target.rs_length);
-               xdr_decode_hyper((__be32 *)&ch->rc_target.rs_offset,
-                                &rs_offset);
-
-               while (byte_count > 0) {
-                       last = (ch + 1)->rc_discrim == xdr_zero;
-                       ret = xprt->sc_reader(xprt, rqstp, head,
-                                             &page_no, &page_offset,
-                                             handle, byte_count,
-                                             rs_offset, last);
-                       if (ret < 0)
-                               goto err;
-                       byte_count -= ret;
-                       rs_offset += ret;
-                       head->arg.buflen += ret;
-               }
+       default:
+               goto out_proc;
        }
 
-       /* Read list may need XDR round-up (see RFC 5666, s. 3.7) */
-       if (page_offset & 3) {
-               u32 pad = 4 - (page_offset & 3);
-
-               head->arg.tail[0].iov_len += pad;
-               head->arg.len += pad;
-               head->arg.buflen += pad;
-               page_offset += pad;
-       }
+       end = (__be32 *)((unsigned long)rdma_argp + rq_arg->len);
+       p = xdr_check_read_list(rdma_argp + 4, end);
+       if (!p)
+               goto out_inval;
+       p = xdr_check_write_list(p, end);
+       if (!p)
+               goto out_inval;
+       p = xdr_check_reply_chunk(p, end);
+       if (!p)
+               goto out_inval;
+       if (p > end)
+               goto out_inval;
+
+       rq_arg->head[0].iov_base = p;
+       hdr_len = (unsigned long)p - (unsigned long)rdma_argp;
+       rq_arg->head[0].iov_len -= hdr_len;
+       rq_arg->len -= hdr_len;
+       dprintk("svcrdma: received %s request for XID 0x%08x, hdr_len=%u\n",
+               proc, be32_to_cpup(rdma_argp), hdr_len);
+       return hdr_len;
+
+out_short:
+       dprintk("svcrdma: header too short = %d\n", rq_arg->len);
+       return -EINVAL;
+
+out_version:
+       dprintk("svcrdma: bad xprt version: %u\n",
+               be32_to_cpup(rdma_argp + 1));
+       return -EPROTONOSUPPORT;
 
-       ret = 1;
-       if (position && position < head->arg.head[0].iov_len)
-               ret = rdma_copy_tail(rqstp, head, position,
-                                    byte_count, page_offset, page_no);
-       head->arg.head[0].iov_len = position;
-       head->position = position;
+out_drop:
+       dprintk("svcrdma: dropping RDMA_DONE/ERROR message\n");
+       return 0;
 
- err:
-       /* Detach arg pages. svc_recv will replenish them */
-       for (page_no = 0;
-            &rqstp->rq_pages[page_no] < rqstp->rq_respages; page_no++)
-               rqstp->rq_pages[page_no] = NULL;
+out_proc:
+       dprintk("svcrdma: bad rdma procedure (%u)\n",
+               be32_to_cpup(rdma_argp + 3));
+       return -EINVAL;
 
-       return ret;
+out_inval:
+       dprintk("svcrdma: failed to parse transport header\n");
+       return -EINVAL;
 }
 
 static void rdma_read_complete(struct svc_rqst *rqstp,
@@ -528,24 +376,9 @@ static void rdma_read_complete(struct svc_rqst *rqstp,
                rqstp->rq_pages[page_no] = head->pages[page_no];
        }
 
-       /* Adjustments made for RDMA_NOMSG type requests */
-       if (head->position == 0) {
-               if (head->arg.len <= head->sge[0].length) {
-                       head->arg.head[0].iov_len = head->arg.len -
-                                                       head->byte_len;
-                       head->arg.page_len = 0;
-               } else {
-                       head->arg.head[0].iov_len = head->sge[0].length -
-                                                               head->byte_len;
-                       head->arg.page_len = head->arg.len -
-                                               head->sge[0].length;
-               }
-       }
-
        /* Point rq_arg.pages past header */
        rqstp->rq_arg.pages = &rqstp->rq_pages[head->hdr_count];
        rqstp->rq_arg.page_len = head->arg.page_len;
-       rqstp->rq_arg.page_base = head->arg.page_base;
 
        /* rq_respages starts after the last arg page */
        rqstp->rq_respages = &rqstp->rq_pages[page_no];
@@ -642,21 +475,44 @@ static bool svc_rdma_is_backchannel_reply(struct svc_xprt *xprt,
        return true;
 }
 
-/*
- * Set up the rqstp thread context to point to the RQ buffer. If
- * necessary, pull additional data from the client with an RDMA_READ
- * request.
+/**
+ * svc_rdma_recvfrom - Receive an RPC call
+ * @rqstp: request structure into which to receive an RPC Call
+ *
+ * Returns:
+ *     The positive number of bytes in the RPC Call message,
+ *     %0 if there were no Calls ready to return,
+ *     %-EINVAL if the Read chunk data is too large,
+ *     %-ENOMEM if rdma_rw context pool was exhausted,
+ *     %-ENOTCONN if posting failed (connection is lost),
+ *     %-EIO if rdma_rw initialization failed (DMA mapping, etc).
+ *
+ * Called in a loop when XPT_DATA is set. XPT_DATA is cleared only
+ * when there are no remaining ctxt's to process.
+ *
+ * The next ctxt is removed from the "receive" lists.
+ *
+ * - If the ctxt completes a Read, then finish assembling the Call
+ *   message and return the number of bytes in the message.
+ *
+ * - If the ctxt completes a Receive, then construct the Call
+ *   message from the contents of the Receive buffer.
+ *
+ *   - If there are no Read chunks in this message, then finish
+ *     assembling the Call message and return the number of bytes
+ *     in the message.
+ *
+ *   - If there are Read chunks in this message, post Read WRs to
+ *     pull that payload and return 0.
  */
 int svc_rdma_recvfrom(struct svc_rqst *rqstp)
 {
        struct svc_xprt *xprt = rqstp->rq_xprt;
        struct svcxprt_rdma *rdma_xprt =
                container_of(xprt, struct svcxprt_rdma, sc_xprt);
-       struct svc_rdma_op_ctxt *ctxt = NULL;
-       struct rpcrdma_msg *rmsgp;
-       int ret = 0;
-
-       dprintk("svcrdma: rqstp=%p\n", rqstp);
+       struct svc_rdma_op_ctxt *ctxt;
+       __be32 *p;
+       int ret;
 
        spin_lock(&rdma_xprt->sc_rq_dto_lock);
        if (!list_empty(&rdma_xprt->sc_read_complete_q)) {
@@ -671,22 +527,14 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
                                        struct svc_rdma_op_ctxt, list);
                list_del(&ctxt->list);
        } else {
-               atomic_inc(&rdma_stat_rq_starve);
+               /* No new incoming requests, terminate the loop */
                clear_bit(XPT_DATA, &xprt->xpt_flags);
-               ctxt = NULL;
+               spin_unlock(&rdma_xprt->sc_rq_dto_lock);
+               return 0;
        }
        spin_unlock(&rdma_xprt->sc_rq_dto_lock);
-       if (!ctxt) {
-               /* This is the EAGAIN path. The svc_recv routine will
-                * return -EAGAIN, the nfsd thread will go to call into
-                * svc_recv again and we shouldn't be on the active
-                * transport list
-                */
-               if (test_bit(XPT_CLOSE, &xprt->xpt_flags))
-                       goto defer;
-               goto out;
-       }
-       dprintk("svcrdma: processing ctxt=%p on xprt=%p, rqstp=%p\n",
+
+       dprintk("svcrdma: recvfrom: ctxt=%p on xprt=%p, rqstp=%p\n",
                ctxt, rdma_xprt, rqstp);
        atomic_inc(&rdma_stat_recv);
 
@@ -694,7 +542,7 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
        rdma_build_arg_xdr(rqstp, ctxt, ctxt->byte_len);
 
        /* Decode the RDMA header. */
-       rmsgp = (struct rpcrdma_msg *)rqstp->rq_arg.head[0].iov_base;
+       p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
        ret = svc_rdma_xdr_decode_req(&rqstp->rq_arg);
        if (ret < 0)
                goto out_err;
@@ -702,9 +550,8 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
                goto out_drop;
        rqstp->rq_xprt_hlen = ret;
 
-       if (svc_rdma_is_backchannel_reply(xprt, &rmsgp->rm_xid)) {
-               ret = svc_rdma_handle_bc_reply(xprt->xpt_bc_xprt,
-                                              &rmsgp->rm_xid,
+       if (svc_rdma_is_backchannel_reply(xprt, p)) {
+               ret = svc_rdma_handle_bc_reply(xprt->xpt_bc_xprt, p,
                                               &rqstp->rq_arg);
                svc_rdma_put_context(ctxt, 0);
                if (ret)
@@ -712,39 +559,34 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
                return ret;
        }
 
-       /* Read read-list data. */
-       ret = rdma_read_chunks(rdma_xprt, rmsgp, rqstp, ctxt);
-       if (ret > 0) {
-               /* read-list posted, defer until data received from client. */
-               goto defer;
-       } else if (ret < 0) {
-               /* Post of read-list failed, free context. */
-               svc_rdma_put_context(ctxt, 1);
-               return 0;
-       }
+       p += rpcrdma_fixed_maxsz;
+       if (*p != xdr_zero)
+               goto out_readchunk;
 
 complete:
-       ret = rqstp->rq_arg.head[0].iov_len
-               + rqstp->rq_arg.page_len
-               + rqstp->rq_arg.tail[0].iov_len;
        svc_rdma_put_context(ctxt, 0);
- out:
-       dprintk("svcrdma: ret=%d, rq_arg.len=%u, "
-               "rq_arg.head[0].iov_base=%p, rq_arg.head[0].iov_len=%zd\n",
-               ret, rqstp->rq_arg.len,
-               rqstp->rq_arg.head[0].iov_base,
-               rqstp->rq_arg.head[0].iov_len);
+       dprintk("svcrdma: recvfrom: xprt=%p, rqstp=%p, rq_arg.len=%u\n",
+               rdma_xprt, rqstp, rqstp->rq_arg.len);
        rqstp->rq_prot = IPPROTO_MAX;
        svc_xprt_copy_addrs(rqstp, xprt);
-       return ret;
+       return rqstp->rq_arg.len;
+
+out_readchunk:
+       ret = svc_rdma_recv_read_chunk(rdma_xprt, rqstp, ctxt, p);
+       if (ret < 0)
+               goto out_postfail;
+       return 0;
 
 out_err:
-       svc_rdma_send_error(rdma_xprt, &rmsgp->rm_xid, ret);
+       svc_rdma_send_error(rdma_xprt, p, ret);
        svc_rdma_put_context(ctxt, 0);
        return 0;
 
-defer:
-       return 0;
+out_postfail:
+       if (ret == -EINVAL)
+               svc_rdma_send_error(rdma_xprt, p, ret);
+       svc_rdma_put_context(ctxt, 1);
+       return ret;
 
 out_drop:
        svc_rdma_put_context(ctxt, 1);
index 0cf6202..933f79b 100644 (file)
@@ -12,6 +12,9 @@
 
 #define RPCDBG_FACILITY        RPCDBG_SVCXPRT
 
+static void svc_rdma_write_done(struct ib_cq *cq, struct ib_wc *wc);
+static void svc_rdma_wc_read_done(struct ib_cq *cq, struct ib_wc *wc);
+
 /* Each R/W context contains state for one chain of RDMA Read or
  * Write Work Requests.
  *
@@ -113,22 +116,20 @@ struct svc_rdma_chunk_ctxt {
        struct svcxprt_rdma     *cc_rdma;
        struct list_head        cc_rwctxts;
        int                     cc_sqecount;
-       enum dma_data_direction cc_dir;
 };
 
 static void svc_rdma_cc_init(struct svcxprt_rdma *rdma,
-                            struct svc_rdma_chunk_ctxt *cc,
-                            enum dma_data_direction dir)
+                            struct svc_rdma_chunk_ctxt *cc)
 {
        cc->cc_rdma = rdma;
        svc_xprt_get(&rdma->sc_xprt);
 
        INIT_LIST_HEAD(&cc->cc_rwctxts);
        cc->cc_sqecount = 0;
-       cc->cc_dir = dir;
 }
 
-static void svc_rdma_cc_release(struct svc_rdma_chunk_ctxt *cc)
+static void svc_rdma_cc_release(struct svc_rdma_chunk_ctxt *cc,
+                               enum dma_data_direction dir)
 {
        struct svcxprt_rdma *rdma = cc->cc_rdma;
        struct svc_rdma_rw_ctxt *ctxt;
@@ -138,7 +139,7 @@ static void svc_rdma_cc_release(struct svc_rdma_chunk_ctxt *cc)
 
                rdma_rw_ctx_destroy(&ctxt->rw_ctx, rdma->sc_qp,
                                    rdma->sc_port_num, ctxt->rw_sg_table.sgl,
-                                   ctxt->rw_nents, cc->cc_dir);
+                                   ctxt->rw_nents, dir);
                svc_rdma_put_rw_ctxt(rdma, ctxt);
        }
        svc_xprt_put(&rdma->sc_xprt);
@@ -176,13 +177,14 @@ svc_rdma_write_info_alloc(struct svcxprt_rdma *rdma, __be32 *chunk)
        info->wi_seg_no = 0;
        info->wi_nsegs = be32_to_cpup(++chunk);
        info->wi_segs = ++chunk;
-       svc_rdma_cc_init(rdma, &info->wi_cc, DMA_TO_DEVICE);
+       svc_rdma_cc_init(rdma, &info->wi_cc);
+       info->wi_cc.cc_cqe.done = svc_rdma_write_done;
        return info;
 }
 
 static void svc_rdma_write_info_free(struct svc_rdma_write_info *info)
 {
-       svc_rdma_cc_release(&info->wi_cc);
+       svc_rdma_cc_release(&info->wi_cc, DMA_TO_DEVICE);
        kfree(info);
 }
 
@@ -216,6 +218,76 @@ static void svc_rdma_write_done(struct ib_cq *cq, struct ib_wc *wc)
        svc_rdma_write_info_free(info);
 }
 
+/* State for pulling a Read chunk.
+ */
+struct svc_rdma_read_info {
+       struct svc_rdma_op_ctxt         *ri_readctxt;
+       unsigned int                    ri_position;
+       unsigned int                    ri_pageno;
+       unsigned int                    ri_pageoff;
+       unsigned int                    ri_chunklen;
+
+       struct svc_rdma_chunk_ctxt      ri_cc;
+};
+
+static struct svc_rdma_read_info *
+svc_rdma_read_info_alloc(struct svcxprt_rdma *rdma)
+{
+       struct svc_rdma_read_info *info;
+
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return info;
+
+       svc_rdma_cc_init(rdma, &info->ri_cc);
+       info->ri_cc.cc_cqe.done = svc_rdma_wc_read_done;
+       return info;
+}
+
+static void svc_rdma_read_info_free(struct svc_rdma_read_info *info)
+{
+       svc_rdma_cc_release(&info->ri_cc, DMA_FROM_DEVICE);
+       kfree(info);
+}
+
+/**
+ * svc_rdma_wc_read_done - Handle completion of an RDMA Read ctx
+ * @cq: controlling Completion Queue
+ * @wc: Work Completion
+ *
+ */
+static void svc_rdma_wc_read_done(struct ib_cq *cq, struct ib_wc *wc)
+{
+       struct ib_cqe *cqe = wc->wr_cqe;
+       struct svc_rdma_chunk_ctxt *cc =
+                       container_of(cqe, struct svc_rdma_chunk_ctxt, cc_cqe);
+       struct svcxprt_rdma *rdma = cc->cc_rdma;
+       struct svc_rdma_read_info *info =
+                       container_of(cc, struct svc_rdma_read_info, ri_cc);
+
+       atomic_add(cc->cc_sqecount, &rdma->sc_sq_avail);
+       wake_up(&rdma->sc_send_wait);
+
+       if (unlikely(wc->status != IB_WC_SUCCESS)) {
+               set_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags);
+               if (wc->status != IB_WC_WR_FLUSH_ERR)
+                       pr_err("svcrdma: read ctx: %s (%u/0x%x)\n",
+                              ib_wc_status_msg(wc->status),
+                              wc->status, wc->vendor_err);
+               svc_rdma_put_context(info->ri_readctxt, 1);
+       } else {
+               spin_lock(&rdma->sc_rq_dto_lock);
+               list_add_tail(&info->ri_readctxt->list,
+                             &rdma->sc_read_complete_q);
+               spin_unlock(&rdma->sc_rq_dto_lock);
+
+               set_bit(XPT_DATA, &rdma->sc_xprt.xpt_flags);
+               svc_xprt_enqueue(&rdma->sc_xprt);
+       }
+
+       svc_rdma_read_info_free(info);
+}
+
 /* This function sleeps when the transport's Send Queue is congested.
  *
  * Assumptions:
@@ -232,6 +304,9 @@ static int svc_rdma_post_chunk_ctxt(struct svc_rdma_chunk_ctxt *cc)
        struct ib_cqe *cqe;
        int ret;
 
+       if (cc->cc_sqecount > rdma->sc_sq_depth)
+               return -EINVAL;
+
        first_wr = NULL;
        cqe = &cc->cc_cqe;
        list_for_each(tmp, &cc->cc_rwctxts) {
@@ -295,8 +370,9 @@ static void svc_rdma_pagelist_to_sg(struct svc_rdma_write_info *info,
        struct scatterlist *sg;
        struct page **page;
 
-       page_off = (info->wi_next_off + xdr->page_base) & ~PAGE_MASK;
-       page_no = (info->wi_next_off + xdr->page_base) >> PAGE_SHIFT;
+       page_off = info->wi_next_off + xdr->page_base;
+       page_no = page_off >> PAGE_SHIFT;
+       page_off = offset_in_page(page_off);
        page = xdr->pages + page_no;
        info->wi_next_off += remaining;
        sg = ctxt->rw_sg_table.sgl;
@@ -332,7 +408,6 @@ svc_rdma_build_writes(struct svc_rdma_write_info *info,
        __be32 *seg;
        int ret;
 
-       cc->cc_cqe.done = svc_rdma_write_done;
        seg = info->wi_segs + info->wi_seg_no * rpcrdma_segment_maxsz;
        do {
                unsigned int write_len;
@@ -425,6 +500,7 @@ static int svc_rdma_send_xdr_pagelist(struct svc_rdma_write_info *info,
  *
  * Returns a non-negative number of bytes the chunk consumed, or
  *     %-E2BIG if the payload was larger than the Write chunk,
+ *     %-EINVAL if client provided too many segments,
  *     %-ENOMEM if rdma_rw context pool was exhausted,
  *     %-ENOTCONN if posting failed (connection is lost),
  *     %-EIO if rdma_rw initialization failed (DMA mapping, etc).
@@ -465,6 +541,7 @@ out_err:
  *
  * Returns a non-negative number of bytes the chunk consumed, or
  *     %-E2BIG if the payload was larger than the Reply chunk,
+ *     %-EINVAL if client provided too many segments,
  *     %-ENOMEM if rdma_rw context pool was exhausted,
  *     %-ENOTCONN if posting failed (connection is lost),
  *     %-EIO if rdma_rw initialization failed (DMA mapping, etc).
@@ -510,3 +587,353 @@ out_err:
        svc_rdma_write_info_free(info);
        return ret;
 }
+
+static int svc_rdma_build_read_segment(struct svc_rdma_read_info *info,
+                                      struct svc_rqst *rqstp,
+                                      u32 rkey, u32 len, u64 offset)
+{
+       struct svc_rdma_op_ctxt *head = info->ri_readctxt;
+       struct svc_rdma_chunk_ctxt *cc = &info->ri_cc;
+       struct svc_rdma_rw_ctxt *ctxt;
+       unsigned int sge_no, seg_len;
+       struct scatterlist *sg;
+       int ret;
+
+       sge_no = PAGE_ALIGN(info->ri_pageoff + len) >> PAGE_SHIFT;
+       ctxt = svc_rdma_get_rw_ctxt(cc->cc_rdma, sge_no);
+       if (!ctxt)
+               goto out_noctx;
+       ctxt->rw_nents = sge_no;
+
+       dprintk("svcrdma: reading segment %u@0x%016llx:0x%08x (%u sges)\n",
+               len, offset, rkey, sge_no);
+
+       sg = ctxt->rw_sg_table.sgl;
+       for (sge_no = 0; sge_no < ctxt->rw_nents; sge_no++) {
+               seg_len = min_t(unsigned int, len,
+                               PAGE_SIZE - info->ri_pageoff);
+
+               head->arg.pages[info->ri_pageno] =
+                       rqstp->rq_pages[info->ri_pageno];
+               if (!info->ri_pageoff)
+                       head->count++;
+
+               sg_set_page(sg, rqstp->rq_pages[info->ri_pageno],
+                           seg_len, info->ri_pageoff);
+               sg = sg_next(sg);
+
+               info->ri_pageoff += seg_len;
+               if (info->ri_pageoff == PAGE_SIZE) {
+                       info->ri_pageno++;
+                       info->ri_pageoff = 0;
+               }
+               len -= seg_len;
+
+               /* Safety check */
+               if (len &&
+                   &rqstp->rq_pages[info->ri_pageno + 1] > rqstp->rq_page_end)
+                       goto out_overrun;
+       }
+
+       ret = rdma_rw_ctx_init(&ctxt->rw_ctx, cc->cc_rdma->sc_qp,
+                              cc->cc_rdma->sc_port_num,
+                              ctxt->rw_sg_table.sgl, ctxt->rw_nents,
+                              0, offset, rkey, DMA_FROM_DEVICE);
+       if (ret < 0)
+               goto out_initerr;
+
+       list_add(&ctxt->rw_list, &cc->cc_rwctxts);
+       cc->cc_sqecount += ret;
+       return 0;
+
+out_noctx:
+       dprintk("svcrdma: no R/W ctxs available\n");
+       return -ENOMEM;
+
+out_overrun:
+       dprintk("svcrdma: request overruns rq_pages\n");
+       return -EINVAL;
+
+out_initerr:
+       svc_rdma_put_rw_ctxt(cc->cc_rdma, ctxt);
+       pr_err("svcrdma: failed to map pagelist (%d)\n", ret);
+       return -EIO;
+}
+
+static int svc_rdma_build_read_chunk(struct svc_rqst *rqstp,
+                                    struct svc_rdma_read_info *info,
+                                    __be32 *p)
+{
+       int ret;
+
+       info->ri_chunklen = 0;
+       while (*p++ != xdr_zero) {
+               u32 rs_handle, rs_length;
+               u64 rs_offset;
+
+               if (be32_to_cpup(p++) != info->ri_position)
+                       break;
+               rs_handle = be32_to_cpup(p++);
+               rs_length = be32_to_cpup(p++);
+               p = xdr_decode_hyper(p, &rs_offset);
+
+               ret = svc_rdma_build_read_segment(info, rqstp,
+                                                 rs_handle, rs_length,
+                                                 rs_offset);
+               if (ret < 0)
+                       break;
+
+               info->ri_chunklen += rs_length;
+       }
+
+       return ret;
+}
+
+/* If there is inline content following the Read chunk, append it to
+ * the page list immediately following the data payload. This has to
+ * be done after the reader function has determined how many pages
+ * were consumed for RDMA Read.
+ *
+ * On entry, ri_pageno and ri_pageoff point directly to the end of the
+ * page list. On exit, both have been updated to the new "next byte".
+ *
+ * Assumptions:
+ *     - Inline content fits entirely in rq_pages[0]
+ *     - Trailing content is only a handful of bytes
+ */
+static int svc_rdma_copy_tail(struct svc_rqst *rqstp,
+                             struct svc_rdma_read_info *info)
+{
+       struct svc_rdma_op_ctxt *head = info->ri_readctxt;
+       unsigned int tail_length, remaining;
+       u8 *srcp, *destp;
+
+       /* Assert that all inline content fits in page 0. This is an
+        * implementation limit, not a protocol limit.
+        */
+       if (head->arg.head[0].iov_len > PAGE_SIZE) {
+               pr_warn_once("svcrdma: too much trailing inline content\n");
+               return -EINVAL;
+       }
+
+       srcp = head->arg.head[0].iov_base;
+       srcp += info->ri_position;
+       tail_length = head->arg.head[0].iov_len - info->ri_position;
+       remaining = tail_length;
+
+       /* If there is room on the last page in the page list, try to
+        * fit the trailing content there.
+        */
+       if (info->ri_pageoff > 0) {
+               unsigned int len;
+
+               len = min_t(unsigned int, remaining,
+                           PAGE_SIZE - info->ri_pageoff);
+               destp = page_address(rqstp->rq_pages[info->ri_pageno]);
+               destp += info->ri_pageoff;
+
+               memcpy(destp, srcp, len);
+               srcp += len;
+               destp += len;
+               info->ri_pageoff += len;
+               remaining -= len;
+
+               if (info->ri_pageoff == PAGE_SIZE) {
+                       info->ri_pageno++;
+                       info->ri_pageoff = 0;
+               }
+       }
+
+       /* Otherwise, a fresh page is needed. */
+       if (remaining) {
+               head->arg.pages[info->ri_pageno] =
+                               rqstp->rq_pages[info->ri_pageno];
+               head->count++;
+
+               destp = page_address(rqstp->rq_pages[info->ri_pageno]);
+               memcpy(destp, srcp, remaining);
+               info->ri_pageoff += remaining;
+       }
+
+       head->arg.page_len += tail_length;
+       head->arg.len += tail_length;
+       head->arg.buflen += tail_length;
+       return 0;
+}
+
+/* Construct RDMA Reads to pull over a normal Read chunk. The chunk
+ * data lands in the page list of head->arg.pages.
+ *
+ * Currently NFSD does not look at the head->arg.tail[0] iovec.
+ * Therefore, XDR round-up of the Read chunk and trailing
+ * inline content must both be added at the end of the pagelist.
+ */
+static int svc_rdma_build_normal_read_chunk(struct svc_rqst *rqstp,
+                                           struct svc_rdma_read_info *info,
+                                           __be32 *p)
+{
+       struct svc_rdma_op_ctxt *head = info->ri_readctxt;
+       int ret;
+
+       dprintk("svcrdma: Reading Read chunk at position %u\n",
+               info->ri_position);
+
+       info->ri_pageno = head->hdr_count;
+       info->ri_pageoff = 0;
+
+       ret = svc_rdma_build_read_chunk(rqstp, info, p);
+       if (ret < 0)
+               goto out;
+
+       /* Read chunk may need XDR round-up (see RFC 5666, s. 3.7).
+        */
+       if (info->ri_chunklen & 3) {
+               u32 padlen = 4 - (info->ri_chunklen & 3);
+
+               info->ri_chunklen += padlen;
+
+               /* NB: data payload always starts on XDR alignment,
+                * thus the pad can never contain a page boundary.
+                */
+               info->ri_pageoff += padlen;
+               if (info->ri_pageoff == PAGE_SIZE) {
+                       info->ri_pageno++;
+                       info->ri_pageoff = 0;
+               }
+       }
+
+       head->arg.page_len = info->ri_chunklen;
+       head->arg.len += info->ri_chunklen;
+       head->arg.buflen += info->ri_chunklen;
+
+       if (info->ri_position < head->arg.head[0].iov_len) {
+               ret = svc_rdma_copy_tail(rqstp, info);
+               if (ret < 0)
+                       goto out;
+       }
+       head->arg.head[0].iov_len = info->ri_position;
+
+out:
+       return ret;
+}
+
+/* Construct RDMA Reads to pull over a Position Zero Read chunk.
+ * The start of the data lands in the first page just after
+ * the Transport header, and the rest lands in the page list of
+ * head->arg.pages.
+ *
+ * Assumptions:
+ *     - A PZRC has an XDR-aligned length (no implicit round-up).
+ *     - There can be no trailing inline content (IOW, we assume
+ *       a PZRC is never sent in an RDMA_MSG message, though it's
+ *       allowed by spec).
+ */
+static int svc_rdma_build_pz_read_chunk(struct svc_rqst *rqstp,
+                                       struct svc_rdma_read_info *info,
+                                       __be32 *p)
+{
+       struct svc_rdma_op_ctxt *head = info->ri_readctxt;
+       int ret;
+
+       dprintk("svcrdma: Reading Position Zero Read chunk\n");
+
+       info->ri_pageno = head->hdr_count - 1;
+       info->ri_pageoff = offset_in_page(head->byte_len);
+
+       ret = svc_rdma_build_read_chunk(rqstp, info, p);
+       if (ret < 0)
+               goto out;
+
+       head->arg.len += info->ri_chunklen;
+       head->arg.buflen += info->ri_chunklen;
+
+       if (head->arg.buflen <= head->sge[0].length) {
+               /* Transport header and RPC message fit entirely
+                * in page where head iovec resides.
+                */
+               head->arg.head[0].iov_len = info->ri_chunklen;
+       } else {
+               /* Transport header and part of RPC message reside
+                * in the head iovec's page.
+                */
+               head->arg.head[0].iov_len =
+                               head->sge[0].length - head->byte_len;
+               head->arg.page_len =
+                               info->ri_chunklen - head->arg.head[0].iov_len;
+       }
+
+out:
+       return ret;
+}
+
+/**
+ * svc_rdma_recv_read_chunk - Pull a Read chunk from the client
+ * @rdma: controlling RDMA transport
+ * @rqstp: set of pages to use as Read sink buffers
+ * @head: pages under I/O collect here
+ * @p: pointer to start of Read chunk
+ *
+ * Returns:
+ *     %0 if all needed RDMA Reads were posted successfully,
+ *     %-EINVAL if client provided too many segments,
+ *     %-ENOMEM if rdma_rw context pool was exhausted,
+ *     %-ENOTCONN if posting failed (connection is lost),
+ *     %-EIO if rdma_rw initialization failed (DMA mapping, etc).
+ *
+ * Assumptions:
+ * - All Read segments in @p have the same Position value.
+ */
+int svc_rdma_recv_read_chunk(struct svcxprt_rdma *rdma, struct svc_rqst *rqstp,
+                            struct svc_rdma_op_ctxt *head, __be32 *p)
+{
+       struct svc_rdma_read_info *info;
+       struct page **page;
+       int ret;
+
+       /* The request (with page list) is constructed in
+        * head->arg. Pages involved with RDMA Read I/O are
+        * transferred there.
+        */
+       head->hdr_count = head->count;
+       head->arg.head[0] = rqstp->rq_arg.head[0];
+       head->arg.tail[0] = rqstp->rq_arg.tail[0];
+       head->arg.pages = head->pages;
+       head->arg.page_base = 0;
+       head->arg.page_len = 0;
+       head->arg.len = rqstp->rq_arg.len;
+       head->arg.buflen = rqstp->rq_arg.buflen;
+
+       info = svc_rdma_read_info_alloc(rdma);
+       if (!info)
+               return -ENOMEM;
+       info->ri_readctxt = head;
+
+       info->ri_position = be32_to_cpup(p + 1);
+       if (info->ri_position)
+               ret = svc_rdma_build_normal_read_chunk(rqstp, info, p);
+       else
+               ret = svc_rdma_build_pz_read_chunk(rqstp, info, p);
+
+       /* Mark the start of the pages that can be used for the reply */
+       if (info->ri_pageoff > 0)
+               info->ri_pageno++;
+       rqstp->rq_respages = &rqstp->rq_pages[info->ri_pageno];
+       rqstp->rq_next_page = rqstp->rq_respages + 1;
+
+       if (ret < 0)
+               goto out;
+
+       ret = svc_rdma_post_chunk_ctxt(&info->ri_cc);
+
+out:
+       /* Read sink pages have been moved from rqstp->rq_pages to
+        * head->arg.pages. Force svc_recv to refill those slots
+        * in rq_pages.
+        */
+       for (page = rqstp->rq_pages; page < rqstp->rq_respages; page++)
+               *page = NULL;
+
+       if (ret < 0)
+               svc_rdma_read_info_free(info);
+       return ret;
+}
index 1736337..7c3a211 100644 (file)
@@ -313,13 +313,17 @@ static int svc_rdma_dma_map_buf(struct svcxprt_rdma *rdma,
        dma_addr = ib_dma_map_page(dev, virt_to_page(base),
                                   offset, len, DMA_TO_DEVICE);
        if (ib_dma_mapping_error(dev, dma_addr))
-               return -EIO;
+               goto out_maperr;
 
        ctxt->sge[sge_no].addr = dma_addr;
        ctxt->sge[sge_no].length = len;
        ctxt->sge[sge_no].lkey = rdma->sc_pd->local_dma_lkey;
        svc_rdma_count_mappings(rdma, ctxt);
        return 0;
+
+out_maperr:
+       pr_err("svcrdma: failed to map buffer\n");
+       return -EIO;
 }
 
 static int svc_rdma_dma_map_page(struct svcxprt_rdma *rdma,
@@ -334,13 +338,17 @@ static int svc_rdma_dma_map_page(struct svcxprt_rdma *rdma,
 
        dma_addr = ib_dma_map_page(dev, page, offset, len, DMA_TO_DEVICE);
        if (ib_dma_mapping_error(dev, dma_addr))
-               return -EIO;
+               goto out_maperr;
 
        ctxt->sge[sge_no].addr = dma_addr;
        ctxt->sge[sge_no].length = len;
        ctxt->sge[sge_no].lkey = rdma->sc_pd->local_dma_lkey;
        svc_rdma_count_mappings(rdma, ctxt);
        return 0;
+
+out_maperr:
+       pr_err("svcrdma: failed to map page\n");
+       return -EIO;
 }
 
 /**
@@ -547,7 +555,6 @@ static int svc_rdma_send_reply_msg(struct svcxprt_rdma *rdma,
        return 0;
 
 err:
-       pr_err("svcrdma: failed to post Send WR (%d)\n", ret);
        svc_rdma_unmap_dma(ctxt);
        svc_rdma_put_context(ctxt, 1);
        return ret;
@@ -677,7 +684,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
        return 0;
 
  err2:
-       if (ret != -E2BIG)
+       if (ret != -E2BIG && ret != -EINVAL)
                goto err1;
 
        ret = svc_rdma_post_recv(rdma, GFP_KERNEL);
index a9d9cb1..e660d49 100644 (file)
@@ -202,7 +202,6 @@ struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
 out:
        ctxt->count = 0;
        ctxt->mapped_sges = 0;
-       ctxt->frmr = NULL;
        return ctxt;
 
 out_empty:
@@ -226,22 +225,13 @@ void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
 {
        struct svcxprt_rdma *xprt = ctxt->xprt;
        struct ib_device *device = xprt->sc_cm_id->device;
-       u32 lkey = xprt->sc_pd->local_dma_lkey;
        unsigned int i;
 
-       for (i = 0; i < ctxt->mapped_sges; i++) {
-               /*
-                * Unmap the DMA addr in the SGE if the lkey matches
-                * the local_dma_lkey, otherwise, ignore it since it is
-                * an FRMR lkey and will be unmapped later when the
-                * last WR that uses it completes.
-                */
-               if (ctxt->sge[i].lkey == lkey)
-                       ib_dma_unmap_page(device,
-                                           ctxt->sge[i].addr,
-                                           ctxt->sge[i].length,
-                                           ctxt->direction);
-       }
+       for (i = 0; i < ctxt->mapped_sges; i++)
+               ib_dma_unmap_page(device,
+                                 ctxt->sge[i].addr,
+                                 ctxt->sge[i].length,
+                                 ctxt->direction);
        ctxt->mapped_sges = 0;
 }
 
@@ -346,36 +336,6 @@ out:
        svc_xprt_put(&xprt->sc_xprt);
 }
 
-static void svc_rdma_send_wc_common(struct svcxprt_rdma *xprt,
-                                   struct ib_wc *wc,
-                                   const char *opname)
-{
-       if (wc->status != IB_WC_SUCCESS)
-               goto err;
-
-out:
-       atomic_inc(&xprt->sc_sq_avail);
-       wake_up(&xprt->sc_send_wait);
-       return;
-
-err:
-       set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
-       if (wc->status != IB_WC_WR_FLUSH_ERR)
-               pr_err("svcrdma: %s: %s (%u/0x%x)\n",
-                      opname, ib_wc_status_msg(wc->status),
-                      wc->status, wc->vendor_err);
-       goto out;
-}
-
-static void svc_rdma_send_wc_common_put(struct ib_cq *cq, struct ib_wc *wc,
-                                       const char *opname)
-{
-       struct svcxprt_rdma *xprt = cq->cq_context;
-
-       svc_rdma_send_wc_common(xprt, wc, opname);
-       svc_xprt_put(&xprt->sc_xprt);
-}
-
 /**
  * svc_rdma_wc_send - Invoked by RDMA provider for each polled Send WC
  * @cq:        completion queue
@@ -384,73 +344,28 @@ static void svc_rdma_send_wc_common_put(struct ib_cq *cq, struct ib_wc *wc,
  */
 void svc_rdma_wc_send(struct ib_cq *cq, struct ib_wc *wc)
 {
-       struct ib_cqe *cqe = wc->wr_cqe;
-       struct svc_rdma_op_ctxt *ctxt;
-
-       svc_rdma_send_wc_common_put(cq, wc, "send");
-
-       ctxt = container_of(cqe, struct svc_rdma_op_ctxt, cqe);
-       svc_rdma_unmap_dma(ctxt);
-       svc_rdma_put_context(ctxt, 1);
-}
-
-/**
- * svc_rdma_wc_reg - Invoked by RDMA provider for each polled FASTREG WC
- * @cq:        completion queue
- * @wc:        completed WR
- *
- */
-void svc_rdma_wc_reg(struct ib_cq *cq, struct ib_wc *wc)
-{
-       svc_rdma_send_wc_common_put(cq, wc, "fastreg");
-}
-
-/**
- * svc_rdma_wc_read - Invoked by RDMA provider for each polled Read WC
- * @cq:        completion queue
- * @wc:        completed WR
- *
- */
-void svc_rdma_wc_read(struct ib_cq *cq, struct ib_wc *wc)
-{
        struct svcxprt_rdma *xprt = cq->cq_context;
        struct ib_cqe *cqe = wc->wr_cqe;
        struct svc_rdma_op_ctxt *ctxt;
 
-       svc_rdma_send_wc_common(xprt, wc, "read");
+       atomic_inc(&xprt->sc_sq_avail);
+       wake_up(&xprt->sc_send_wait);
 
        ctxt = container_of(cqe, struct svc_rdma_op_ctxt, cqe);
        svc_rdma_unmap_dma(ctxt);
-       svc_rdma_put_frmr(xprt, ctxt->frmr);
-
-       if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
-               struct svc_rdma_op_ctxt *read_hdr;
-
-               read_hdr = ctxt->read_hdr;
-               spin_lock(&xprt->sc_rq_dto_lock);
-               list_add_tail(&read_hdr->list,
-                             &xprt->sc_read_complete_q);
-               spin_unlock(&xprt->sc_rq_dto_lock);
+       svc_rdma_put_context(ctxt, 1);
 
-               set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
-               svc_xprt_enqueue(&xprt->sc_xprt);
+       if (unlikely(wc->status != IB_WC_SUCCESS)) {
+               set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+               if (wc->status != IB_WC_WR_FLUSH_ERR)
+                       pr_err("svcrdma: Send: %s (%u/0x%x)\n",
+                              ib_wc_status_msg(wc->status),
+                              wc->status, wc->vendor_err);
        }
 
-       svc_rdma_put_context(ctxt, 0);
        svc_xprt_put(&xprt->sc_xprt);
 }
 
-/**
- * svc_rdma_wc_inv - Invoked by RDMA provider for each polled LOCAL_INV WC
- * @cq:        completion queue
- * @wc:        completed WR
- *
- */
-void svc_rdma_wc_inv(struct ib_cq *cq, struct ib_wc *wc)
-{
-       svc_rdma_send_wc_common_put(cq, wc, "localInv");
-}
-
 static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
                                             int listener)
 {
@@ -462,14 +377,12 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
        INIT_LIST_HEAD(&cma_xprt->sc_accept_q);
        INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q);
        INIT_LIST_HEAD(&cma_xprt->sc_read_complete_q);
-       INIT_LIST_HEAD(&cma_xprt->sc_frmr_q);
        INIT_LIST_HEAD(&cma_xprt->sc_ctxts);
        INIT_LIST_HEAD(&cma_xprt->sc_rw_ctxts);
        init_waitqueue_head(&cma_xprt->sc_send_wait);
 
        spin_lock_init(&cma_xprt->sc_lock);
        spin_lock_init(&cma_xprt->sc_rq_dto_lock);
-       spin_lock_init(&cma_xprt->sc_frmr_q_lock);
        spin_lock_init(&cma_xprt->sc_ctxt_lock);
        spin_lock_init(&cma_xprt->sc_rw_ctxt_lock);
 
@@ -780,86 +693,6 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
        return ERR_PTR(ret);
 }
 
-static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
-{
-       struct ib_mr *mr;
-       struct scatterlist *sg;
-       struct svc_rdma_fastreg_mr *frmr;
-       u32 num_sg;
-
-       frmr = kmalloc(sizeof(*frmr), GFP_KERNEL);
-       if (!frmr)
-               goto err;
-
-       num_sg = min_t(u32, RPCSVC_MAXPAGES, xprt->sc_frmr_pg_list_len);
-       mr = ib_alloc_mr(xprt->sc_pd, IB_MR_TYPE_MEM_REG, num_sg);
-       if (IS_ERR(mr))
-               goto err_free_frmr;
-
-       sg = kcalloc(RPCSVC_MAXPAGES, sizeof(*sg), GFP_KERNEL);
-       if (!sg)
-               goto err_free_mr;
-
-       sg_init_table(sg, RPCSVC_MAXPAGES);
-
-       frmr->mr = mr;
-       frmr->sg = sg;
-       INIT_LIST_HEAD(&frmr->frmr_list);
-       return frmr;
-
- err_free_mr:
-       ib_dereg_mr(mr);
- err_free_frmr:
-       kfree(frmr);
- err:
-       return ERR_PTR(-ENOMEM);
-}
-
-static void rdma_dealloc_frmr_q(struct svcxprt_rdma *xprt)
-{
-       struct svc_rdma_fastreg_mr *frmr;
-
-       while (!list_empty(&xprt->sc_frmr_q)) {
-               frmr = list_entry(xprt->sc_frmr_q.next,
-                                 struct svc_rdma_fastreg_mr, frmr_list);
-               list_del_init(&frmr->frmr_list);
-               kfree(frmr->sg);
-               ib_dereg_mr(frmr->mr);
-               kfree(frmr);
-       }
-}
-
-struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *rdma)
-{
-       struct svc_rdma_fastreg_mr *frmr = NULL;
-
-       spin_lock(&rdma->sc_frmr_q_lock);
-       if (!list_empty(&rdma->sc_frmr_q)) {
-               frmr = list_entry(rdma->sc_frmr_q.next,
-                                 struct svc_rdma_fastreg_mr, frmr_list);
-               list_del_init(&frmr->frmr_list);
-               frmr->sg_nents = 0;
-       }
-       spin_unlock(&rdma->sc_frmr_q_lock);
-       if (frmr)
-               return frmr;
-
-       return rdma_alloc_frmr(rdma);
-}
-
-void svc_rdma_put_frmr(struct svcxprt_rdma *rdma,
-                      struct svc_rdma_fastreg_mr *frmr)
-{
-       if (frmr) {
-               ib_dma_unmap_sg(rdma->sc_cm_id->device,
-                               frmr->sg, frmr->sg_nents, frmr->direction);
-               spin_lock(&rdma->sc_frmr_q_lock);
-               WARN_ON_ONCE(!list_empty(&frmr->frmr_list));
-               list_add(&frmr->frmr_list, &rdma->sc_frmr_q);
-               spin_unlock(&rdma->sc_frmr_q_lock);
-       }
-}
-
 /*
  * This is the xpo_recvfrom function for listening endpoints. Its
  * purpose is to accept incoming connections. The CMA callback handler
@@ -908,8 +741,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
         * capabilities of this particular device */
        newxprt->sc_max_sge = min((size_t)dev->attrs.max_sge,
                                  (size_t)RPCSVC_MAXPAGES);
-       newxprt->sc_max_sge_rd = min_t(size_t, dev->attrs.max_sge_rd,
-                                      RPCSVC_MAXPAGES);
        newxprt->sc_max_req_size = svcrdma_max_req_size;
        newxprt->sc_max_requests = min_t(u32, dev->attrs.max_qp_wr,
                                         svcrdma_max_requests);
@@ -952,7 +783,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
        memset(&qp_attr, 0, sizeof qp_attr);
        qp_attr.event_handler = qp_event_handler;
        qp_attr.qp_context = &newxprt->sc_xprt;
-       qp_attr.port_num = newxprt->sc_cm_id->port_num;
+       qp_attr.port_num = newxprt->sc_port_num;
        qp_attr.cap.max_rdma_ctxs = newxprt->sc_max_requests;
        qp_attr.cap.max_send_wr = newxprt->sc_sq_depth;
        qp_attr.cap.max_recv_wr = newxprt->sc_rq_depth;
@@ -976,47 +807,12 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
        }
        newxprt->sc_qp = newxprt->sc_cm_id->qp;
 
-       /*
-        * Use the most secure set of MR resources based on the
-        * transport type and available memory management features in
-        * the device. Here's the table implemented below:
-        *
-        *              Fast    Global  DMA     Remote WR
-        *              Reg     LKEY    MR      Access
-        *              Sup'd   Sup'd   Needed  Needed
-        *
-        * IWARP        N       N       Y       Y
-        *              N       Y       Y       Y
-        *              Y       N       Y       N
-        *              Y       Y       N       -
-        *
-        * IB           N       N       Y       N
-        *              N       Y       N       -
-        *              Y       N       Y       N
-        *              Y       Y       N       -
-        *
-        * NB:  iWARP requires remote write access for the data sink
-        *      of an RDMA_READ. IB does not.
-        */
-       newxprt->sc_reader = rdma_read_chunk_lcl;
-       if (dev->attrs.device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) {
-               newxprt->sc_frmr_pg_list_len =
-                       dev->attrs.max_fast_reg_page_list_len;
-               newxprt->sc_dev_caps |= SVCRDMA_DEVCAP_FAST_REG;
-               newxprt->sc_reader = rdma_read_chunk_frmr;
-       } else
+       if (!(dev->attrs.device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS))
                newxprt->sc_snd_w_inv = false;
-
-       /*
-        * Determine if a DMA MR is required and if so, what privs are required
-        */
-       if (!rdma_protocol_iwarp(dev, newxprt->sc_cm_id->port_num) &&
-           !rdma_ib_or_roce(dev, newxprt->sc_cm_id->port_num))
+       if (!rdma_protocol_iwarp(dev, newxprt->sc_port_num) &&
+           !rdma_ib_or_roce(dev, newxprt->sc_port_num))
                goto errout;
 
-       if (rdma_protocol_iwarp(dev, newxprt->sc_cm_id->port_num))
-               newxprt->sc_dev_caps |= SVCRDMA_DEVCAP_READ_W_INV;
-
        /* Post receive buffers */
        for (i = 0; i < newxprt->sc_max_requests; i++) {
                ret = svc_rdma_post_recv(newxprt, GFP_KERNEL);
@@ -1056,7 +852,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
        sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr;
        dprintk("    remote address  : %pIS:%u\n", sap, rpc_get_port(sap));
        dprintk("    max_sge         : %d\n", newxprt->sc_max_sge);
-       dprintk("    max_sge_rd      : %d\n", newxprt->sc_max_sge_rd);
        dprintk("    sq_depth        : %d\n", newxprt->sc_sq_depth);
        dprintk("    max_requests    : %d\n", newxprt->sc_max_requests);
        dprintk("    ord             : %d\n", newxprt->sc_ord);
@@ -1117,12 +912,6 @@ static void __svc_rdma_free(struct work_struct *work)
                pr_err("svcrdma: sc_xprt still in use? (%d)\n",
                       kref_read(&xprt->xpt_ref));
 
-       /*
-        * Destroy queued, but not processed read completions. Note
-        * that this cleanup has to be done before destroying the
-        * cm_id because the device ptr is needed to unmap the dma in
-        * svc_rdma_put_context.
-        */
        while (!list_empty(&rdma->sc_read_complete_q)) {
                struct svc_rdma_op_ctxt *ctxt;
                ctxt = list_first_entry(&rdma->sc_read_complete_q,
@@ -1130,8 +919,6 @@ static void __svc_rdma_free(struct work_struct *work)
                list_del(&ctxt->list);
                svc_rdma_put_context(ctxt, 1);
        }
-
-       /* Destroy queued, but not processed recv completions */
        while (!list_empty(&rdma->sc_rq_dto_q)) {
                struct svc_rdma_op_ctxt *ctxt;
                ctxt = list_first_entry(&rdma->sc_rq_dto_q,
@@ -1151,7 +938,6 @@ static void __svc_rdma_free(struct work_struct *work)
                xprt->xpt_bc_xprt = NULL;
        }
 
-       rdma_dealloc_frmr_q(rdma);
        svc_rdma_destroy_rw_ctxts(rdma);
        svc_rdma_destroy_ctxts(rdma);
 
index 62ecbcc..d1c458e 100644 (file)
@@ -684,7 +684,8 @@ xprt_rdma_free(struct rpc_task *task)
 
        dprintk("RPC:       %s: called on 0x%p\n", __func__, req->rl_reply);
 
-       if (unlikely(!list_empty(&req->rl_registered)))
+       rpcrdma_remove_req(&r_xprt->rx_buf, req);
+       if (!list_empty(&req->rl_registered))
                ia->ri_ops->ro_unmap_safe(r_xprt, req, !RPC_IS_ASYNC(task));
        rpcrdma_unmap_sges(ia, req);
        rpcrdma_buffer_put(req);
index 3dbce9a..e4171f2 100644 (file)
@@ -243,8 +243,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
        struct sockaddr *sap = (struct sockaddr *)&ep->rep_remote_addr;
 #endif
-       struct ib_qp_attr *attr = &ia->ri_qp_attr;
-       struct ib_qp_init_attr *iattr = &ia->ri_qp_init_attr;
        int connstate = 0;
 
        switch (event->event) {
@@ -267,7 +265,8 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
                break;
        case RDMA_CM_EVENT_DEVICE_REMOVAL:
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-               pr_info("rpcrdma: removing device for %pIS:%u\n",
+               pr_info("rpcrdma: removing device %s for %pIS:%u\n",
+                       ia->ri_device->name,
                        sap, rpc_get_port(sap));
 #endif
                set_bit(RPCRDMA_IAF_REMOVING, &ia->ri_flags);
@@ -282,13 +281,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
                return 1;
        case RDMA_CM_EVENT_ESTABLISHED:
                connstate = 1;
-               ib_query_qp(ia->ri_id->qp, attr,
-                           IB_QP_MAX_QP_RD_ATOMIC | IB_QP_MAX_DEST_RD_ATOMIC,
-                           iattr);
-               dprintk("RPC:       %s: %d responder resources"
-                       " (%d initiator)\n",
-                       __func__, attr->max_dest_rd_atomic,
-                       attr->max_rd_atomic);
                rpcrdma_update_connect_private(xprt, &event->param.conn);
                goto connected;
        case RDMA_CM_EVENT_CONNECT_ERROR:
@@ -298,11 +290,9 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
                connstate = -ENETDOWN;
                goto connected;
        case RDMA_CM_EVENT_REJECTED:
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-               pr_info("rpcrdma: connection to %pIS:%u on %s rejected: %s\n",
-                       sap, rpc_get_port(sap), ia->ri_device->name,
+               dprintk("rpcrdma: connection to %pIS:%u rejected: %s\n",
+                       sap, rpc_get_port(sap),
                        rdma_reject_msg(id, event->status));
-#endif
                connstate = -ECONNREFUSED;
                if (event->status == IB_CM_REJ_STALE_CONN)
                        connstate = -EAGAIN;
@@ -310,37 +300,19 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
        case RDMA_CM_EVENT_DISCONNECTED:
                connstate = -ECONNABORTED;
 connected:
-               dprintk("RPC:       %s: %sconnected\n",
-                                       __func__, connstate > 0 ? "" : "dis");
                atomic_set(&xprt->rx_buf.rb_credits, 1);
                ep->rep_connected = connstate;
                rpcrdma_conn_func(ep);
                wake_up_all(&ep->rep_connect_wait);
                /*FALLTHROUGH*/
        default:
-               dprintk("RPC:       %s: %pIS:%u (ep 0x%p): %s\n",
-                       __func__, sap, rpc_get_port(sap), ep,
-                       rdma_event_msg(event->event));
+               dprintk("RPC:       %s: %pIS:%u on %s/%s (ep 0x%p): %s\n",
+                       __func__, sap, rpc_get_port(sap),
+                       ia->ri_device->name, ia->ri_ops->ro_displayname,
+                       ep, rdma_event_msg(event->event));
                break;
        }
 
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-       if (connstate == 1) {
-               int ird = attr->max_dest_rd_atomic;
-               int tird = ep->rep_remote_cma.responder_resources;
-
-               pr_info("rpcrdma: connection to %pIS:%u on %s, memreg '%s', %d credits, %d responders%s\n",
-                       sap, rpc_get_port(sap),
-                       ia->ri_device->name,
-                       ia->ri_ops->ro_displayname,
-                       xprt->rx_buf.rb_max_requests,
-                       ird, ird < 4 && ird < tird / 2 ? " (low!)" : "");
-       } else if (connstate < 0) {
-               pr_info("rpcrdma: connection to %pIS:%u closed (%d)\n",
-                       sap, rpc_get_port(sap), connstate);
-       }
-#endif
-
        return 0;
 }
 
@@ -971,7 +943,6 @@ rpcrdma_create_req(struct rpcrdma_xprt *r_xprt)
        if (req == NULL)
                return ERR_PTR(-ENOMEM);
 
-       INIT_LIST_HEAD(&req->rl_free);
        spin_lock(&buffer->rb_reqslock);
        list_add(&req->rl_all, &buffer->rb_allreqs);
        spin_unlock(&buffer->rb_reqslock);
@@ -1033,6 +1004,7 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
        spin_lock_init(&buf->rb_recovery_lock);
        INIT_LIST_HEAD(&buf->rb_mws);
        INIT_LIST_HEAD(&buf->rb_all);
+       INIT_LIST_HEAD(&buf->rb_pending);
        INIT_LIST_HEAD(&buf->rb_stale_mrs);
        INIT_DELAYED_WORK(&buf->rb_refresh_worker,
                          rpcrdma_mr_refresh_worker);
@@ -1055,7 +1027,7 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
                        goto out;
                }
                req->rl_backchannel = false;
-               list_add(&req->rl_free, &buf->rb_send_bufs);
+               list_add(&req->rl_list, &buf->rb_send_bufs);
        }
 
        INIT_LIST_HEAD(&buf->rb_recv_bufs);
@@ -1084,8 +1056,8 @@ rpcrdma_buffer_get_req_locked(struct rpcrdma_buffer *buf)
        struct rpcrdma_req *req;
 
        req = list_first_entry(&buf->rb_send_bufs,
-                              struct rpcrdma_req, rl_free);
-       list_del(&req->rl_free);
+                              struct rpcrdma_req, rl_list);
+       list_del_init(&req->rl_list);
        return req;
 }
 
@@ -1187,6 +1159,7 @@ rpcrdma_get_mw(struct rpcrdma_xprt *r_xprt)
 
        if (!mw)
                goto out_nomws;
+       mw->mw_flags = 0;
        return mw;
 
 out_nomws:
@@ -1267,7 +1240,7 @@ rpcrdma_buffer_put(struct rpcrdma_req *req)
 
        spin_lock(&buffers->rb_lock);
        buffers->rb_send_count--;
-       list_add_tail(&req->rl_free, &buffers->rb_send_bufs);
+       list_add_tail(&req->rl_list, &buffers->rb_send_bufs);
        if (rep) {
                buffers->rb_recv_count--;
                list_add_tail(&rep->rr_list, &buffers->rb_recv_bufs);
index 1d66acf..b282d3f 100644 (file)
@@ -271,6 +271,7 @@ struct rpcrdma_mw {
        struct scatterlist      *mw_sg;
        int                     mw_nents;
        enum dma_data_direction mw_dir;
+       unsigned long           mw_flags;
        union {
                struct rpcrdma_fmr      fmr;
                struct rpcrdma_frmr     frmr;
@@ -282,6 +283,11 @@ struct rpcrdma_mw {
        struct list_head        mw_all;
 };
 
+/* mw_flags */
+enum {
+       RPCRDMA_MW_F_RI         = 1,
+};
+
 /*
  * struct rpcrdma_req -- structure central to the request/reply sequence.
  *
@@ -334,7 +340,8 @@ enum {
 
 struct rpcrdma_buffer;
 struct rpcrdma_req {
-       struct list_head        rl_free;
+       struct list_head        rl_list;
+       __be32                  rl_xid;
        unsigned int            rl_mapped_sges;
        unsigned int            rl_connect_cookie;
        struct rpcrdma_buffer   *rl_buffer;
@@ -396,6 +403,7 @@ struct rpcrdma_buffer {
        int                     rb_send_count, rb_recv_count;
        struct list_head        rb_send_bufs;
        struct list_head        rb_recv_bufs;
+       struct list_head        rb_pending;
        u32                     rb_max_requests;
        atomic_t                rb_credits;     /* most recent credit grant */
 
@@ -461,7 +469,7 @@ struct rpcrdma_memreg_ops {
                                  struct rpcrdma_mr_seg *, int, bool,
                                  struct rpcrdma_mw **);
        void            (*ro_unmap_sync)(struct rpcrdma_xprt *,
-                                        struct rpcrdma_req *);
+                                        struct list_head *);
        void            (*ro_unmap_safe)(struct rpcrdma_xprt *,
                                         struct rpcrdma_req *, bool);
        void            (*ro_recover_mr)(struct rpcrdma_mw *);
@@ -544,6 +552,34 @@ void rpcrdma_destroy_req(struct rpcrdma_req *);
 int rpcrdma_buffer_create(struct rpcrdma_xprt *);
 void rpcrdma_buffer_destroy(struct rpcrdma_buffer *);
 
+static inline void
+rpcrdma_insert_req(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req)
+{
+       spin_lock(&buffers->rb_lock);
+       if (list_empty(&req->rl_list))
+               list_add_tail(&req->rl_list, &buffers->rb_pending);
+       spin_unlock(&buffers->rb_lock);
+}
+
+static inline struct rpcrdma_req *
+rpcrdma_lookup_req_locked(struct rpcrdma_buffer *buffers, __be32 xid)
+{
+       struct rpcrdma_req *pos;
+
+       list_for_each_entry(pos, &buffers->rb_pending, rl_list)
+               if (pos->rl_xid == xid)
+                       return pos;
+       return NULL;
+}
+
+static inline void
+rpcrdma_remove_req(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req)
+{
+       spin_lock(&buffers->rb_lock);
+       list_del(&req->rl_list);
+       spin_unlock(&buffers->rb_lock);
+}
+
 struct rpcrdma_mw *rpcrdma_get_mw(struct rpcrdma_xprt *);
 void rpcrdma_put_mw(struct rpcrdma_xprt *, struct rpcrdma_mw *);
 struct rpcrdma_req *rpcrdma_buffer_get(struct rpcrdma_buffer *);
index d5b54c0..4f154d3 100644 (file)
@@ -1624,6 +1624,8 @@ static void xs_tcp_state_change(struct sock *sk)
                if (test_and_clear_bit(XPRT_SOCK_CONNECTING,
                                        &transport->sock_state))
                        xprt_clear_connecting(xprt);
+               if (sk->sk_err)
+                       xprt_wake_pending_tasks(xprt, -sk->sk_err);
                xs_sock_mark_closed(xprt);
        }
  out:
index 9c823a6..270edcc 100644 (file)
@@ -147,9 +147,9 @@ int _geneve_set_tunnel(struct __sk_buff *skb)
        __builtin_memset(&gopt, 0x0, sizeof(gopt));
        gopt.opt_class = 0x102; /* Open Virtual Networking (OVN) */
        gopt.type = 0x08;
-       gopt.r1 = 1;
+       gopt.r1 = 0;
        gopt.r2 = 0;
-       gopt.r3 = 1;
+       gopt.r3 = 0;
        gopt.length = 2; /* 4-byte multiple */
        *(int *) &gopt.opt_data = 0xdeadbeef;
 
index 1ff634f..a70d2ea 100755 (executable)
@@ -149,6 +149,7 @@ function cleanup {
        ip link del veth1
        ip link del ipip11
        ip link del gretap11
+       ip link del vxlan11
        ip link del geneve11
        pkill tcpdump
        pkill cat
index aa243db..be0d4a5 100644 (file)
@@ -75,8 +75,8 @@ static int __init example_init(void)
        for (i = 0; i < nents; i++) {
                printk(KERN_INFO
                "sg[%d] -> "
-               "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n",
-                       i, sg[i].page_link, sg[i].offset, sg[i].length);
+               "page %p offset 0x%.8x length 0x%.8x\n",
+                       i, sg_page(&sg[i]), sg[i].offset, sg[i].length);
 
                if (sg_is_last(&sg[i]))
                        break;
@@ -104,8 +104,8 @@ static int __init example_init(void)
        for (i = 0; i < nents; i++) {
                printk(KERN_INFO
                "sg[%d] -> "
-               "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n",
-                       i, sg[i].page_link, sg[i].offset, sg[i].length);
+               "page %p offset 0x%.8x length 0x%.8x\n",
+                       i, sg_page(&sg[i]), sg[i].offset, sg[i].length);
 
                if (sg_is_last(&sg[i]))
                        break;
index c583a1e..343d586 100644 (file)
@@ -23,15 +23,12 @@ subdirs       := $(patsubst $(srcdir)/%/,%,\
                 $(filter-out $(srcdir)/,\
                 $(sort $(dir $(wildcard $(srcdir)/*/)))))
 
-# caller may set destination dir (when installing to asm/)
-_dst          := $(if $(dst),$(dst),$(obj))
-
 # Recursion
 __headers: $(subdirs)
 
 .PHONY: $(subdirs)
 $(subdirs):
-       $(Q)$(MAKE) $(hdr-inst)=$(obj)/$@ dst=$(_dst)/$@
+       $(Q)$(MAKE) $(hdr-inst)=$(obj)/$@ dst=$(dst)/$@
 
 # Skip header install/check for include/uapi and arch/$(hdr-arch)/include/uapi.
 # We have only sub-directories there.
@@ -39,21 +36,12 @@ skip-inst := $(if $(filter %/uapi,$(obj)),1)
 
 ifeq ($(skip-inst),)
 
-# generated header directory
-gen := $(if $(gen),$(gen),$(subst include/,include/generated/,$(obj)))
-
 # Kbuild file is optional
 kbuild-file := $(srctree)/$(obj)/Kbuild
 -include $(kbuild-file)
 
-old-kbuild-file := $(srctree)/$(subst uapi/,,$(obj))/Kbuild
-ifneq ($(wildcard $(old-kbuild-file)),)
-include $(old-kbuild-file)
-endif
-
-installdir    := $(INSTALL_HDR_PATH)/$(subst uapi/,,$(_dst))
-
-gendir        := $(objtree)/$(gen)
+installdir    := $(INSTALL_HDR_PATH)/$(dst)
+gendir        := $(objtree)/$(subst include/,include/generated/,$(obj))
 header-files  := $(notdir $(wildcard $(srcdir)/*.h))
 header-files  += $(notdir $(wildcard $(srcdir)/*.agh))
 header-files  := $(filter-out $(no-export-headers), $(header-files))
@@ -64,14 +52,8 @@ genhdr-files  := $(filter-out $(header-files), $(genhdr-files))
 install-file  := $(installdir)/.install
 check-file    := $(installdir)/.check
 
-# generic-y list all files an architecture uses from asm-generic
-# Use this to build a list of headers which require a wrapper
-generic-files := $(notdir $(wildcard $(srctree)/include/uapi/asm-generic/*.h))
-wrapper-files := $(filter $(generic-files), $(generic-y))
-wrapper-files := $(filter-out $(header-files), $(wrapper-files))
-
 # all headers files for this dir
-all-files     := $(header-files) $(genhdr-files) $(wrapper-files)
+all-files     := $(header-files) $(genhdr-files)
 output-files  := $(addprefix $(installdir)/, $(all-files))
 
 ifneq ($(mandatory-y),)
@@ -95,9 +77,6 @@ quiet_cmd_install = INSTALL $(printdir) ($(words $(all-files))\
       cmd_install = \
         $(CONFIG_SHELL) $< $(installdir) $(srcdir) $(header-files); \
         $(CONFIG_SHELL) $< $(installdir) $(gendir) $(genhdr-files); \
-        for F in $(wrapper-files); do                                   \
-                echo "\#include <asm-generic/$$F>" > $(installdir)/$$F;    \
-        done;                                                           \
         touch $@
 
 quiet_cmd_remove = REMOVE  $(unwanted)
index 8f940c0..2287a0b 100755 (executable)
@@ -5576,10 +5576,18 @@ sub process {
                            "architecture specific defines should be avoided\n" .  $herecurr);
                }
 
+# check that the storage class is not after a type
+               if ($line =~ /\b($Type)\s+($Storage)\b/) {
+                       WARN("STORAGE_CLASS",
+                            "storage class '$2' should be located before type '$1'\n" . $herecurr);
+               }
 # Check that the storage class is at the beginning of a declaration
-               if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) {
+               if ($line =~ /\b$Storage\b/ &&
+                   $line !~ /^.\s*$Storage/ &&
+                   $line =~ /^.\s*(.+?)\$Storage\s/ &&
+                   $1 !~ /[\,\)]\s*$/) {
                        WARN("STORAGE_CLASS",
-                            "storage class should be at the beginning of the declaration\n" . $herecurr)
+                            "storage class should be at the beginning of the declaration\n" . $herecurr);
                }
 
 # check the location of the inline attribute, that it is between
index fb86f38..f9a3d8d 100755 (executable)
@@ -321,7 +321,7 @@ fi
 cpp_flags="\
        -nostdinc                                  \
        -I${srctree}/arch/${ARCH}/boot/dts         \
-       -I${srctree}/arch/${ARCH}/boot/dts/include \
+       -I${srctree}/scripts/dtc/include-prefixes  \
        -I${srctree}/drivers/of/testcase-data      \
        -undef -D__DTS__"
 
index 7986f4e..7aad824 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/fs.h>
 #include <linux/mount.h>
+#include <linux/of_fdt.h>
 
 /* We need to stringify expanded macros so that they can be parsed */
 
@@ -50,3 +51,9 @@ LX_VALUE(MNT_NOEXEC)
 LX_VALUE(MNT_NOATIME)
 LX_VALUE(MNT_NODIRATIME)
 LX_VALUE(MNT_RELATIME)
+
+/* linux/of_fdt.h> */
+LX_VALUE(OF_DT_HEADER)
+
+/* Kernel Configs */
+LX_CONFIG(CONFIG_OF)
index 5afd109..6d2e09a 100644 (file)
@@ -12,6 +12,7 @@
 #
 
 import gdb
+import sys
 
 from linux import utils
 
@@ -24,7 +25,7 @@ class LxDmesg(gdb.Command):
 
     def invoke(self, arg, from_tty):
         log_buf_addr = int(str(gdb.parse_and_eval(
-            "'printk.c'::log_buf")).split()[0], 16)
+            "(void *)'printk.c'::log_buf")).split()[0], 16)
         log_first_idx = int(gdb.parse_and_eval("'printk.c'::log_first_idx"))
         log_next_idx = int(gdb.parse_and_eval("'printk.c'::log_next_idx"))
         log_buf_len = int(gdb.parse_and_eval("'printk.c'::log_buf_len"))
@@ -52,13 +53,19 @@ class LxDmesg(gdb.Command):
                 continue
 
             text_len = utils.read_u16(log_buf[pos + 10:pos + 12])
-            text = log_buf[pos + 16:pos + 16 + text_len].decode()
+            text = log_buf[pos + 16:pos + 16 + text_len].decode(
+                encoding='utf8', errors='replace')
             time_stamp = utils.read_u64(log_buf[pos:pos + 8])
 
             for line in text.splitlines():
-                gdb.write("[{time:12.6f}] {line}\n".format(
+                msg = u"[{time:12.6f}] {line}\n".format(
                     time=time_stamp / 1000000000.0,
-                    line=line))
+                    line=line)
+                # With python2 gdb.write will attempt to convert unicode to
+                # ascii and might fail so pass an utf8-encoded str instead.
+                if sys.hexversion < 0x03000000:
+                    msg = msg.encode(encoding='utf8', errors='replace')
+                gdb.write(msg)
 
             pos += length
 
index 38b1f09..086d272 100644 (file)
@@ -16,6 +16,7 @@ from linux import constants
 from linux import utils
 from linux import tasks
 from linux import lists
+from struct import *
 
 
 class LxCmdLine(gdb.Command):
@@ -195,3 +196,75 @@ values of that process namespace"""
                         info_opts(MNT_INFO, m_flags)))
 
 LxMounts()
+
+
+class LxFdtDump(gdb.Command):
+    """Output Flattened Device Tree header and dump FDT blob to the filename
+       specified as the command argument. Equivalent to
+       'cat /proc/fdt > fdtdump.dtb' on a running target"""
+
+    def __init__(self):
+        super(LxFdtDump, self).__init__("lx-fdtdump", gdb.COMMAND_DATA,
+                                        gdb.COMPLETE_FILENAME)
+
+    def fdthdr_to_cpu(self, fdt_header):
+
+        fdt_header_be = ">IIIIIII"
+        fdt_header_le = "<IIIIIII"
+
+        if utils.get_target_endianness() == 1:
+            output_fmt = fdt_header_le
+        else:
+            output_fmt = fdt_header_be
+
+        return unpack(output_fmt, pack(fdt_header_be,
+                                       fdt_header['magic'],
+                                       fdt_header['totalsize'],
+                                       fdt_header['off_dt_struct'],
+                                       fdt_header['off_dt_strings'],
+                                       fdt_header['off_mem_rsvmap'],
+                                       fdt_header['version'],
+                                       fdt_header['last_comp_version']))
+
+    def invoke(self, arg, from_tty):
+
+        if not constants.LX_CONFIG_OF:
+            raise gdb.GdbError("Kernel not compiled with CONFIG_OF\n")
+
+        if len(arg) == 0:
+            filename = "fdtdump.dtb"
+        else:
+            filename = arg
+
+        py_fdt_header_ptr = gdb.parse_and_eval(
+            "(const struct fdt_header *) initial_boot_params")
+        py_fdt_header = py_fdt_header_ptr.dereference()
+
+        fdt_header = self.fdthdr_to_cpu(py_fdt_header)
+
+        if fdt_header[0] != constants.LX_OF_DT_HEADER:
+            raise gdb.GdbError("No flattened device tree magic found\n")
+
+        gdb.write("fdt_magic:         0x{:02X}\n".format(fdt_header[0]))
+        gdb.write("fdt_totalsize:     0x{:02X}\n".format(fdt_header[1]))
+        gdb.write("off_dt_struct:     0x{:02X}\n".format(fdt_header[2]))
+        gdb.write("off_dt_strings:    0x{:02X}\n".format(fdt_header[3]))
+        gdb.write("off_mem_rsvmap:    0x{:02X}\n".format(fdt_header[4]))
+        gdb.write("version:           {}\n".format(fdt_header[5]))
+        gdb.write("last_comp_version: {}\n".format(fdt_header[6]))
+
+        inf = gdb.inferiors()[0]
+        fdt_buf = utils.read_memoryview(inf, py_fdt_header_ptr,
+                                        fdt_header[1]).tobytes()
+
+        try:
+            f = open(filename, 'wb')
+        except:
+            raise gdb.GdbError("Could not open file to dump fdt")
+
+        f.write(fdt_buf)
+        f.close()
+
+        gdb.write("Dumped fdt blob to " + filename + "\n")
+
+LxFdtDump()
diff --git a/scripts/parse-maintainers.pl b/scripts/parse-maintainers.pl
new file mode 100644 (file)
index 0000000..a0fe343
--- /dev/null
@@ -0,0 +1,77 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+my %map;
+
+# sort comparison function
+sub by_category($$) {
+    my ($a, $b) = @_;
+
+    $a = uc $a;
+    $b = uc $b;
+
+    # This always sorts last
+    $a =~ s/THE REST/ZZZZZZ/g;
+    $b =~ s/THE REST/ZZZZZZ/g;
+
+    $a cmp $b;
+}
+
+sub alpha_output {
+    my $key;
+    my $sort_method = \&by_category;
+    my $sep = "";
+
+    foreach $key (sort $sort_method keys %map) {
+        if ($key ne " ") {
+            print $sep . $key . "\n";
+            $sep = "\n";
+        }
+        print $map{$key};
+    }
+}
+
+sub trim {
+    my $s = shift;
+    $s =~ s/\s+$//;
+    $s =~ s/^\s+//;
+    return $s;
+}
+
+sub file_input {
+    my $lastline = "";
+    my $case = " ";
+    $map{$case} = "";
+
+    while (<>) {
+        my $line = $_;
+
+        # Pattern line?
+        if ($line =~ m/^([A-Z]):\s*(.*)/) {
+            $line = $1 . ":\t" . trim($2) . "\n";
+            if ($lastline eq "") {
+                $map{$case} = $map{$case} . $line;
+                next;
+            }
+            $case = trim($lastline);
+            exists $map{$case} and die "Header '$case' already exists";
+            $map{$case} = $line;
+            $lastline = "";
+            next;
+        }
+
+        if ($case eq " ") {
+            $map{$case} = $map{$case} . $lastline;
+            $lastline = $line;
+            next;
+        }
+        trim($lastline) eq "" or die ("Odd non-pattern line '$lastline' for '$case'");
+        $lastline = $line;
+    }
+    $map{$case} = $map{$case} . $lastline;
+}
+
+&file_input;
+&alpha_output;
+exit(0);
index d540bfe..e8e4494 100644 (file)
@@ -163,6 +163,13 @@ config HARDENED_USERCOPY_PAGESPAN
          been removed. This config is intended to be used only while
          trying to find such users.
 
+config FORTIFY_SOURCE
+       bool "Harden common str/mem functions against buffer overflows"
+       depends on ARCH_HAS_FORTIFY_SOURCE
+       help
+         Detect overflows of buffers in common string and memory functions
+         where the compiler can determine and validate the buffer sizes.
+
 config STATIC_USERMODEHELPER
        bool "Force all usermode helper calls through a single binary"
        help
index a6a659b..aa6b34c 100644 (file)
@@ -33,6 +33,8 @@ long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params,
        kdfcopy.hashname = compat_ptr(compat_kdfcopy.hashname);
        kdfcopy.otherinfo = compat_ptr(compat_kdfcopy.otherinfo);
        kdfcopy.otherinfolen = compat_kdfcopy.otherinfolen;
+       memcpy(kdfcopy.__spare, compat_kdfcopy.__spare,
+              sizeof(kdfcopy.__spare));
 
        return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
 }
index 4755d4b..d1ea9f3 100644 (file)
@@ -266,6 +266,11 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
        if (kdfcopy) {
                char *hashname;
 
+               if (memchr_inv(kdfcopy->__spare, 0, sizeof(kdfcopy->__spare))) {
+                       ret = -EINVAL;
+                       goto out1;
+               }
+
                if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN ||
                    kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) {
                        ret = -EMSGSIZE;
index 91bc621..1c02c65 100644 (file)
@@ -198,7 +198,7 @@ struct request_key_auth {
        void                    *callout_info;
        size_t                  callout_len;
        pid_t                   pid;
-};
+} __randomize_layout;
 
 extern struct key_type key_type_request_key_auth;
 extern struct key *request_key_auth_new(struct key *target,
index b3d5bed..22995cb 100644 (file)
@@ -238,10 +238,8 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream)
 {
        if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP))
                return false;
-       /* check architectures that return -EINVAL from dma_mmap_coherent() */
-       /* FIXME: this should be some global flag */
-#if defined(CONFIG_C6X) || defined(CONFIG_FRV) || defined(CONFIG_MN10300) ||\
-       defined(CONFIG_PARISC) || defined(CONFIG_XTENSA)
+       /* architecture supports dma_mmap_coherent()? */
+#if defined(CONFIG_ARCH_NO_COHERENT_DMA_MMAP) || !defined(CONFIG_HAS_DMA)
        if (!substream->ops->mmap &&
            substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
                return false;
@@ -3502,7 +3500,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
        }
 #endif /* CONFIG_GENERIC_ALLOCATOR */
 #ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */
-       if (!substream->ops->page &&
+       if (IS_ENABLED(CONFIG_HAS_DMA) && !substream->ops->page &&
            substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
                return dma_mmap_coherent(substream->dma_buffer.dev.dev,
                                         area,
index bc345d5..db76a5b 100644 (file)
@@ -29,7 +29,7 @@ MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("OPL4 driver");
 MODULE_LICENSE("GPL");
 
-static void inline snd_opl4_wait(struct snd_opl4 *opl4)
+static inline void snd_opl4_wait(struct snd_opl4 *opl4)
 {
        int timeout = 10;
        while ((inb(opl4->fm_port) & OPL4_STATUS_BUSY) && --timeout > 0)
index 912b5a9..013d8d1 100644 (file)
@@ -120,24 +120,24 @@ void snd_msndmidi_input_read(void *mpuv)
        unsigned long flags;
        struct snd_msndmidi *mpu = mpuv;
        void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
+       u16 head, tail, size;
 
        spin_lock_irqsave(&mpu->input_lock, flags);
-       while (readw(mpu->dev->MIDQ + JQS_wTail) !=
-              readw(mpu->dev->MIDQ + JQS_wHead)) {
-               u16 wTmp, val;
-               val = readw(pwMIDQData + 2 * readw(mpu->dev->MIDQ + JQS_wHead));
-
-                       if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
-                                    &mpu->mode))
-                               snd_rawmidi_receive(mpu->substream_input,
-                                                   (unsigned char *)&val, 1);
-
-               wTmp = readw(mpu->dev->MIDQ + JQS_wHead) + 1;
-               if (wTmp > readw(mpu->dev->MIDQ + JQS_wSize))
-                       writew(0,  mpu->dev->MIDQ + JQS_wHead);
-               else
-                       writew(wTmp,  mpu->dev->MIDQ + JQS_wHead);
+       head = readw(mpu->dev->MIDQ + JQS_wHead);
+       tail = readw(mpu->dev->MIDQ + JQS_wTail);
+       size = readw(mpu->dev->MIDQ + JQS_wSize);
+       if (head > size || tail > size)
+               goto out;
+       while (head != tail) {
+               unsigned char val = readw(pwMIDQData + 2 * head);
+
+               if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
+                       snd_rawmidi_receive(mpu->substream_input, &val, 1);
+               if (++head > size)
+                       head = 0;
+               writew(head, mpu->dev->MIDQ + JQS_wHead);
        }
+ out:
        spin_unlock_irqrestore(&mpu->input_lock, flags);
 }
 EXPORT_SYMBOL(snd_msndmidi_input_read);
index ad48973..fc4fb19 100644 (file)
@@ -170,23 +170,24 @@ static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
 {
        struct snd_msnd *chip = dev_id;
        void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
+       u16 head, tail, size;
 
        /* Send ack to DSP */
        /* inb(chip->io + HP_RXL); */
 
        /* Evaluate queued DSP messages */
-       while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) {
-               u16 wTmp;
-
-               snd_msnd_eval_dsp_msg(chip,
-                       readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead)));
-
-               wTmp = readw(chip->DSPQ + JQS_wHead) + 1;
-               if (wTmp > readw(chip->DSPQ + JQS_wSize))
-                       writew(0, chip->DSPQ + JQS_wHead);
-               else
-                       writew(wTmp, chip->DSPQ + JQS_wHead);
+       head = readw(chip->DSPQ + JQS_wHead);
+       tail = readw(chip->DSPQ + JQS_wTail);
+       size = readw(chip->DSPQ + JQS_wSize);
+       if (head > size || tail > size)
+               goto out;
+       while (head != tail) {
+               snd_msnd_eval_dsp_msg(chip, readw(pwDSPQData + 2 * head));
+               if (++head > size)
+                       head = 0;
+               writew(head, chip->DSPQ + JQS_wHead);
        }
+ out:
        /* Send ack to DSP */
        inb(chip->io + HP_RXL);
        return IRQ_HANDLED;
index 2e402ec..8e6b04b 100644 (file)
@@ -1235,8 +1235,6 @@ static int snd_fm801_create(struct snd_card *card,
                }
        }
 
-       snd_fm801_chip_init(chip);
-
        if ((chip->tea575x_tuner & TUNER_ONLY) == 0) {
                if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
                                IRQF_SHARED, KBUILD_MODNAME, chip)) {
@@ -1248,6 +1246,8 @@ static int snd_fm801_create(struct snd_card *card,
                pci_set_master(pci);
        }
 
+       snd_fm801_chip_init(chip);
+
        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
                snd_fm801_free(chip);
                return err;
index 63bc894..8c12899 100644 (file)
@@ -933,6 +933,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
        SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
        SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
+       SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO),
        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),
index 76c85f0..53f9311 100644 (file)
@@ -53,9 +53,11 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
 #define is_skylake(codec) ((codec)->core.vendor_id == 0x80862809)
 #define is_broxton(codec) ((codec)->core.vendor_id == 0x8086280a)
 #define is_kabylake(codec) ((codec)->core.vendor_id == 0x8086280b)
+#define is_geminilake(codec) (((codec)->core.vendor_id == 0x8086280d) || \
+                               ((codec)->core.vendor_id == 0x80862800))
 #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \
                                || is_skylake(codec) || is_broxton(codec) \
-                               || is_kabylake(codec))
+                               || is_kabylake(codec)) || is_geminilake(codec)
 
 #define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882)
 #define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883)
@@ -3731,11 +3733,15 @@ HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI",        patch_atihdmi),
 HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI",    patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI",    patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI",   patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI",      patch_nvhdmi_2ch),
 HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
 HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI",     patch_nvhdmi_8ch_7x),
 HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
 HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
 HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI",   patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI",      patch_nvhdmi),
@@ -3762,17 +3768,40 @@ HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP",   patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI",      patch_nvhdmi_2ch),
 HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI",      patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI",   patch_nvhdmi_2ch),
 HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP",   patch_via_hdmi),
 HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP",   patch_via_hdmi),
 HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP",    patch_generic_hdmi),
@@ -3790,6 +3819,7 @@ HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI",       patch_i915_hsw_hdmi),
 HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI",    patch_i915_hsw_hdmi),
 HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI",   patch_i915_hsw_hdmi),
 HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi),
+HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi),
 HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",        patch_i915_byt_hdmi),
 HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",   patch_i915_byt_hdmi),
index cd6987b..443a45e 100644 (file)
@@ -379,6 +379,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
                break;
        case 0x10ec0899:
        case 0x10ec0900:
+       case 0x10ec1168:
        case 0x10ec1220:
                alc_update_coef_idx(codec, 0x7, 1<<1, 0);
                break;
@@ -3837,6 +3838,17 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
        }
 }
 
+static struct coef_fw alc225_pre_hsmode[] = {
+       UPDATE_COEF(0x4a, 1<<8, 0),
+       UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
+       UPDATE_COEF(0x63, 3<<14, 3<<14),
+       UPDATE_COEF(0x4a, 3<<4, 2<<4),
+       UPDATE_COEF(0x4a, 3<<10, 3<<10),
+       UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+       UPDATE_COEF(0x4a, 3<<10, 0),
+       {}
+};
+
 static void alc_headset_mode_unplugged(struct hda_codec *codec)
 {
        static struct coef_fw coef0255[] = {
@@ -3872,6 +3884,10 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
                UPDATE_COEF(0x67, 0x2000, 0),
                {}
        };
+       static struct coef_fw coef0298[] = {
+               UPDATE_COEF(0x19, 0x1300, 0x0300),
+               {}
+       };
        static struct coef_fw coef0292[] = {
                WRITE_COEF(0x76, 0x000e),
                WRITE_COEF(0x6c, 0x2400),
@@ -3894,13 +3910,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
                {}
        };
        static struct coef_fw coef0225[] = {
-               UPDATE_COEF(0x4a, 1<<8, 0),
-               UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
-               UPDATE_COEF(0x63, 3<<14, 3<<14),
-               UPDATE_COEF(0x4a, 3<<4, 2<<4),
-               UPDATE_COEF(0x4a, 3<<10, 3<<10),
-               UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
-               UPDATE_COEF(0x4a, 3<<10, 0),
+               UPDATE_COEF(0x63, 3<<14, 0),
                {}
        };
        static struct coef_fw coef0274[] = {
@@ -3934,7 +3944,10 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
                break;
        case 0x10ec0286:
        case 0x10ec0288:
+               alc_process_coef_fw(codec, coef0288);
+               break;
        case 0x10ec0298:
+               alc_process_coef_fw(codec, coef0298);
                alc_process_coef_fw(codec, coef0288);
                break;
        case 0x10ec0292:
@@ -3975,6 +3988,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
                {}
        };
        static struct coef_fw coef0288[] = {
+               UPDATE_COEF(0x4f, 0x00c0, 0),
                UPDATE_COEF(0x50, 0x2000, 0),
                UPDATE_COEF(0x56, 0x0006, 0),
                UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
@@ -4038,7 +4052,6 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
        case 0x10ec0286:
        case 0x10ec0288:
        case 0x10ec0298:
-               alc_update_coef_idx(codec, 0x4f, 0x000c, 0);
                snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
                alc_process_coef_fw(codec, coef0288);
                snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
@@ -4071,6 +4084,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
        case 0x10ec0225:
        case 0x10ec0295:
        case 0x10ec0299:
+               alc_process_coef_fw(codec, alc225_pre_hsmode);
                alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
                snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
                alc_process_coef_fw(codec, coef0225);
@@ -4083,7 +4097,12 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
 static void alc_headset_mode_default(struct hda_codec *codec)
 {
        static struct coef_fw coef0225[] = {
-               UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+               UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10),
+               UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10),
+               UPDATE_COEF(0x49, 3<<8, 0<<8),
+               UPDATE_COEF(0x4a, 3<<4, 3<<4),
+               UPDATE_COEF(0x63, 3<<14, 0),
+               UPDATE_COEF(0x67, 0xf000, 0x3000),
                {}
        };
        static struct coef_fw coef0255[] = {
@@ -4137,6 +4156,7 @@ static void alc_headset_mode_default(struct hda_codec *codec)
        case 0x10ec0225:
        case 0x10ec0295:
        case 0x10ec0299:
+               alc_process_coef_fw(codec, alc225_pre_hsmode);
                alc_process_coef_fw(codec, coef0225);
                break;
        case 0x10ec0255:
@@ -4176,6 +4196,8 @@ static void alc_headset_mode_default(struct hda_codec *codec)
 /* Iphone type */
 static void alc_headset_mode_ctia(struct hda_codec *codec)
 {
+       int val;
+
        static struct coef_fw coef0255[] = {
                WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
                WRITE_COEF(0x1b, 0x0c2b),
@@ -4218,11 +4240,14 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
                WRITE_COEF(0xc3, 0x0000),
                {}
        };
-       static struct coef_fw coef0225[] = {
+       static struct coef_fw coef0225_1[] = {
                UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
-               UPDATE_COEF(0x49, 1<<8, 1<<8),
-               UPDATE_COEF(0x4a, 7<<6, 7<<6),
-               UPDATE_COEF(0x4a, 3<<4, 3<<4),
+               UPDATE_COEF(0x63, 3<<14, 2<<14),
+               {}
+       };
+       static struct coef_fw coef0225_2[] = {
+               UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
+               UPDATE_COEF(0x63, 3<<14, 1<<14),
                {}
        };
 
@@ -4243,8 +4268,17 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
                alc_process_coef_fw(codec, coef0233);
                break;
        case 0x10ec0298:
-               alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);/* Headset output enable */
-               /* ALC298 jack type setting is the same with ALC286/ALC288 */
+               val = alc_read_coef_idx(codec, 0x50);
+               if (val & (1 << 12)) {
+                       alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
+                       alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+                       msleep(300);
+               } else {
+                       alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
+                       alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+                       msleep(300);
+               }
+               break;
        case 0x10ec0286:
        case 0x10ec0288:
                alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
@@ -4263,7 +4297,11 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
        case 0x10ec0225:
        case 0x10ec0295:
        case 0x10ec0299:
-               alc_process_coef_fw(codec, coef0225);
+               val = alc_read_coef_idx(codec, 0x45);
+               if (val & (1 << 9))
+                       alc_process_coef_fw(codec, coef0225_2);
+               else
+                       alc_process_coef_fw(codec, coef0225_1);
                break;
        case 0x10ec0867:
                alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
@@ -4319,9 +4357,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
        };
        static struct coef_fw coef0225[] = {
                UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
-               UPDATE_COEF(0x49, 1<<8, 1<<8),
-               UPDATE_COEF(0x4a, 7<<6, 7<<6),
-               UPDATE_COEF(0x4a, 3<<4, 3<<4),
+               UPDATE_COEF(0x63, 3<<14, 2<<14),
                {}
        };
 
@@ -4343,7 +4379,9 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
                break;
        case 0x10ec0298:
                alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */
-               /* ALC298 jack type setting is the same with ALC286/ALC288 */
+               alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
+               msleep(300);
+               break;
        case 0x10ec0286:
        case 0x10ec0288:
                alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
@@ -4383,6 +4421,14 @@ static void alc_determine_headset_type(struct hda_codec *codec)
                UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
                {}
        };
+       static struct coef_fw coef0298[] = {
+               UPDATE_COEF(0x50, 0x2000, 0x2000),
+               UPDATE_COEF(0x56, 0x0006, 0x0006),
+               UPDATE_COEF(0x66, 0x0008, 0),
+               UPDATE_COEF(0x67, 0x2000, 0),
+               UPDATE_COEF(0x19, 0x1300, 0x1300),
+               {}
+       };
        static struct coef_fw coef0293[] = {
                UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
                WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
@@ -4395,11 +4441,6 @@ static void alc_determine_headset_type(struct hda_codec *codec)
                WRITE_COEF(0xc3, 0x0c00),
                {}
        };
-       static struct coef_fw coef0225[] = {
-               UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
-               UPDATE_COEF(0x49, 1<<8, 1<<8),
-               {}
-       };
        static struct coef_fw coef0274[] = {
                UPDATE_COEF(0x4a, 0x0010, 0),
                UPDATE_COEF(0x4a, 0x8000, 0),
@@ -4432,8 +4473,34 @@ static void alc_determine_headset_type(struct hda_codec *codec)
                is_ctia = (val & 0x0070) == 0x0070;
                break;
        case 0x10ec0298:
-               alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020); /* Headset output enable */
-               /* ALC298 check jack type is the same with ALC286/ALC288 */
+               snd_hda_codec_write(codec, 0x21, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+               msleep(100);
+               snd_hda_codec_write(codec, 0x21, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+               msleep(200);
+
+               val = alc_read_coef_idx(codec, 0x50);
+               if (val & (1 << 12)) {
+                       alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
+                       alc_process_coef_fw(codec, coef0288);
+                       msleep(350);
+                       val = alc_read_coef_idx(codec, 0x50);
+                       is_ctia = (val & 0x0070) == 0x0070;
+               } else {
+                       alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
+                       alc_process_coef_fw(codec, coef0288);
+                       msleep(350);
+                       val = alc_read_coef_idx(codec, 0x50);
+                       is_ctia = (val & 0x0070) == 0x0070;
+               }
+               alc_process_coef_fw(codec, coef0298);
+               snd_hda_codec_write(codec, 0x21, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+               msleep(75);
+               snd_hda_codec_write(codec, 0x21, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+               break;
        case 0x10ec0286:
        case 0x10ec0288:
                alc_process_coef_fw(codec, coef0288);
@@ -4462,10 +4529,25 @@ static void alc_determine_headset_type(struct hda_codec *codec)
        case 0x10ec0225:
        case 0x10ec0295:
        case 0x10ec0299:
-               alc_process_coef_fw(codec, coef0225);
-               msleep(800);
-               val = alc_read_coef_idx(codec, 0x46);
-               is_ctia = (val & 0x00f0) == 0x00f0;
+               alc_process_coef_fw(codec, alc225_pre_hsmode);
+               alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000);
+               val = alc_read_coef_idx(codec, 0x45);
+               if (val & (1 << 9)) {
+                       alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
+                       alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8);
+                       msleep(800);
+                       val = alc_read_coef_idx(codec, 0x46);
+                       is_ctia = (val & 0x00f0) == 0x00f0;
+               } else {
+                       alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
+                       alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
+                       msleep(800);
+                       val = alc_read_coef_idx(codec, 0x46);
+                       is_ctia = (val & 0x00f0) == 0x00f0;
+               }
+               alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6);
+               alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4);
+               alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
                break;
        case 0x10ec0867:
                is_ctia = true;
@@ -5179,6 +5261,7 @@ enum {
        ALC233_FIXUP_ASUS_MIC_NO_PRESENCE,
        ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE,
        ALC233_FIXUP_LENOVO_MULTI_CODECS,
+       ALC294_FIXUP_LENOVO_MIC_LOCATION,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5962,6 +6045,18 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc233_alc662_fixup_lenovo_dual_codecs,
        },
+       [ALC294_FIXUP_LENOVO_MIC_LOCATION] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* Change the mic location from front to right, otherwise there are
+                          two front mics with the same name, pulseaudio can't handle them.
+                          This is just a temporary workaround, after applying this fixup,
+                          there will be one "Front Mic" and one "Mic" in this machine.
+                        */
+                       { 0x1a, 0x04a19040 },
+                       { }
+               },
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -6143,6 +6238,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460),
        SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
+       SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
        SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
        SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
@@ -6709,6 +6805,7 @@ static int patch_alc269(struct hda_codec *codec)
        case 0x10ec0225:
        case 0x10ec0295:
                spec->codec_variant = ALC269_TYPE_ALC225;
+               spec->gen.mixer_nid = 0; /* no loopback on ALC225 ALC295 */
                break;
        case 0x10ec0299:
                spec->codec_variant = ALC269_TYPE_ALC225;
@@ -7801,6 +7898,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
        HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
        HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
        HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882),
        HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882),
        {} /* terminator */
 };
index ce2988b..1579cab 100644 (file)
@@ -104,6 +104,7 @@ enum bpf_map_type {
        BPF_MAP_TYPE_LPM_TRIE,
        BPF_MAP_TYPE_ARRAY_OF_MAPS,
        BPF_MAP_TYPE_HASH_OF_MAPS,
+       BPF_MAP_TYPE_DEVMAP,
 };
 
 enum bpf_prog_type {
index dd8f00c..32283d8 100755 (executable)
@@ -474,7 +474,7 @@ class Provider(object):
     @staticmethod
     def is_field_wanted(fields_filter, field):
         """Indicate whether field is valid according to fields_filter."""
-        if not fields_filter:
+        if not fields_filter or fields_filter == "help":
             return True
         return re.match(fields_filter, field) is not None
 
@@ -1413,8 +1413,8 @@ performance.
 
 Requirements:
 - Access to:
-    /sys/kernel/debug/kvm
-    /sys/kernel/debug/trace/events/*
+    %s
+    %s/events/*
     /proc/pid/task
 - /proc/sys/kernel/perf_event_paranoid < 1 if user has no
   CAP_SYS_ADMIN and perf events are used.
@@ -1434,7 +1434,7 @@ Interactive Commands:
    s     set update interval
    x     toggle reporting of stats for individual child trace events
 Press any other key to refresh statistics immediately.
-"""
+""" % (PATH_DEBUGFS_KVM, PATH_DEBUGFS_TRACING)
 
     class PlainHelpFormatter(optparse.IndentedHelpFormatter):
         def format_description(self, description):
@@ -1496,7 +1496,8 @@ Press any other key to refresh statistics immediately.
                          action='store',
                          default=DEFAULT_REGEX,
                          dest='fields',
-                         help='fields to display (regex)',
+                         help='''fields to display (regex)
+                                 "-f help" for a list of available events''',
                          )
     optparser.add_option('-p', '--pid',
                          action='store',
@@ -1559,6 +1560,17 @@ def main():
 
     stats = Stats(options)
 
+    if options.fields == "help":
+        event_list = "\n"
+        s = stats.get()
+        for key in s.keys():
+            if key.find('(') != -1:
+                key = key[0:key.find('(')]
+            if event_list.find('\n' + key + '\n') == -1:
+                event_list += key + '\n'
+        sys.stdout.write(event_list)
+        return ""
+
     if options.log:
         log(stats)
     elif not options.once:
index 1f5300e..4452895 100644 (file)
@@ -189,6 +189,10 @@ install_lib: all_cmd
        $(call QUIET_INSTALL, $(LIB_FILE)) \
                $(call do_install,$(LIB_FILE),$(libdir_SQ))
 
+install_headers:
+       $(call QUIET_INSTALL, headers) \
+               $(call do_install,bpf.h,$(prefix)/include/bpf,644)
+
 install: install_lib
 
 ### Cleaning rules
index 7e0405e..256f571 100644 (file)
@@ -120,7 +120,7 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
 int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
                       size_t insns_cnt, int strict_alignment,
                       const char *license, __u32 kern_version,
-                      char *log_buf, size_t log_buf_sz)
+                      char *log_buf, size_t log_buf_sz, int log_level)
 {
        union bpf_attr attr;
 
@@ -131,7 +131,7 @@ int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
        attr.license = ptr_to_u64(license);
        attr.log_buf = ptr_to_u64(log_buf);
        attr.log_size = log_buf_sz;
-       attr.log_level = 2;
+       attr.log_level = log_level;
        log_buf[0] = 0;
        attr.kern_version = kern_version;
        attr.prog_flags = strict_alignment ? BPF_F_STRICT_ALIGNMENT : 0;
@@ -314,7 +314,6 @@ int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len)
        int err;
 
        bzero(&attr, sizeof(attr));
-       bzero(info, *info_len);
        attr.info.bpf_fd = prog_fd;
        attr.info.info_len = *info_len;
        attr.info.info = ptr_to_u64(info);
index 16de44a..418c86e 100644 (file)
@@ -38,7 +38,7 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
 int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
                       size_t insns_cnt, int strict_alignment,
                       const char *license, __u32 kern_version,
-                      char *log_buf, size_t log_buf_sz);
+                      char *log_buf, size_t log_buf_sz, int log_level);
 
 int bpf_map_update_elem(int fd, const void *key, const void *value,
                        __u64 flags);
index 0a8a1c4..a1497c5 100644 (file)
@@ -643,7 +643,7 @@ static const struct {
        { "__GFP_FS",                   "F" },
        { "__GFP_COLD",                 "CO" },
        { "__GFP_NOWARN",               "NWR" },
-       { "__GFP_REPEAT",               "R" },
+       { "__GFP_RETRY_MAYFAIL",        "R" },
        { "__GFP_NOFAIL",               "NF" },
        { "__GFP_NORETRY",              "NR" },
        { "__GFP_COMP",                 "C" },
index a4d3762..83874b0 100644 (file)
@@ -704,7 +704,7 @@ static void __ui_browser__line_arrow_down(struct ui_browser *browser,
                ui_browser__gotorc(browser, row, column + 1);
                SLsmg_draw_hline(2);
 
-               if (row++ == 0)
+               if (++row == 0)
                        goto out;
        } else
                row = 0;
index 87b4318..413f74d 100644 (file)
@@ -273,7 +273,7 @@ struct perf_evsel *perf_evsel__new_cycles(void)
        struct perf_event_attr attr = {
                .type   = PERF_TYPE_HARDWARE,
                .config = PERF_COUNT_HW_CPU_CYCLES,
-               .exclude_kernel = 1,
+               .exclude_kernel = geteuid() != 0,
        };
        struct perf_evsel *evsel;
 
@@ -298,8 +298,10 @@ struct perf_evsel *perf_evsel__new_cycles(void)
                goto out;
 
        /* use asprintf() because free(evsel) assumes name is allocated */
-       if (asprintf(&evsel->name, "cycles%.*s",
-                    attr.precise_ip ? attr.precise_ip + 1 : 0, ":ppp") < 0)
+       if (asprintf(&evsel->name, "cycles%s%s%.*s",
+                    (attr.precise_ip || attr.exclude_kernel) ? ":" : "",
+                    attr.exclude_kernel ? "u" : "",
+                    attr.precise_ip ? attr.precise_ip + 1 : 0, "ppp") < 0)
                goto error_free;
 out:
        return evsel;
index 5de2b86..2e9eb6a 100644 (file)
@@ -2209,7 +2209,7 @@ int machine__get_kernel_start(struct machine *machine)
        machine->kernel_start = 1ULL << 63;
        if (map) {
                err = map__load(map);
-               if (map->start)
+               if (!err)
                        machine->kernel_start = map->start;
        }
        return err;
index bccebd9..2979369 100644 (file)
@@ -380,7 +380,7 @@ static int do_test_single(struct bpf_align_test *test)
        prog_len = probe_filter_length(prog);
        fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
                                     prog, prog_len, 1, "GPL", 0,
-                                    bpf_vlog, sizeof(bpf_vlog));
+                                    bpf_vlog, sizeof(bpf_vlog), 2);
        if (fd_prog < 0) {
                printf("Failed to load program.\n");
                printf("%s", bpf_vlog);
index 36d6ac3..c991ab6 100644 (file)
@@ -440,7 +440,7 @@ static void test_arraymap_percpu_many_keys(void)
 
 static void test_devmap(int task, void *data)
 {
-       int next_key, fd;
+       int fd;
        __u32 key, value;
 
        fd = bpf_create_map(BPF_MAP_TYPE_DEVMAP, sizeof(key), sizeof(value),
@@ -620,6 +620,8 @@ static void run_all_tests(void)
 
        test_arraymap_percpu_many_keys();
 
+       test_devmap(0, NULL);
+
        test_map_large();
        test_map_parallel();
        test_map_stress();
index 5855cd3..1f7dd35 100644 (file)
@@ -340,6 +340,7 @@ static void test_bpf_obj_id(void)
 
                /* Check getting prog info */
                info_len = sizeof(struct bpf_prog_info) * 2;
+               bzero(&prog_infos[i], info_len);
                prog_infos[i].jited_prog_insns = ptr_to_u64(jited_insns);
                prog_infos[i].jited_prog_len = sizeof(jited_insns);
                prog_infos[i].xlated_prog_insns = ptr_to_u64(xlated_insns);
@@ -369,6 +370,7 @@ static void test_bpf_obj_id(void)
 
                /* Check getting map info */
                info_len = sizeof(struct bpf_map_info) * 2;
+               bzero(&map_infos[i], info_len);
                err = bpf_obj_get_info_by_fd(map_fds[i], &map_infos[i],
                                             &info_len);
                if (CHECK(err ||
@@ -394,7 +396,7 @@ static void test_bpf_obj_id(void)
        nr_id_found = 0;
        next_id = 0;
        while (!bpf_prog_get_next_id(next_id, &next_id)) {
-               struct bpf_prog_info prog_info;
+               struct bpf_prog_info prog_info = {};
                int prog_fd;
 
                info_len = sizeof(prog_info);
@@ -418,6 +420,8 @@ static void test_bpf_obj_id(void)
                nr_id_found++;
 
                err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
+               prog_infos[i].jited_prog_insns = 0;
+               prog_infos[i].xlated_prog_insns = 0;
                CHECK(err || info_len != sizeof(struct bpf_prog_info) ||
                      memcmp(&prog_info, &prog_infos[i], info_len),
                      "get-prog-info(next_id->fd)",
@@ -436,7 +440,7 @@ static void test_bpf_obj_id(void)
        nr_id_found = 0;
        next_id = 0;
        while (!bpf_map_get_next_id(next_id, &next_id)) {
-               struct bpf_map_info map_info;
+               struct bpf_map_info map_info = {};
                int map_fd;
 
                info_len = sizeof(map_info);
index 404aec5..addea82 100644 (file)
@@ -4969,7 +4969,7 @@ static struct bpf_test tests[] = {
                        BPF_JMP_IMM(BPF_JSGT, BPF_REG_2,
                                sizeof(struct test_val), 4),
                        BPF_MOV64_IMM(BPF_REG_4, 0),
-                       BPF_JMP_REG(BPF_JGE, BPF_REG_4, BPF_REG_2, 2),
+                       BPF_JMP_REG(BPF_JSGE, BPF_REG_4, BPF_REG_2, 2),
                        BPF_MOV64_IMM(BPF_REG_3, 0),
                        BPF_EMIT_CALL(BPF_FUNC_probe_read),
                        BPF_MOV64_IMM(BPF_REG_0, 0),
@@ -4995,7 +4995,7 @@ static struct bpf_test tests[] = {
                        BPF_JMP_IMM(BPF_JSGT, BPF_REG_2,
                                sizeof(struct test_val) + 1, 4),
                        BPF_MOV64_IMM(BPF_REG_4, 0),
-                       BPF_JMP_REG(BPF_JGE, BPF_REG_4, BPF_REG_2, 2),
+                       BPF_JMP_REG(BPF_JSGE, BPF_REG_4, BPF_REG_2, 2),
                        BPF_MOV64_IMM(BPF_REG_3, 0),
                        BPF_EMIT_CALL(BPF_FUNC_probe_read),
                        BPF_MOV64_IMM(BPF_REG_0, 0),
@@ -5023,7 +5023,7 @@ static struct bpf_test tests[] = {
                        BPF_JMP_IMM(BPF_JSGT, BPF_REG_2,
                                sizeof(struct test_val) - 20, 4),
                        BPF_MOV64_IMM(BPF_REG_4, 0),
-                       BPF_JMP_REG(BPF_JGE, BPF_REG_4, BPF_REG_2, 2),
+                       BPF_JMP_REG(BPF_JSGE, BPF_REG_4, BPF_REG_2, 2),
                        BPF_MOV64_IMM(BPF_REG_3, 0),
                        BPF_EMIT_CALL(BPF_FUNC_probe_read),
                        BPF_MOV64_IMM(BPF_REG_0, 0),
@@ -5050,7 +5050,7 @@ static struct bpf_test tests[] = {
                        BPF_JMP_IMM(BPF_JSGT, BPF_REG_2,
                                sizeof(struct test_val) - 19, 4),
                        BPF_MOV64_IMM(BPF_REG_4, 0),
-                       BPF_JMP_REG(BPF_JGE, BPF_REG_4, BPF_REG_2, 2),
+                       BPF_JMP_REG(BPF_JSGE, BPF_REG_4, BPF_REG_2, 2),
                        BPF_MOV64_IMM(BPF_REG_3, 0),
                        BPF_EMIT_CALL(BPF_FUNC_probe_read),
                        BPF_MOV64_IMM(BPF_REG_0, 0),
@@ -5510,6 +5510,504 @@ static struct bpf_test tests[] = {
                .errstr = "invalid bpf_context access",
                .prog_type = BPF_PROG_TYPE_LWT_IN,
        },
+       {
+               "bounds checks mixing signed and unsigned, positive bounds",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, 2),
+                       BPF_JMP_REG(BPF_JGE, BPF_REG_2, BPF_REG_1, 3),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 4, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, -1),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_2, 3),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 1, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 2",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, -1),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_2, 5),
+                       BPF_MOV64_IMM(BPF_REG_8, 0),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_8, BPF_REG_1),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_8, 1, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_8),
+                       BPF_ST_MEM(BPF_B, BPF_REG_8, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R8 invalid mem access 'inv'",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 3",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 8),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, -1),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_2, 4),
+                       BPF_MOV64_REG(BPF_REG_8, BPF_REG_1),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_8, 1, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_8),
+                       BPF_ST_MEM(BPF_B, BPF_REG_8, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R8 invalid mem access 'inv'",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 4",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, 1),
+                       BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 1, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 5",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, -1),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_2, 5),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 1, 4),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 4),
+                       BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 invalid mem access",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 6",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_2, 0),
+                       BPF_MOV64_REG(BPF_REG_3, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, -512),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_6, -1),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_6, 5),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_4, 1, 4),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 1),
+                       BPF_MOV64_IMM(BPF_REG_5, 0),
+                       BPF_ST_MEM(BPF_H, BPF_REG_10, -512, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_skb_load_bytes),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .errstr_unpriv = "R4 min value is negative, either use unsigned",
+               .errstr = "R4 min value is negative, either use unsigned",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 7",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, 1024 * 1024 * 1024),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_2, 3),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 1, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 8",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, 1024 * 1024 * 1024 + 1),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_2, 3),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 1, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 9",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, -1),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_2, BPF_REG_1, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 1, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 10",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 10),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_LD_IMM64(BPF_REG_2, -9223372036854775808ULL),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_2, BPF_REG_1, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 1, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 11",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, 0),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_2, BPF_REG_1, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 1, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 12",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, -1),
+                       BPF_JMP_REG(BPF_JGE, BPF_REG_2, BPF_REG_1, 2),
+                       /* Dead branch. */
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 1, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 13",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, -6),
+                       BPF_JMP_REG(BPF_JGE, BPF_REG_2, BPF_REG_1, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 1, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 14",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, 2),
+                       BPF_JMP_REG(BPF_JGE, BPF_REG_2, BPF_REG_1, 2),
+                       BPF_MOV64_IMM(BPF_REG_7, 1),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_7, 0, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_1),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_7, 4, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_7),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 15",
+               .insns = {
+                       BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_1,
+                                   offsetof(struct __sk_buff, mark)),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 8),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, -1),
+                       BPF_MOV64_IMM(BPF_REG_8, 2),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_9, 42, 6),
+                       BPF_JMP_REG(BPF_JSGT, BPF_REG_8, BPF_REG_1, 3),
+                       BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 1, 2),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_2, -3),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, -7),
+               },
+               .fixup_map1 = { 4 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "bounds checks mixing signed and unsigned, variant 16",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16),
+                       BPF_MOV64_IMM(BPF_REG_2, -6),
+                       BPF_JMP_REG(BPF_JGE, BPF_REG_2, BPF_REG_1, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_JMP_IMM(BPF_JGT, BPF_REG_0, 1, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+       {
+               "subtraction bounds (map value)",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+                       BPF_JMP_IMM(BPF_JGT, BPF_REG_1, 0xff, 7),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_3, BPF_REG_0, 1),
+                       BPF_JMP_IMM(BPF_JGT, BPF_REG_3, 0xff, 5),
+                       BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_3),
+                       BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 56),
+                       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .errstr_unpriv = "R0 pointer arithmetic prohibited",
+               .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
 };
 
 static int probe_filter_length(const struct bpf_insn *fp)
@@ -5633,7 +6131,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
 
        fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
                                     prog, prog_len, test->flags & F_LOAD_WITH_STRICT_ALIGNMENT,
-                                    "GPL", 0, bpf_vlog, sizeof(bpf_vlog));
+                                    "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 1);
 
        expected_ret = unpriv && test->result_unpriv != UNDEF ?
                       test->result_unpriv : test->result;
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_eventname.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_eventname.tc
new file mode 100644 (file)
index 0000000..b9302cc
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/sh
+# description: Kprobe event auto/manual naming
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+disable_events
+echo > kprobe_events
+
+:;: "Add an event on function without name" ;:
+
+FUNC=`grep " [tT] .*vfs_read$" /proc/kallsyms | tail -n 1 | cut -f 3 -d " "`
+[ "x" != "x$FUNC" ] || exit_unresolved
+echo "p $FUNC" > kprobe_events
+PROBE_NAME=`echo $FUNC | tr ".:" "_"`
+test -d events/kprobes/p_${PROBE_NAME}_0 || exit_failure
+
+:;: "Add an event on function with new name" ;:
+
+echo "p:event1 $FUNC" > kprobe_events
+test -d events/kprobes/event1 || exit_failure
+
+:;: "Add an event on function with new name and group" ;:
+
+echo "p:kprobes2/event2 $FUNC" > kprobe_events
+test -d events/kprobes2/event2 || exit_failure
+
+:;: "Add an event on dot function without name" ;:
+
+FUNC=`grep -m 10 " [tT] .*\.isra\..*$" /proc/kallsyms | tail -n 1 | cut -f 3 -d " "`
+[ "x" != "x$FUNC" ] || exit_unresolved
+echo "p $FUNC" > kprobe_events
+EVENT=`grep $FUNC kprobe_events | cut -f 1 -d " " | cut -f 2 -d:`
+[ "x" != "x$EVENT" ] || exit_failure
+test -d events/$EVENT || exit_failure
+
+echo > kprobe_events
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_module.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_module.tc
new file mode 100644 (file)
index 0000000..6d634e4
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+# description: Kprobe dynamic event - probing module
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+disable_events
+echo > kprobe_events
+
+:;: "Add an event on a module function without specifying event name" ;:
+
+MOD=`lsmod | head -n 2 | tail -n 1 | cut -f1 -d" "`
+FUNC=`grep -m 1 ".* t .*\\[$MOD\\]" /proc/kallsyms | xargs | cut -f3 -d" "`
+[ "x" != "x$MOD" -a "y" != "y$FUNC" ] || exit_unresolved
+echo "p $MOD:$FUNC" > kprobe_events
+PROBE_NAME=`echo $MOD:$FUNC | tr ".:" "_"`
+test -d events/kprobes/p_${PROBE_NAME}_0 || exit_failure
+
+:;: "Add an event on a module function with new event name" ;:
+
+echo "p:event1 $MOD:$FUNC" > kprobe_events
+test -d events/kprobes/event1 || exit_failure
+
+:;: "Add an event on a module function with new event and group name" ;:
+
+echo "p:kprobes1/event1 $MOD:$FUNC" > kprobe_events
+test -d events/kprobes1/event1 || exit_failure
+
+echo > kprobe_events
index f4d1ff7..2a1cb99 100644 (file)
@@ -2,10 +2,10 @@
 # description: Register/unregister many kprobe events
 
 # ftrace fentry skip size depends on the machine architecture.
-# Currently HAVE_KPROBES_ON_FTRACE defined on x86 and powerpc
+# Currently HAVE_KPROBES_ON_FTRACE defined on x86 and powerpc64le
 case `uname -m` in
   x86_64|i[3456]86) OFFS=5;;
-  ppc*) OFFS=4;;
+  ppc64le) OFFS=8;;
   *) OFFS=0;;
 esac
 
diff --git a/tools/testing/selftests/kmod/Makefile b/tools/testing/selftests/kmod/Makefile
new file mode 100644 (file)
index 0000000..fa2ccc5
--- /dev/null
@@ -0,0 +1,11 @@
+# Makefile for kmod loading selftests
+
+# No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
+all:
+
+TEST_PROGS := kmod.sh
+
+include ../lib.mk
+
+# Nothing to clean up.
+clean:
diff --git a/tools/testing/selftests/kmod/config b/tools/testing/selftests/kmod/config
new file mode 100644 (file)
index 0000000..259f4fd
--- /dev/null
@@ -0,0 +1,7 @@
+CONFIG_TEST_KMOD=m
+CONFIG_TEST_LKM=m
+CONFIG_XFS_FS=m
+
+# For the module parameter force_init_test is used
+CONFIG_TUN=m
+CONFIG_BTRFS_FS=m
diff --git a/tools/testing/selftests/kmod/kmod.sh b/tools/testing/selftests/kmod/kmod.sh
new file mode 100644 (file)
index 0000000..8cecae9
--- /dev/null
@@ -0,0 +1,615 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org>
+#
+# 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; or, when distributed separately from the Linux kernel or
+# when incorporated into other software packages, subject to the following
+# license:
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of copyleft-next (version 0.3.1 or later) as published
+# at http://copyleft-next.org/.
+
+# This is a stress test script for kmod, the kernel module loader. It uses
+# test_kmod which exposes a series of knobs for the API for us so we can
+# tweak each test in userspace rather than in kernelspace.
+#
+# The way kmod works is it uses the kernel's usermode helper API to eventually
+# call /sbin/modprobe. It has a limit of the number of concurrent calls
+# possible. The kernel interface to load modules is request_module(), however
+# mount uses get_fs_type(). Both behave slightly differently, but the
+# differences are important enough to test each call separately. For this
+# reason test_kmod starts by providing tests for both calls.
+#
+# The test driver test_kmod assumes a series of defaults which you can
+# override by exporting to your environment prior running this script.
+# For instance this script assumes you do not have xfs loaded upon boot.
+# If this is false, export DEFAULT_KMOD_FS="ext4" prior to running this
+# script if the filesyste module you don't have loaded upon bootup
+# is ext4 instead. Refer to allow_user_defaults() for a list of user
+# override variables possible.
+#
+# You'll want at least 4 GiB of RAM to expect to run these tests
+# without running out of memory on them. For other requirements refer
+# to test_reqs()
+
+set -e
+
+TEST_NAME="kmod"
+TEST_DRIVER="test_${TEST_NAME}"
+TEST_DIR=$(dirname $0)
+
+# This represents
+#
+# TEST_ID:TEST_COUNT:ENABLED
+#
+# TEST_ID: is the test id number
+# TEST_COUNT: number of times we should run the test
+# ENABLED: 1 if enabled, 0 otherwise
+#
+# Once these are enabled please leave them as-is. Write your own test,
+# we have tons of space.
+ALL_TESTS="0001:3:1"
+ALL_TESTS="$ALL_TESTS 0002:3:1"
+ALL_TESTS="$ALL_TESTS 0003:1:1"
+ALL_TESTS="$ALL_TESTS 0004:1:1"
+ALL_TESTS="$ALL_TESTS 0005:10:1"
+ALL_TESTS="$ALL_TESTS 0006:10:1"
+ALL_TESTS="$ALL_TESTS 0007:5:1"
+ALL_TESTS="$ALL_TESTS 0008:150:1"
+ALL_TESTS="$ALL_TESTS 0009:150:1"
+
+test_modprobe()
+{
+       if [ ! -d $DIR ]; then
+               echo "$0: $DIR not present" >&2
+               echo "You must have the following enabled in your kernel:" >&2
+               cat $TEST_DIR/config >&2
+               exit 1
+       fi
+}
+
+function allow_user_defaults()
+{
+       if [ -z $DEFAULT_KMOD_DRIVER ]; then
+               DEFAULT_KMOD_DRIVER="test_module"
+       fi
+
+       if [ -z $DEFAULT_KMOD_FS ]; then
+               DEFAULT_KMOD_FS="xfs"
+       fi
+
+       if [ -z $PROC_DIR ]; then
+               PROC_DIR="/proc/sys/kernel/"
+       fi
+
+       if [ -z $MODPROBE_LIMIT ]; then
+               MODPROBE_LIMIT=50
+       fi
+
+       if [ -z $DIR ]; then
+               DIR="/sys/devices/virtual/misc/${TEST_DRIVER}0/"
+       fi
+
+       if [ -z $DEFAULT_NUM_TESTS ]; then
+               DEFAULT_NUM_TESTS=150
+       fi
+
+       MODPROBE_LIMIT_FILE="${PROC_DIR}/kmod-limit"
+}
+
+test_reqs()
+{
+       if ! which modprobe 2> /dev/null > /dev/null; then
+               echo "$0: You need modprobe installed" >&2
+               exit 1
+       fi
+
+       if ! which kmod 2> /dev/null > /dev/null; then
+               echo "$0: You need kmod installed" >&2
+               exit 1
+       fi
+
+       # kmod 19 has a bad bug where it returns 0 when modprobe
+       # gets called *even* if the module was not loaded due to
+       # some bad heuristics. For details see:
+       #
+       # A work around is possible in-kernel but its rather
+       # complex.
+       KMOD_VERSION=$(kmod --version | awk '{print $3}')
+       if [[ $KMOD_VERSION  -le 19 ]]; then
+               echo "$0: You need at least kmod 20" >&2
+               echo "kmod <= 19 is buggy, for details see:" >&2
+               echo "http://git.kernel.org/cgit/utils/kernel/kmod/kmod.git/commit/libkmod/libkmod-module.c?id=fd44a98ae2eb5eb32161088954ab21e58e19dfc4" >&2
+               exit 1
+       fi
+
+       uid=$(id -u)
+       if [ $uid -ne 0 ]; then
+               echo $msg must be run as root >&2
+               exit 0
+       fi
+}
+
+function load_req_mod()
+{
+       trap "test_modprobe" EXIT
+
+       if [ ! -d $DIR ]; then
+               # Alanis: "Oh isn't it ironic?"
+               modprobe $TEST_DRIVER
+       fi
+}
+
+test_finish()
+{
+       echo "Test completed"
+}
+
+errno_name_to_val()
+{
+       case "$1" in
+       # kmod calls modprobe and upon of a module not found
+       # modprobe returns just 1... However in the kernel we
+       # *sometimes* see 256...
+       MODULE_NOT_FOUND)
+               echo 256;;
+       SUCCESS)
+               echo 0;;
+       -EPERM)
+               echo -1;;
+       -ENOENT)
+               echo -2;;
+       -EINVAL)
+               echo -22;;
+       -ERR_ANY)
+               echo -123456;;
+       *)
+               echo invalid;;
+       esac
+}
+
+errno_val_to_name()
+       case "$1" in
+       256)
+               echo MODULE_NOT_FOUND;;
+       0)
+               echo SUCCESS;;
+       -1)
+               echo -EPERM;;
+       -2)
+               echo -ENOENT;;
+       -22)
+               echo -EINVAL;;
+       -123456)
+               echo -ERR_ANY;;
+       *)
+               echo invalid;;
+       esac
+
+config_set_test_case_driver()
+{
+       if ! echo -n 1 >$DIR/config_test_case; then
+               echo "$0: Unable to set to test case to driver" >&2
+               exit 1
+       fi
+}
+
+config_set_test_case_fs()
+{
+       if ! echo -n 2 >$DIR/config_test_case; then
+               echo "$0: Unable to set to test case to fs" >&2
+               exit 1
+       fi
+}
+
+config_num_threads()
+{
+       if ! echo -n $1 >$DIR/config_num_threads; then
+               echo "$0: Unable to set to number of threads" >&2
+               exit 1
+       fi
+}
+
+config_get_modprobe_limit()
+{
+       if [[ -f ${MODPROBE_LIMIT_FILE} ]] ; then
+               MODPROBE_LIMIT=$(cat $MODPROBE_LIMIT_FILE)
+       fi
+       echo $MODPROBE_LIMIT
+}
+
+config_num_thread_limit_extra()
+{
+       MODPROBE_LIMIT=$(config_get_modprobe_limit)
+       let EXTRA_LIMIT=$MODPROBE_LIMIT+$1
+       config_num_threads $EXTRA_LIMIT
+}
+
+# For special characters use printf directly,
+# refer to kmod_test_0001
+config_set_driver()
+{
+       if ! echo -n $1 >$DIR/config_test_driver; then
+               echo "$0: Unable to set driver" >&2
+               exit 1
+       fi
+}
+
+config_set_fs()
+{
+       if ! echo -n $1 >$DIR/config_test_fs; then
+               echo "$0: Unable to set driver" >&2
+               exit 1
+       fi
+}
+
+config_get_driver()
+{
+       cat $DIR/config_test_driver
+}
+
+config_get_test_result()
+{
+       cat $DIR/test_result
+}
+
+config_reset()
+{
+       if ! echo -n "1" >"$DIR"/reset; then
+               echo "$0: reset shuld have worked" >&2
+               exit 1
+       fi
+}
+
+config_show_config()
+{
+       echo "----------------------------------------------------"
+       cat "$DIR"/config
+       echo "----------------------------------------------------"
+}
+
+config_trigger()
+{
+       if ! echo -n "1" >"$DIR"/trigger_config 2>/dev/null; then
+               echo "$1: FAIL - loading should have worked"
+               config_show_config
+               exit 1
+       fi
+       echo "$1: OK! - loading kmod test"
+}
+
+config_trigger_want_fail()
+{
+       if echo "1" > $DIR/trigger_config 2>/dev/null; then
+               echo "$1: FAIL - test case was expected to fail"
+               config_show_config
+               exit 1
+       fi
+       echo "$1: OK! - kmod test case failed as expected"
+}
+
+config_expect_result()
+{
+       RC=$(config_get_test_result)
+       RC_NAME=$(errno_val_to_name $RC)
+
+       ERRNO_NAME=$2
+       ERRNO=$(errno_name_to_val $ERRNO_NAME)
+
+       if [[ $ERRNO_NAME = "-ERR_ANY" ]]; then
+               if [[ $RC -ge 0 ]]; then
+                       echo "$1: FAIL, test expects $ERRNO_NAME - got $RC_NAME ($RC)" >&2
+                       config_show_config
+                       exit 1
+               fi
+       elif [[ $RC != $ERRNO ]]; then
+               echo "$1: FAIL, test expects $ERRNO_NAME ($ERRNO) - got $RC_NAME ($RC)" >&2
+               config_show_config
+               exit 1
+       fi
+       echo "$1: OK! - Return value: $RC ($RC_NAME), expected $ERRNO_NAME"
+}
+
+kmod_defaults_driver()
+{
+       config_reset
+       modprobe -r $DEFAULT_KMOD_DRIVER
+       config_set_driver $DEFAULT_KMOD_DRIVER
+}
+
+kmod_defaults_fs()
+{
+       config_reset
+       modprobe -r $DEFAULT_KMOD_FS
+       config_set_fs $DEFAULT_KMOD_FS
+       config_set_test_case_fs
+}
+
+kmod_test_0001_driver()
+{
+       NAME='\000'
+
+       kmod_defaults_driver
+       config_num_threads 1
+       printf '\000' >"$DIR"/config_test_driver
+       config_trigger ${FUNCNAME[0]}
+       config_expect_result ${FUNCNAME[0]} MODULE_NOT_FOUND
+}
+
+kmod_test_0001_fs()
+{
+       NAME='\000'
+
+       kmod_defaults_fs
+       config_num_threads 1
+       printf '\000' >"$DIR"/config_test_fs
+       config_trigger ${FUNCNAME[0]}
+       config_expect_result ${FUNCNAME[0]} -EINVAL
+}
+
+kmod_test_0001()
+{
+       kmod_test_0001_driver
+       kmod_test_0001_fs
+}
+
+kmod_test_0002_driver()
+{
+       NAME="nope-$DEFAULT_KMOD_DRIVER"
+
+       kmod_defaults_driver
+       config_set_driver $NAME
+       config_num_threads 1
+       config_trigger ${FUNCNAME[0]}
+       config_expect_result ${FUNCNAME[0]} MODULE_NOT_FOUND
+}
+
+kmod_test_0002_fs()
+{
+       NAME="nope-$DEFAULT_KMOD_FS"
+
+       kmod_defaults_fs
+       config_set_fs $NAME
+       config_trigger ${FUNCNAME[0]}
+       config_expect_result ${FUNCNAME[0]} -EINVAL
+}
+
+kmod_test_0002()
+{
+       kmod_test_0002_driver
+       kmod_test_0002_fs
+}
+
+kmod_test_0003()
+{
+       kmod_defaults_fs
+       config_num_threads 1
+       config_trigger ${FUNCNAME[0]}
+       config_expect_result ${FUNCNAME[0]} SUCCESS
+}
+
+kmod_test_0004()
+{
+       kmod_defaults_fs
+       config_num_threads 2
+       config_trigger ${FUNCNAME[0]}
+       config_expect_result ${FUNCNAME[0]} SUCCESS
+}
+
+kmod_test_0005()
+{
+       kmod_defaults_driver
+       config_trigger ${FUNCNAME[0]}
+       config_expect_result ${FUNCNAME[0]} SUCCESS
+}
+
+kmod_test_0006()
+{
+       kmod_defaults_fs
+       config_trigger ${FUNCNAME[0]}
+       config_expect_result ${FUNCNAME[0]} SUCCESS
+}
+
+kmod_test_0007()
+{
+       kmod_test_0005
+       kmod_test_0006
+}
+
+kmod_test_0008()
+{
+       kmod_defaults_driver
+       MODPROBE_LIMIT=$(config_get_modprobe_limit)
+       let EXTRA=$MODPROBE_LIMIT/6
+       config_num_thread_limit_extra $EXTRA
+       config_trigger ${FUNCNAME[0]}
+       config_expect_result ${FUNCNAME[0]} SUCCESS
+}
+
+kmod_test_0009()
+{
+       kmod_defaults_fs
+       MODPROBE_LIMIT=$(config_get_modprobe_limit)
+       let EXTRA=$MODPROBE_LIMIT/4
+       config_num_thread_limit_extra $EXTRA
+       config_trigger ${FUNCNAME[0]}
+       config_expect_result ${FUNCNAME[0]} SUCCESS
+}
+
+list_tests()
+{
+       echo "Test ID list:"
+       echo
+       echo "TEST_ID x NUM_TEST"
+       echo "TEST_ID:   Test ID"
+       echo "NUM_TESTS: Number of recommended times to run the test"
+       echo
+       echo "0001 x $(get_test_count 0001) - Simple test - 1 thread  for empty string"
+       echo "0002 x $(get_test_count 0002) - Simple test - 1 thread  for modules/filesystems that do not exist"
+       echo "0003 x $(get_test_count 0003) - Simple test - 1 thread  for get_fs_type() only"
+       echo "0004 x $(get_test_count 0004) - Simple test - 2 threads for get_fs_type() only"
+       echo "0005 x $(get_test_count 0005) - multithreaded tests with default setup - request_module() only"
+       echo "0006 x $(get_test_count 0006) - multithreaded tests with default setup - get_fs_type() only"
+       echo "0007 x $(get_test_count 0007) - multithreaded tests with default setup test request_module() and get_fs_type()"
+       echo "0008 x $(get_test_count 0008) - multithreaded - push kmod_concurrent over max_modprobes for request_module()"
+       echo "0009 x $(get_test_count 0009) - multithreaded - push kmod_concurrent over max_modprobes for get_fs_type()"
+}
+
+usage()
+{
+       NUM_TESTS=$(grep -o ' ' <<<"$ALL_TESTS" | grep -c .)
+       let NUM_TESTS=$NUM_TESTS+1
+       MAX_TEST=$(printf "%04d\n" $NUM_TESTS)
+       echo "Usage: $0 [ -t <4-number-digit> ] | [ -w <4-number-digit> ] |"
+       echo "           [ -s <4-number-digit> ] | [ -c <4-number-digit> <test- count>"
+       echo "           [ all ] [ -h | --help ] [ -l ]"
+       echo ""
+       echo "Valid tests: 0001-$MAX_TEST"
+       echo ""
+       echo "    all     Runs all tests (default)"
+       echo "    -t      Run test ID the number amount of times is recommended"
+       echo "    -w      Watch test ID run until it runs into an error"
+       echo "    -c      Run test ID once"
+       echo "    -s      Run test ID x test-count number of times"
+       echo "    -l      List all test ID list"
+       echo " -h|--help  Help"
+       echo
+       echo "If an error every occurs execution will immediately terminate."
+       echo "If you are adding a new test try using -w <test-ID> first to"
+       echo "make sure the test passes a series of tests."
+       echo
+       echo Example uses:
+       echo
+       echo "${TEST_NAME}.sh           -- executes all tests"
+       echo "${TEST_NAME}.sh -t 0008   -- Executes test ID 0008 number of times is recomended"
+       echo "${TEST_NAME}.sh -w 0008   -- Watch test ID 0008 run until an error occurs"
+       echo "${TEST_NAME}.sh -s 0008   -- Run test ID 0008 once"
+       echo "${TEST_NAME}.sh -c 0008 3 -- Run test ID 0008 three times"
+       echo
+       list_tests
+       exit 1
+}
+
+function test_num()
+{
+       re='^[0-9]+$'
+       if ! [[ $1 =~ $re ]]; then
+               usage
+       fi
+}
+
+function get_test_count()
+{
+       test_num $1
+       TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
+       LAST_TWO=${TEST_DATA#*:*}
+       echo ${LAST_TWO%:*}
+}
+
+function get_test_enabled()
+{
+       test_num $1
+       TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
+       echo ${TEST_DATA#*:*:}
+}
+
+function run_all_tests()
+{
+       for i in $ALL_TESTS ; do
+               TEST_ID=${i%:*:*}
+               ENABLED=$(get_test_enabled $TEST_ID)
+               TEST_COUNT=$(get_test_count $TEST_ID)
+               if [[ $ENABLED -eq "1" ]]; then
+                       test_case $TEST_ID $TEST_COUNT
+               fi
+       done
+}
+
+function watch_log()
+{
+       if [ $# -ne 3 ]; then
+               clear
+       fi
+       date
+       echo "Running test: $2 - run #$1"
+}
+
+function watch_case()
+{
+       i=0
+       while [ 1 ]; do
+
+               if [ $# -eq 1 ]; then
+                       test_num $1
+                       watch_log $i ${TEST_NAME}_test_$1
+                       ${TEST_NAME}_test_$1
+               else
+                       watch_log $i all
+                       run_all_tests
+               fi
+               let i=$i+1
+       done
+}
+
+function test_case()
+{
+       NUM_TESTS=$DEFAULT_NUM_TESTS
+       if [ $# -eq 2 ]; then
+               NUM_TESTS=$2
+       fi
+
+       i=0
+       while [ $i -lt $NUM_TESTS ]; do
+               test_num $1
+               watch_log $i ${TEST_NAME}_test_$1 noclear
+               RUN_TEST=${TEST_NAME}_test_$1
+               $RUN_TEST
+               let i=$i+1
+       done
+}
+
+function parse_args()
+{
+       if [ $# -eq 0 ]; then
+               run_all_tests
+       else
+               if [[ "$1" = "all" ]]; then
+                       run_all_tests
+               elif [[ "$1" = "-w" ]]; then
+                       shift
+                       watch_case $@
+               elif [[ "$1" = "-t" ]]; then
+                       shift
+                       test_num $1
+                       test_case $1 $(get_test_count $1)
+               elif [[ "$1" = "-c" ]]; then
+                       shift
+                       test_num $1
+                       test_num $2
+                       test_case $1 $2
+               elif [[ "$1" = "-s" ]]; then
+                       shift
+                       test_case $1 1
+               elif [[ "$1" = "-l" ]]; then
+                       list_tests
+               elif [[ "$1" = "-h" || "$1" = "--help" ]]; then
+                       usage
+               else
+                       usage
+               fi
+       fi
+}
+
+test_reqs
+allow_user_defaults
+load_req_mod
+
+trap "test_finish" EXIT
+
+parse_args $@
+
+exit 0
index 13f5198..1c12b58 100755 (executable)
@@ -18,6 +18,7 @@ LIST_DEVS=FALSE
 
 DEBUGFS=${DEBUGFS-/sys/kernel/debug}
 
+DB_BITMASK=0x7FFF
 PERF_RUN_ORDER=32
 MAX_MW_SIZE=0
 RUN_DMA_TESTS=
@@ -38,6 +39,7 @@ function show_help()
        echo "be highly recommended."
        echo
        echo "Options:"
+       echo "  -b BITMASK      doorbell clear bitmask for ntb_tool"
        echo "  -C              don't cleanup ntb modules on exit"
        echo "  -d              run dma tests"
        echo "  -h              show this help message"
@@ -52,8 +54,9 @@ function show_help()
 function parse_args()
 {
        OPTIND=0
-       while getopts "Cdhlm:r:p:w:" opt; do
+       while getopts "b:Cdhlm:r:p:w:" opt; do
                case "$opt" in
+               b)  DB_BITMASK=${OPTARG} ;;
                C)  DONT_CLEANUP=1 ;;
                d)  RUN_DMA_TESTS=1 ;;
                h)  show_help; exit 0 ;;
@@ -85,6 +88,10 @@ set -e
 function _modprobe()
 {
         modprobe "$@"
+
+       if [[ "$REMOTE_HOST" != "" ]]; then
+               ssh "$REMOTE_HOST" modprobe "$@"
+       fi
 }
 
 function split_remote()
@@ -154,7 +161,7 @@ function doorbell_test()
 
        echo "Running db tests on: $(basename $LOC) / $(basename $REM)"
 
-       write_file "c 0xFFFFFFFF" "$REM/db"
+       write_file "c $DB_BITMASK" "$REM/db"
 
        for ((i=1; i <= 8; i++)); do
                let DB=$(read_file "$REM/db") || true
index b3c33e0..95c320b 100644 (file)
@@ -4,8 +4,7 @@
 # No binaries, but make sure arg-less "make" doesn't trigger "run_tests".
 all:
 
-TEST_PROGS := run_numerictests run_stringtests
-TEST_FILES := common_tests
+TEST_PROGS := sysctl.sh
 
 include ../lib.mk
 
diff --git a/tools/testing/selftests/sysctl/common_tests b/tools/testing/selftests/sysctl/common_tests
deleted file mode 100644 (file)
index b686232..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/bin/sh
-
-TEST_FILE=$(mktemp)
-
-echo "== Testing sysctl behavior against ${TARGET} =="
-
-set_orig()
-{
-       echo "${ORIG}" > "${TARGET}"
-}
-
-set_test()
-{
-       echo "${TEST_STR}" > "${TARGET}"
-}
-
-verify()
-{
-       local seen
-       seen=$(cat "$1")
-       if [ "${seen}" != "${TEST_STR}" ]; then
-               return 1
-       fi
-       return 0
-}
-
-exit_test()
-{
-       if [ ! -z ${old_strict} ]; then
-               echo ${old_strict} > ${WRITES_STRICT}
-       fi
-       exit $rc
-}
-
-trap 'set_orig; rm -f "${TEST_FILE}"' EXIT
-
-rc=0
-
-echo -n "Writing test file ... "
-echo "${TEST_STR}" > "${TEST_FILE}"
-if ! verify "${TEST_FILE}"; then
-       echo "FAIL" >&2
-       exit 1
-else
-       echo "ok"
-fi
-
-echo -n "Checking sysctl is not set to test value ... "
-if verify "${TARGET}"; then
-       echo "FAIL" >&2
-       exit 1
-else
-       echo "ok"
-fi
-
-echo -n "Writing sysctl from shell ... "
-set_test
-if ! verify "${TARGET}"; then
-       echo "FAIL" >&2
-       exit 1
-else
-       echo "ok"
-fi
-
-echo -n "Resetting sysctl to original value ... "
-set_orig
-if verify "${TARGET}"; then
-       echo "FAIL" >&2
-       exit 1
-else
-       echo "ok"
-fi
-
-echo -n "Checking write strict setting ... "
-WRITES_STRICT="${SYSCTL}/kernel/sysctl_writes_strict"
-if [ ! -e ${WRITES_STRICT} ]; then
-       echo "FAIL, but skip in case of old kernel" >&2
-else
-       old_strict=$(cat ${WRITES_STRICT})
-       if [ "$old_strict" = "1" ]; then
-               echo "ok"
-       else
-               echo "FAIL, strict value is 0 but force to 1 to continue" >&2
-               echo "1" > ${WRITES_STRICT}
-       fi
-fi
-
-# Now that we've validated the sanity of "set_test" and "set_orig",
-# we can use those functions to set starting states before running
-# specific behavioral tests.
-
-echo -n "Writing entire sysctl in single write ... "
-set_orig
-dd if="${TEST_FILE}" of="${TARGET}" bs=4096 2>/dev/null
-if ! verify "${TARGET}"; then
-       echo "FAIL" >&2
-       rc=1
-else
-       echo "ok"
-fi
-
-echo -n "Writing middle of sysctl after synchronized seek ... "
-set_test
-dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 skip=1 2>/dev/null
-if ! verify "${TARGET}"; then
-       echo "FAIL" >&2
-       rc=1
-else
-       echo "ok"
-fi
-
-echo -n "Writing beyond end of sysctl ... "
-set_orig
-dd if="${TEST_FILE}" of="${TARGET}" bs=20 seek=2 2>/dev/null
-if verify "${TARGET}"; then
-        echo "FAIL" >&2
-        rc=1
-else
-        echo "ok"
-fi
-
-echo -n "Writing sysctl with multiple long writes ... "
-set_orig
-(perl -e 'print "A" x 50;'; echo "${TEST_STR}") | \
-       dd of="${TARGET}" bs=50 2>/dev/null
-if verify "${TARGET}"; then
-       echo "FAIL" >&2
-       rc=1
-else
-       echo "ok"
-fi
diff --git a/tools/testing/selftests/sysctl/config b/tools/testing/selftests/sysctl/config
new file mode 100644 (file)
index 0000000..6ca1480
--- /dev/null
@@ -0,0 +1 @@
+CONFIG_TEST_SYSCTL=y
diff --git a/tools/testing/selftests/sysctl/run_numerictests b/tools/testing/selftests/sysctl/run_numerictests
deleted file mode 100755 (executable)
index e6e76c9..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-
-SYSCTL="/proc/sys"
-TARGET="${SYSCTL}/vm/swappiness"
-ORIG=$(cat "${TARGET}")
-TEST_STR=$(( $ORIG + 1 ))
-
-. ./common_tests
-
-exit_test
diff --git a/tools/testing/selftests/sysctl/run_stringtests b/tools/testing/selftests/sysctl/run_stringtests
deleted file mode 100755 (executable)
index 857ec66..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/bin/sh
-
-SYSCTL="/proc/sys"
-TARGET="${SYSCTL}/kernel/domainname"
-ORIG=$(cat "${TARGET}")
-TEST_STR="Testing sysctl"
-
-. ./common_tests
-
-# Only string sysctls support seeking/appending.
-MAXLEN=65
-
-echo -n "Writing entire sysctl in short writes ... "
-set_orig
-dd if="${TEST_FILE}" of="${TARGET}" bs=1 2>/dev/null
-if ! verify "${TARGET}"; then
-       echo "FAIL" >&2
-       rc=1
-else
-       echo "ok"
-fi
-
-echo -n "Writing middle of sysctl after unsynchronized seek ... "
-set_test
-dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 2>/dev/null
-if verify "${TARGET}"; then
-       echo "FAIL" >&2
-       rc=1
-else
-       echo "ok"
-fi
-
-echo -n "Checking sysctl maxlen is at least $MAXLEN ... "
-set_orig
-perl -e 'print "A" x ('"${MAXLEN}"'-2), "B";' | \
-       dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null
-if ! grep -q B "${TARGET}"; then
-       echo "FAIL" >&2
-       rc=1
-else
-       echo "ok"
-fi
-
-echo -n "Checking sysctl keeps original string on overflow append ... "
-set_orig
-perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \
-       dd of="${TARGET}" bs=$(( MAXLEN - 1 )) 2>/dev/null
-if grep -q B "${TARGET}"; then
-       echo "FAIL" >&2
-       rc=1
-else
-       echo "ok"
-fi
-
-echo -n "Checking sysctl stays NULL terminated on write ... "
-set_orig
-perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \
-       dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null
-if grep -q B "${TARGET}"; then
-       echo "FAIL" >&2
-       rc=1
-else
-       echo "ok"
-fi
-
-echo -n "Checking sysctl stays NULL terminated on overwrite ... "
-set_orig
-perl -e 'print "A" x ('"${MAXLEN}"'-1), "BB";' | \
-       dd of="${TARGET}" bs=$(( $MAXLEN + 1 )) 2>/dev/null
-if grep -q B "${TARGET}"; then
-       echo "FAIL" >&2
-       rc=1
-else
-       echo "ok"
-fi
-
-exit_test
diff --git a/tools/testing/selftests/sysctl/sysctl.sh b/tools/testing/selftests/sysctl/sysctl.sh
new file mode 100644 (file)
index 0000000..ec232c3
--- /dev/null
@@ -0,0 +1,774 @@
+#!/bin/bash
+# Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org>
+#
+# 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; or, when distributed separately from the Linux kernel or
+# when incorporated into other software packages, subject to the following
+# license:
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of copyleft-next (version 0.3.1 or later) as published
+# at http://copyleft-next.org/.
+
+# This performs a series tests against the proc sysctl interface.
+
+TEST_NAME="sysctl"
+TEST_DRIVER="test_${TEST_NAME}"
+TEST_DIR=$(dirname $0)
+TEST_FILE=$(mktemp)
+
+# This represents
+#
+# TEST_ID:TEST_COUNT:ENABLED
+#
+# TEST_ID: is the test id number
+# TEST_COUNT: number of times we should run the test
+# ENABLED: 1 if enabled, 0 otherwise
+#
+# Once these are enabled please leave them as-is. Write your own test,
+# we have tons of space.
+ALL_TESTS="0001:1:1"
+ALL_TESTS="$ALL_TESTS 0002:1:1"
+ALL_TESTS="$ALL_TESTS 0003:1:1"
+ALL_TESTS="$ALL_TESTS 0004:1:1"
+ALL_TESTS="$ALL_TESTS 0005:3:1"
+
+test_modprobe()
+{
+       if [ ! -d $DIR ]; then
+               echo "$0: $DIR not present" >&2
+               echo "You must have the following enabled in your kernel:" >&2
+               cat $TEST_DIR/config >&2
+               exit 1
+       fi
+}
+
+function allow_user_defaults()
+{
+       if [ -z $DIR ]; then
+               DIR="/sys/module/test_sysctl/"
+       fi
+       if [ -z $DEFAULT_NUM_TESTS ]; then
+               DEFAULT_NUM_TESTS=50
+       fi
+       if [ -z $SYSCTL ]; then
+               SYSCTL="/proc/sys/debug/test_sysctl"
+       fi
+       if [ -z $PROD_SYSCTL ]; then
+               PROD_SYSCTL="/proc/sys"
+       fi
+       if [ -z $WRITES_STRICT ]; then
+               WRITES_STRICT="${PROD_SYSCTL}/kernel/sysctl_writes_strict"
+       fi
+}
+
+function check_production_sysctl_writes_strict()
+{
+       echo -n "Checking production write strict setting ... "
+       if [ ! -e ${WRITES_STRICT} ]; then
+               echo "FAIL, but skip in case of old kernel" >&2
+       else
+               old_strict=$(cat ${WRITES_STRICT})
+               if [ "$old_strict" = "1" ]; then
+                       echo "ok"
+               else
+                       echo "FAIL, strict value is 0 but force to 1 to continue" >&2
+                       echo "1" > ${WRITES_STRICT}
+               fi
+       fi
+
+       if [ -z $PAGE_SIZE ]; then
+               PAGE_SIZE=$(getconf PAGESIZE)
+       fi
+       if [ -z $MAX_DIGITS ]; then
+               MAX_DIGITS=$(($PAGE_SIZE/8))
+       fi
+       if [ -z $INT_MAX ]; then
+               INT_MAX=$(getconf INT_MAX)
+       fi
+       if [ -z $UINT_MAX ]; then
+               UINT_MAX=$(getconf UINT_MAX)
+       fi
+}
+
+test_reqs()
+{
+       uid=$(id -u)
+       if [ $uid -ne 0 ]; then
+               echo $msg must be run as root >&2
+               exit 0
+       fi
+
+       if ! which perl 2> /dev/null > /dev/null; then
+               echo "$0: You need perl installed"
+               exit 1
+       fi
+       if ! which getconf 2> /dev/null > /dev/null; then
+               echo "$0: You need getconf installed"
+               exit 1
+       fi
+       if ! which diff 2> /dev/null > /dev/null; then
+               echo "$0: You need diff installed"
+               exit 1
+       fi
+}
+
+function load_req_mod()
+{
+       trap "test_modprobe" EXIT
+
+       if [ ! -d $DIR ]; then
+               modprobe $TEST_DRIVER
+               if [ $? -ne 0 ]; then
+                       exit
+               fi
+       fi
+}
+
+reset_vals()
+{
+       VAL=""
+       TRIGGER=$(basename ${TARGET})
+       case "$TRIGGER" in
+               int_0001)
+                       VAL="60"
+                       ;;
+               int_0002)
+                       VAL="1"
+                       ;;
+               uint_0001)
+                       VAL="314"
+                       ;;
+               string_0001)
+                       VAL="(none)"
+                       ;;
+               *)
+                       ;;
+       esac
+       echo -n $VAL > $TARGET
+}
+
+set_orig()
+{
+       if [ ! -z $TARGET ]; then
+               echo "${ORIG}" > "${TARGET}"
+       fi
+}
+
+set_test()
+{
+       echo "${TEST_STR}" > "${TARGET}"
+}
+
+verify()
+{
+       local seen
+       seen=$(cat "$1")
+       if [ "${seen}" != "${TEST_STR}" ]; then
+               return 1
+       fi
+       return 0
+}
+
+verify_diff_w()
+{
+       echo "$TEST_STR" | diff -q -w -u - $1
+       return $?
+}
+
+test_rc()
+{
+       if [[ $rc != 0 ]]; then
+               echo "Failed test, return value: $rc" >&2
+               exit $rc
+       fi
+}
+
+test_finish()
+{
+       set_orig
+       rm -f "${TEST_FILE}"
+
+       if [ ! -z ${old_strict} ]; then
+               echo ${old_strict} > ${WRITES_STRICT}
+       fi
+       exit $rc
+}
+
+run_numerictests()
+{
+       echo "== Testing sysctl behavior against ${TARGET} =="
+
+       rc=0
+
+       echo -n "Writing test file ... "
+       echo "${TEST_STR}" > "${TEST_FILE}"
+       if ! verify "${TEST_FILE}"; then
+               echo "FAIL" >&2
+               exit 1
+       else
+               echo "ok"
+       fi
+
+       echo -n "Checking sysctl is not set to test value ... "
+       if verify "${TARGET}"; then
+               echo "FAIL" >&2
+               exit 1
+       else
+               echo "ok"
+       fi
+
+       echo -n "Writing sysctl from shell ... "
+       set_test
+       if ! verify "${TARGET}"; then
+               echo "FAIL" >&2
+               exit 1
+       else
+               echo "ok"
+       fi
+
+       echo -n "Resetting sysctl to original value ... "
+       set_orig
+       if verify "${TARGET}"; then
+               echo "FAIL" >&2
+               exit 1
+       else
+               echo "ok"
+       fi
+
+       # Now that we've validated the sanity of "set_test" and "set_orig",
+       # we can use those functions to set starting states before running
+       # specific behavioral tests.
+
+       echo -n "Writing entire sysctl in single write ... "
+       set_orig
+       dd if="${TEST_FILE}" of="${TARGET}" bs=4096 2>/dev/null
+       if ! verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+
+       echo -n "Writing middle of sysctl after synchronized seek ... "
+       set_test
+       dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 skip=1 2>/dev/null
+       if ! verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+
+       echo -n "Writing beyond end of sysctl ... "
+       set_orig
+       dd if="${TEST_FILE}" of="${TARGET}" bs=20 seek=2 2>/dev/null
+       if verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+
+       echo -n "Writing sysctl with multiple long writes ... "
+       set_orig
+       (perl -e 'print "A" x 50;'; echo "${TEST_STR}") | \
+               dd of="${TARGET}" bs=50 2>/dev/null
+       if verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+}
+
+# Your test must accept digits 3 and 4 to use this
+run_limit_digit()
+{
+       echo -n "Checking ignoring spaces up to PAGE_SIZE works on write ..."
+       reset_vals
+
+       LIMIT=$((MAX_DIGITS -1))
+       TEST_STR="3"
+       (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \
+               dd of="${TARGET}" 2>/dev/null
+
+       if ! verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+
+       echo -n "Checking passing PAGE_SIZE of spaces fails on write ..."
+       reset_vals
+
+       LIMIT=$((MAX_DIGITS))
+       TEST_STR="4"
+       (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \
+               dd of="${TARGET}" 2>/dev/null
+
+       if verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+}
+
+# You are using an int
+run_limit_digit_int()
+{
+       echo -n "Testing INT_MAX works ..."
+       reset_vals
+       TEST_STR="$INT_MAX"
+       echo -n $TEST_STR > $TARGET
+
+       if ! verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+
+       echo -n "Testing INT_MAX + 1 will fail as expected..."
+       reset_vals
+       let TEST_STR=$INT_MAX+1
+       echo -n $TEST_STR > $TARGET 2> /dev/null
+
+       if verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+
+       echo -n "Testing negative values will work as expected..."
+       reset_vals
+       TEST_STR="-3"
+       echo -n $TEST_STR > $TARGET 2> /dev/null
+       if ! verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+}
+
+# You used an int array
+run_limit_digit_int_array()
+{
+       echo -n "Testing array works as expected ... "
+       TEST_STR="4 3 2 1"
+       echo -n $TEST_STR > $TARGET
+
+       if ! verify_diff_w "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+
+       echo -n "Testing skipping trailing array elements works ... "
+       # Do not reset_vals, carry on the values from the last test.
+       # If we only echo in two digits the last two are left intact
+       TEST_STR="100 101"
+       echo -n $TEST_STR > $TARGET
+       # After we echo in, to help diff we need to set on TEST_STR what
+       # we expect the result to be.
+       TEST_STR="100 101 2 1"
+
+       if ! verify_diff_w "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+
+       echo -n "Testing PAGE_SIZE limit on array works ... "
+       # Do not reset_vals, carry on the values from the last test.
+       # Even if you use an int array, you are still restricted to
+       # MAX_DIGITS, this is a known limitation. Test limit works.
+       LIMIT=$((MAX_DIGITS -1))
+       TEST_STR="9"
+       (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \
+               dd of="${TARGET}" 2>/dev/null
+
+       TEST_STR="9 101 2 1"
+       if ! verify_diff_w "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+
+       echo -n "Testing exceeding PAGE_SIZE limit fails as expected ... "
+       # Do not reset_vals, carry on the values from the last test.
+       # Now go over limit.
+       LIMIT=$((MAX_DIGITS))
+       TEST_STR="7"
+       (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \
+               dd of="${TARGET}" 2>/dev/null
+
+       TEST_STR="7 101 2 1"
+       if verify_diff_w "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+}
+
+# You are using an unsigned int
+run_limit_digit_uint()
+{
+       echo -n "Testing UINT_MAX works ..."
+       reset_vals
+       TEST_STR="$UINT_MAX"
+       echo -n $TEST_STR > $TARGET
+
+       if ! verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+
+       echo -n "Testing UINT_MAX + 1 will fail as expected..."
+       reset_vals
+       TEST_STR=$(($UINT_MAX+1))
+       echo -n $TEST_STR > $TARGET 2> /dev/null
+
+       if verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+
+       echo -n "Testing negative values will not work as expected ..."
+       reset_vals
+       TEST_STR="-3"
+       echo -n $TEST_STR > $TARGET 2> /dev/null
+
+       if verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+       test_rc
+}
+
+run_stringtests()
+{
+       echo -n "Writing entire sysctl in short writes ... "
+       set_orig
+       dd if="${TEST_FILE}" of="${TARGET}" bs=1 2>/dev/null
+       if ! verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+
+       echo -n "Writing middle of sysctl after unsynchronized seek ... "
+       set_test
+       dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 2>/dev/null
+       if verify "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+
+       echo -n "Checking sysctl maxlen is at least $MAXLEN ... "
+       set_orig
+       perl -e 'print "A" x ('"${MAXLEN}"'-2), "B";' | \
+               dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null
+       if ! grep -q B "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+
+       echo -n "Checking sysctl keeps original string on overflow append ... "
+       set_orig
+       perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \
+               dd of="${TARGET}" bs=$(( MAXLEN - 1 )) 2>/dev/null
+       if grep -q B "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+
+       echo -n "Checking sysctl stays NULL terminated on write ... "
+       set_orig
+       perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \
+               dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null
+       if grep -q B "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+
+       echo -n "Checking sysctl stays NULL terminated on overwrite ... "
+       set_orig
+       perl -e 'print "A" x ('"${MAXLEN}"'-1), "BB";' | \
+               dd of="${TARGET}" bs=$(( $MAXLEN + 1 )) 2>/dev/null
+       if grep -q B "${TARGET}"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+       fi
+
+       test_rc
+}
+
+sysctl_test_0001()
+{
+       TARGET="${SYSCTL}/int_0001"
+       reset_vals
+       ORIG=$(cat "${TARGET}")
+       TEST_STR=$(( $ORIG + 1 ))
+
+       run_numerictests
+       run_limit_digit
+}
+
+sysctl_test_0002()
+{
+       TARGET="${SYSCTL}/string_0001"
+       reset_vals
+       ORIG=$(cat "${TARGET}")
+       TEST_STR="Testing sysctl"
+       # Only string sysctls support seeking/appending.
+       MAXLEN=65
+
+       run_numerictests
+       run_stringtests
+}
+
+sysctl_test_0003()
+{
+       TARGET="${SYSCTL}/int_0002"
+       reset_vals
+       ORIG=$(cat "${TARGET}")
+       TEST_STR=$(( $ORIG + 1 ))
+
+       run_numerictests
+       run_limit_digit
+       run_limit_digit_int
+}
+
+sysctl_test_0004()
+{
+       TARGET="${SYSCTL}/uint_0001"
+       reset_vals
+       ORIG=$(cat "${TARGET}")
+       TEST_STR=$(( $ORIG + 1 ))
+
+       run_numerictests
+       run_limit_digit
+       run_limit_digit_uint
+}
+
+sysctl_test_0005()
+{
+       TARGET="${SYSCTL}/int_0003"
+       reset_vals
+       ORIG=$(cat "${TARGET}")
+
+       run_limit_digit_int_array
+}
+
+list_tests()
+{
+       echo "Test ID list:"
+       echo
+       echo "TEST_ID x NUM_TEST"
+       echo "TEST_ID:   Test ID"
+       echo "NUM_TESTS: Number of recommended times to run the test"
+       echo
+       echo "0001 x $(get_test_count 0001) - tests proc_dointvec_minmax()"
+       echo "0002 x $(get_test_count 0002) - tests proc_dostring()"
+       echo "0003 x $(get_test_count 0003) - tests proc_dointvec()"
+       echo "0004 x $(get_test_count 0004) - tests proc_douintvec()"
+       echo "0005 x $(get_test_count 0005) - tests proc_douintvec() array"
+}
+
+test_reqs
+
+usage()
+{
+       NUM_TESTS=$(grep -o ' ' <<<"$ALL_TESTS" | grep -c .)
+       let NUM_TESTS=$NUM_TESTS+1
+       MAX_TEST=$(printf "%04d\n" $NUM_TESTS)
+       echo "Usage: $0 [ -t <4-number-digit> ] | [ -w <4-number-digit> ] |"
+       echo "           [ -s <4-number-digit> ] | [ -c <4-number-digit> <test- count>"
+       echo "           [ all ] [ -h | --help ] [ -l ]"
+       echo ""
+       echo "Valid tests: 0001-$MAX_TEST"
+       echo ""
+       echo "    all     Runs all tests (default)"
+       echo "    -t      Run test ID the number amount of times is recommended"
+       echo "    -w      Watch test ID run until it runs into an error"
+       echo "    -c      Run test ID once"
+       echo "    -s      Run test ID x test-count number of times"
+       echo "    -l      List all test ID list"
+       echo " -h|--help  Help"
+       echo
+       echo "If an error every occurs execution will immediately terminate."
+       echo "If you are adding a new test try using -w <test-ID> first to"
+       echo "make sure the test passes a series of tests."
+       echo
+       echo Example uses:
+       echo
+       echo "$TEST_NAME.sh            -- executes all tests"
+       echo "$TEST_NAME.sh -t 0002    -- Executes test ID 0002 number of times is recomended"
+       echo "$TEST_NAME.sh -w 0002    -- Watch test ID 0002 run until an error occurs"
+       echo "$TEST_NAME.sh -s 0002    -- Run test ID 0002 once"
+       echo "$TEST_NAME.sh -c 0002 3  -- Run test ID 0002 three times"
+       echo
+       list_tests
+       exit 1
+}
+
+function test_num()
+{
+       re='^[0-9]+$'
+       if ! [[ $1 =~ $re ]]; then
+               usage
+       fi
+}
+
+function get_test_count()
+{
+       test_num $1
+       TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
+       LAST_TWO=${TEST_DATA#*:*}
+       echo ${LAST_TWO%:*}
+}
+
+function get_test_enabled()
+{
+       test_num $1
+       TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
+       echo ${TEST_DATA#*:*:}
+}
+
+function run_all_tests()
+{
+       for i in $ALL_TESTS ; do
+               TEST_ID=${i%:*:*}
+               ENABLED=$(get_test_enabled $TEST_ID)
+               TEST_COUNT=$(get_test_count $TEST_ID)
+               if [[ $ENABLED -eq "1" ]]; then
+                       test_case $TEST_ID $TEST_COUNT
+               fi
+       done
+}
+
+function watch_log()
+{
+       if [ $# -ne 3 ]; then
+               clear
+       fi
+       date
+       echo "Running test: $2 - run #$1"
+}
+
+function watch_case()
+{
+       i=0
+       while [ 1 ]; do
+
+               if [ $# -eq 1 ]; then
+                       test_num $1
+                       watch_log $i ${TEST_NAME}_test_$1
+                       ${TEST_NAME}_test_$1
+               else
+                       watch_log $i all
+                       run_all_tests
+               fi
+               let i=$i+1
+       done
+}
+
+function test_case()
+{
+       NUM_TESTS=$DEFAULT_NUM_TESTS
+       if [ $# -eq 2 ]; then
+               NUM_TESTS=$2
+       fi
+
+       i=0
+       while [ $i -lt $NUM_TESTS ]; do
+               test_num $1
+               watch_log $i ${TEST_NAME}_test_$1 noclear
+               RUN_TEST=${TEST_NAME}_test_$1
+               $RUN_TEST
+               let i=$i+1
+       done
+}
+
+function parse_args()
+{
+       if [ $# -eq 0 ]; then
+               run_all_tests
+       else
+               if [[ "$1" = "all" ]]; then
+                       run_all_tests
+               elif [[ "$1" = "-w" ]]; then
+                       shift
+                       watch_case $@
+               elif [[ "$1" = "-t" ]]; then
+                       shift
+                       test_num $1
+                       test_case $1 $(get_test_count $1)
+               elif [[ "$1" = "-c" ]]; then
+                       shift
+                       test_num $1
+                       test_num $2
+                       test_case $1 $2
+               elif [[ "$1" = "-s" ]]; then
+                       shift
+                       test_case $1 1
+               elif [[ "$1" = "-l" ]]; then
+                       list_tests
+               elif [[ "$1" = "-h" || "$1" = "--help" ]]; then
+                       usage
+               else
+                       usage
+               fi
+       fi
+}
+
+test_reqs
+allow_user_defaults
+check_production_sysctl_writes_strict
+load_req_mod
+
+trap "test_finish" EXIT
+
+parse_args $@
+
+exit 0
index 5801bbe..a9b8613 100644 (file)
@@ -9,7 +9,7 @@ TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \
 
 TEST_GEN_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew \
                      skew_consistency clocksource-switch freq-step leap-a-day \
-                     leapcrash set-tai set-2038 set-tz
+                     leapcrash set-tai set-2038 set-tz rtctest_setdate
 
 
 include ../lib.mk
index 4230d30..f61170f 100644 (file)
@@ -21,6 +21,9 @@
 #include <stdlib.h>
 #include <errno.h>
 
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
 
 /*
  * This expects the new RTC class driver framework, working with
  */
 static const char default_rtc[] = "/dev/rtc0";
 
+static struct rtc_time cutoff_dates[] = {
+       {
+               .tm_year = 70, /* 1970 -1900 */
+               .tm_mday = 1,
+       },
+       /* signed time_t 19/01/2038 3:14:08 */
+       {
+               .tm_year = 138,
+               .tm_mday = 19,
+       },
+       {
+               .tm_year = 138,
+               .tm_mday = 20,
+       },
+       {
+               .tm_year = 199, /* 2099 -1900 */
+               .tm_mday = 1,
+       },
+       {
+               .tm_year = 200, /* 2100 -1900 */
+               .tm_mday = 1,
+       },
+       /* unsigned time_t 07/02/2106 7:28:15*/
+       {
+               .tm_year = 205,
+               .tm_mon = 1,
+               .tm_mday = 7,
+       },
+       {
+               .tm_year = 206,
+               .tm_mon = 1,
+               .tm_mday = 8,
+       },
+       /* signed time on 64bit in nanoseconds 12/04/2262 01:47:16*/
+       {
+               .tm_year = 362,
+               .tm_mon = 3,
+               .tm_mday = 12,
+       },
+       {
+               .tm_year = 362, /* 2262 -1900 */
+               .tm_mon = 3,
+               .tm_mday = 13,
+       },
+};
+
+static int compare_dates(struct rtc_time *a, struct rtc_time *b)
+{
+       if (a->tm_year != b->tm_year ||
+           a->tm_mon != b->tm_mon ||
+           a->tm_mday != b->tm_mday ||
+           a->tm_hour != b->tm_hour ||
+           a->tm_min != b->tm_min ||
+           ((b->tm_sec - a->tm_sec) > 1))
+               return 1;
+
+       return 0;
+}
 
 int main(int argc, char **argv)
 {
-       int i, fd, retval, irqcount = 0;
+       int i, fd, retval, irqcount = 0, dangerous = 0;
        unsigned long tmp, data;
        struct rtc_time rtc_tm;
        const char *rtc = default_rtc;
        struct timeval start, end, diff;
 
        switch (argc) {
+       case 3:
+               if (*argv[2] == 'd')
+                       dangerous = 1;
        case 2:
                rtc = argv[1];
                /* FALLTHROUGH */
        case 1:
                break;
        default:
-               fprintf(stderr, "usage:  rtctest [rtcdev]\n");
+               fprintf(stderr, "usage:  rtctest [rtcdev] [d]\n");
                return 1;
        }
 
@@ -202,7 +266,7 @@ test_PIE:
                /* not all RTCs support periodic IRQs */
                if (errno == EINVAL) {
                        fprintf(stderr, "\nNo periodic IRQ support\n");
-                       goto done;
+                       goto test_DATE;
                }
                perror("RTC_IRQP_READ ioctl");
                exit(errno);
@@ -221,7 +285,7 @@ test_PIE:
                        if (errno == EINVAL) {
                                fprintf(stderr,
                                        "\n...Periodic IRQ rate is fixed\n");
-                               goto done;
+                               goto test_DATE;
                        }
                        perror("RTC_IRQP_SET ioctl");
                        exit(errno);
@@ -269,6 +333,62 @@ test_PIE:
                }
        }
 
+test_DATE:
+       if (!dangerous)
+               goto done;
+
+       fprintf(stderr, "\nTesting problematic dates\n");
+
+       for (i = 0; i < ARRAY_SIZE(cutoff_dates); i++) {
+               struct rtc_time current;
+
+               /* Write the new date in RTC */
+               retval = ioctl(fd, RTC_SET_TIME, &cutoff_dates[i]);
+               if (retval == -1) {
+                       perror("RTC_SET_TIME ioctl");
+                       close(fd);
+                       exit(errno);
+               }
+
+               /* Read back */
+               retval = ioctl(fd, RTC_RD_TIME, &current);
+               if (retval == -1) {
+                       perror("RTC_RD_TIME ioctl");
+                       exit(errno);
+               }
+
+               if(compare_dates(&cutoff_dates[i], &current)) {
+                       fprintf(stderr,"Setting date %d failed\n",
+                               cutoff_dates[i].tm_year + 1900);
+                       goto done;
+               }
+
+               cutoff_dates[i].tm_sec += 5;
+
+               /* Write the new alarm in RTC */
+               retval = ioctl(fd, RTC_ALM_SET, &cutoff_dates[i]);
+               if (retval == -1) {
+                       perror("RTC_ALM_SET ioctl");
+                       close(fd);
+                       exit(errno);
+               }
+
+               /* Read back */
+               retval = ioctl(fd, RTC_ALM_READ, &current);
+               if (retval == -1) {
+                       perror("RTC_ALM_READ ioctl");
+                       exit(errno);
+               }
+
+               if(compare_dates(&cutoff_dates[i], &current)) {
+                       fprintf(stderr,"Setting alarm %d failed\n",
+                               cutoff_dates[i].tm_year + 1900);
+                       goto done;
+               }
+
+               fprintf(stderr, "Setting year %d is OK \n",
+                       cutoff_dates[i].tm_year + 1900);
+       }
 done:
        fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n");
 
diff --git a/tools/testing/selftests/timers/rtctest_setdate.c b/tools/testing/selftests/timers/rtctest_setdate.c
new file mode 100644 (file)
index 0000000..2cb7848
--- /dev/null
@@ -0,0 +1,86 @@
+/* Real Time Clock Driver Test
+ *     by: Benjamin Gaignard (benjamin.gaignard@linaro.org)
+ *
+ * To build
+ *     gcc rtctest_setdate.c -o rtctest_setdate
+ *
+ *   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 <stdio.h>
+#include <linux/rtc.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+static const char default_time[] = "00:00:00";
+
+int main(int argc, char **argv)
+{
+       int fd, retval;
+       struct rtc_time new, current;
+       const char *rtc, *date;
+       const char *time = default_time;
+
+       switch (argc) {
+       case 4:
+               time = argv[3];
+               /* FALLTHROUGH */
+       case 3:
+               date = argv[2];
+               rtc = argv[1];
+               break;
+       default:
+               fprintf(stderr, "usage: rtctest_setdate <rtcdev> <DD-MM-YYYY> [HH:MM:SS]\n");
+               return 1;
+       }
+
+       fd = open(rtc, O_RDONLY);
+       if (fd == -1) {
+               perror(rtc);
+               exit(errno);
+       }
+
+       sscanf(date, "%d-%d-%d", &new.tm_mday, &new.tm_mon, &new.tm_year);
+       new.tm_mon -= 1;
+       new.tm_year -= 1900;
+       sscanf(time, "%d:%d:%d", &new.tm_hour, &new.tm_min, &new.tm_sec);
+
+       fprintf(stderr, "Test will set RTC date/time to %d-%d-%d, %02d:%02d:%02d.\n",
+               new.tm_mday, new.tm_mon + 1, new.tm_year + 1900,
+               new.tm_hour, new.tm_min, new.tm_sec);
+
+       /* Write the new date in RTC */
+       retval = ioctl(fd, RTC_SET_TIME, &new);
+       if (retval == -1) {
+               perror("RTC_SET_TIME ioctl");
+               close(fd);
+               exit(errno);
+       }
+
+       /* Read back */
+       retval = ioctl(fd, RTC_RD_TIME, &current);
+       if (retval == -1) {
+               perror("RTC_RD_TIME ioctl");
+               exit(errno);
+       }
+
+       fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",
+               current.tm_mday, current.tm_mon + 1, current.tm_year + 1900,
+               current.tm_hour, current.tm_min, current.tm_sec);
+
+       close(fd);
+       return 0;
+}
index 9120edf..f2ac53a 100644 (file)
@@ -825,7 +825,7 @@ static int kvm_assign_ioeventfd_idx(struct kvm *kvm,
        if (ret < 0)
                goto unlock_fail;
 
-       kvm->buses[bus_idx]->ioeventfd_count++;
+       kvm_get_bus(kvm, bus_idx)->ioeventfd_count++;
        list_add_tail(&p->list, &kvm->ioeventfds);
 
        mutex_unlock(&kvm->slots_lock);
@@ -848,6 +848,7 @@ kvm_deassign_ioeventfd_idx(struct kvm *kvm, enum kvm_bus bus_idx,
 {
        struct _ioeventfd        *p, *tmp;
        struct eventfd_ctx       *eventfd;
+       struct kvm_io_bus        *bus;
        int                       ret = -ENOENT;
 
        eventfd = eventfd_ctx_fdget(args->fd);
@@ -870,8 +871,9 @@ kvm_deassign_ioeventfd_idx(struct kvm *kvm, enum kvm_bus bus_idx,
                        continue;
 
                kvm_io_bus_unregister_dev(kvm, bus_idx, &p->dev);
-               if (kvm->buses[bus_idx])
-                       kvm->buses[bus_idx]->ioeventfd_count--;
+               bus = kvm_get_bus(kvm, bus_idx);
+               if (bus)
+                       bus->ioeventfd_count--;
                ioeventfd_release(p);
                ret = 0;
                break;
index 31e40c9..b1286c4 100644 (file)
@@ -230,7 +230,7 @@ int kvm_set_irq_routing(struct kvm *kvm,
        }
 
        mutex_lock(&kvm->irq_lock);
-       old = kvm->irq_routing;
+       old = rcu_dereference_protected(kvm->irq_routing, 1);
        rcu_assign_pointer(kvm->irq_routing, new);
        kvm_irq_routing_update(kvm);
        kvm_arch_irq_routing_update(kvm);
index 19f0ecb..f3f7427 100644 (file)
@@ -130,6 +130,12 @@ EXPORT_SYMBOL_GPL(kvm_rebooting);
 
 static bool largepages_enabled = true;
 
+#define KVM_EVENT_CREATE_VM 0
+#define KVM_EVENT_DESTROY_VM 1
+static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm);
+static unsigned long long kvm_createvm_count;
+static unsigned long long kvm_active_vms;
+
 bool kvm_is_reserved_pfn(kvm_pfn_t pfn)
 {
        if (pfn_valid(pfn))
@@ -187,12 +193,23 @@ static void ack_flush(void *_completed)
 {
 }
 
+static inline bool kvm_kick_many_cpus(const struct cpumask *cpus, bool wait)
+{
+       if (unlikely(!cpus))
+               cpus = cpu_online_mask;
+
+       if (cpumask_empty(cpus))
+               return false;
+
+       smp_call_function_many(cpus, ack_flush, NULL, wait);
+       return true;
+}
+
 bool kvm_make_all_cpus_request(struct kvm *kvm, unsigned int req)
 {
        int i, cpu, me;
        cpumask_var_t cpus;
-       bool called = true;
-       bool wait = req & KVM_REQUEST_WAIT;
+       bool called;
        struct kvm_vcpu *vcpu;
 
        zalloc_cpumask_var(&cpus, GFP_ATOMIC);
@@ -207,14 +224,9 @@ bool kvm_make_all_cpus_request(struct kvm *kvm, unsigned int req)
 
                if (cpus != NULL && cpu != -1 && cpu != me &&
                    kvm_request_needs_ipi(vcpu, req))
-                       cpumask_set_cpu(cpu, cpus);
+                       __cpumask_set_cpu(cpu, cpus);
        }
-       if (unlikely(cpus == NULL))
-               smp_call_function_many(cpu_online_mask, ack_flush, NULL, wait);
-       else if (!cpumask_empty(cpus))
-               smp_call_function_many(cpus, ack_flush, NULL, wait);
-       else
-               called = false;
+       called = kvm_kick_many_cpus(cpus, !!(req & KVM_REQUEST_WAIT));
        put_cpu();
        free_cpumask_var(cpus);
        return called;
@@ -293,7 +305,12 @@ EXPORT_SYMBOL_GPL(kvm_vcpu_init);
 
 void kvm_vcpu_uninit(struct kvm_vcpu *vcpu)
 {
-       put_pid(vcpu->pid);
+       /*
+        * no need for rcu_read_lock as VCPU_RUN is the only place that
+        * will change the vcpu->pid pointer and on uninit all file
+        * descriptors are already gone.
+        */
+       put_pid(rcu_dereference_protected(vcpu->pid, 1));
        kvm_arch_vcpu_uninit(vcpu);
        free_page((unsigned long)vcpu->run);
 }
@@ -674,8 +691,8 @@ static struct kvm *kvm_create_vm(unsigned long type)
        if (init_srcu_struct(&kvm->irq_srcu))
                goto out_err_no_irq_srcu;
        for (i = 0; i < KVM_NR_BUSES; i++) {
-               kvm->buses[i] = kzalloc(sizeof(struct kvm_io_bus),
-                                       GFP_KERNEL);
+               rcu_assign_pointer(kvm->buses[i],
+                       kzalloc(sizeof(struct kvm_io_bus), GFP_KERNEL));
                if (!kvm->buses[i])
                        goto out_err;
        }
@@ -700,9 +717,10 @@ out_err_no_srcu:
        hardware_disable_all();
 out_err_no_disable:
        for (i = 0; i < KVM_NR_BUSES; i++)
-               kfree(kvm->buses[i]);
+               kfree(rcu_access_pointer(kvm->buses[i]));
        for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++)
-               kvm_free_memslots(kvm, kvm->memslots[i]);
+               kvm_free_memslots(kvm,
+                       rcu_dereference_protected(kvm->memslots[i], 1));
        kvm_arch_free_vm(kvm);
        mmdrop(current->mm);
        return ERR_PTR(r);
@@ -728,6 +746,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
        int i;
        struct mm_struct *mm = kvm->mm;
 
+       kvm_uevent_notify_change(KVM_EVENT_DESTROY_VM, kvm);
        kvm_destroy_vm_debugfs(kvm);
        kvm_arch_sync_events(kvm);
        spin_lock(&kvm_lock);
@@ -735,8 +754,11 @@ static void kvm_destroy_vm(struct kvm *kvm)
        spin_unlock(&kvm_lock);
        kvm_free_irq_routing(kvm);
        for (i = 0; i < KVM_NR_BUSES; i++) {
-               if (kvm->buses[i])
-                       kvm_io_bus_destroy(kvm->buses[i]);
+               struct kvm_io_bus *bus;
+
+               bus = rcu_dereference_protected(kvm->buses[i], 1);
+               if (bus)
+                       kvm_io_bus_destroy(bus);
                kvm->buses[i] = NULL;
        }
        kvm_coalesced_mmio_free(kvm);
@@ -748,7 +770,8 @@ static void kvm_destroy_vm(struct kvm *kvm)
        kvm_arch_destroy_vm(kvm);
        kvm_destroy_devices(kvm);
        for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++)
-               kvm_free_memslots(kvm, kvm->memslots[i]);
+               kvm_free_memslots(kvm,
+                       rcu_dereference_protected(kvm->memslots[i], 1));
        cleanup_srcu_struct(&kvm->irq_srcu);
        cleanup_srcu_struct(&kvm->srcu);
        kvm_arch_free_vm(kvm);
@@ -2551,13 +2574,14 @@ static long kvm_vcpu_ioctl(struct file *filp,
        if (r)
                return r;
        switch (ioctl) {
-       case KVM_RUN:
+       case KVM_RUN: {
+               struct pid *oldpid;
                r = -EINVAL;
                if (arg)
                        goto out;
-               if (unlikely(vcpu->pid != current->pids[PIDTYPE_PID].pid)) {
+               oldpid = rcu_access_pointer(vcpu->pid);
+               if (unlikely(oldpid != current->pids[PIDTYPE_PID].pid)) {
                        /* The thread running this VCPU changed. */
-                       struct pid *oldpid = vcpu->pid;
                        struct pid *newpid = get_task_pid(current, PIDTYPE_PID);
 
                        rcu_assign_pointer(vcpu->pid, newpid);
@@ -2568,6 +2592,7 @@ static long kvm_vcpu_ioctl(struct file *filp,
                r = kvm_arch_vcpu_ioctl_run(vcpu, vcpu->run);
                trace_kvm_userspace_exit(vcpu->run->exit_reason, r);
                break;
+       }
        case KVM_GET_REGS: {
                struct kvm_regs *kvm_regs;
 
@@ -3202,6 +3227,7 @@ static int kvm_dev_ioctl_create_vm(unsigned long type)
                fput(file);
                return -ENOMEM;
        }
+       kvm_uevent_notify_change(KVM_EVENT_CREATE_VM, kvm);
 
        fd_install(r, file);
        return r;
@@ -3563,7 +3589,7 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
 {
        struct kvm_io_bus *new_bus, *bus;
 
-       bus = kvm->buses[bus_idx];
+       bus = kvm_get_bus(kvm, bus_idx);
        if (!bus)
                return -ENOMEM;
 
@@ -3592,7 +3618,7 @@ void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
        int i;
        struct kvm_io_bus *new_bus, *bus;
 
-       bus = kvm->buses[bus_idx];
+       bus = kvm_get_bus(kvm, bus_idx);
        if (!bus)
                return;
 
@@ -3854,6 +3880,56 @@ static const struct file_operations *stat_fops[] = {
        [KVM_STAT_VM]   = &vm_stat_fops,
 };
 
+static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm)
+{
+       struct kobj_uevent_env *env;
+       unsigned long long created, active;
+
+       if (!kvm_dev.this_device || !kvm)
+               return;
+
+       spin_lock(&kvm_lock);
+       if (type == KVM_EVENT_CREATE_VM) {
+               kvm_createvm_count++;
+               kvm_active_vms++;
+       } else if (type == KVM_EVENT_DESTROY_VM) {
+               kvm_active_vms--;
+       }
+       created = kvm_createvm_count;
+       active = kvm_active_vms;
+       spin_unlock(&kvm_lock);
+
+       env = kzalloc(sizeof(*env), GFP_KERNEL);
+       if (!env)
+               return;
+
+       add_uevent_var(env, "CREATED=%llu", created);
+       add_uevent_var(env, "COUNT=%llu", active);
+
+       if (type == KVM_EVENT_CREATE_VM) {
+               add_uevent_var(env, "EVENT=create");
+               kvm->userspace_pid = task_pid_nr(current);
+       } else if (type == KVM_EVENT_DESTROY_VM) {
+               add_uevent_var(env, "EVENT=destroy");
+       }
+       add_uevent_var(env, "PID=%d", kvm->userspace_pid);
+
+       if (kvm->debugfs_dentry) {
+               char *tmp, *p = kmalloc(PATH_MAX, GFP_KERNEL);
+
+               if (p) {
+                       tmp = dentry_path_raw(kvm->debugfs_dentry, p, PATH_MAX);
+                       if (!IS_ERR(tmp))
+                               add_uevent_var(env, "STATS_PATH=%s", tmp);
+                       kfree(p);
+               }
+       }
+       /* no need for checks, since we are adding at most only 5 keys */
+       env->envp[env->envp_idx++] = NULL;
+       kobject_uevent_env(&kvm_dev.this_device->kobj, KOBJ_CHANGE, env->envp);
+       kfree(env);
+}
+
 static int kvm_init_debug(void)
 {
        int r = -EEXIST;
index 37d9118..d99850c 100644 (file)
@@ -51,6 +51,22 @@ static struct vfio_group *kvm_vfio_group_get_external_user(struct file *filep)
        return vfio_group;
 }
 
+static bool kvm_vfio_external_group_match_file(struct vfio_group *group,
+                                              struct file *filep)
+{
+       bool ret, (*fn)(struct vfio_group *, struct file *);
+
+       fn = symbol_get(vfio_external_group_match_file);
+       if (!fn)
+               return false;
+
+       ret = fn(group, filep);
+
+       symbol_put(vfio_external_group_match_file);
+
+       return ret;
+}
+
 static void kvm_vfio_group_put_external_user(struct vfio_group *vfio_group)
 {
        void (*fn)(struct vfio_group *);
@@ -231,37 +247,31 @@ static int kvm_vfio_set_group(struct kvm_device *dev, long attr, u64 arg)
                if (!f.file)
                        return -EBADF;
 
-               vfio_group = kvm_vfio_group_get_external_user(f.file);
-               fdput(f);
-
-               if (IS_ERR(vfio_group))
-                       return PTR_ERR(vfio_group);
-
                ret = -ENOENT;
 
                mutex_lock(&kv->lock);
 
                list_for_each_entry(kvg, &kv->group_list, node) {
-                       if (kvg->vfio_group != vfio_group)
+                       if (!kvm_vfio_external_group_match_file(kvg->vfio_group,
+                                                               f.file))
                                continue;
 
                        list_del(&kvg->node);
+                       kvm_arch_end_assignment(dev->kvm);
+#ifdef CONFIG_SPAPR_TCE_IOMMU
+                       kvm_spapr_tce_release_vfio_group(dev->kvm,
+                                                        kvg->vfio_group);
+#endif
+                       kvm_vfio_group_set_kvm(kvg->vfio_group, NULL);
                        kvm_vfio_group_put_external_user(kvg->vfio_group);
                        kfree(kvg);
                        ret = 0;
                        break;
                }
 
-               kvm_arch_end_assignment(dev->kvm);
-
                mutex_unlock(&kv->lock);
 
-#ifdef CONFIG_SPAPR_TCE_IOMMU
-               kvm_spapr_tce_release_vfio_group(dev->kvm, vfio_group);
-#endif
-               kvm_vfio_group_set_kvm(vfio_group, NULL);
-
-               kvm_vfio_group_put_external_user(vfio_group);
+               fdput(f);
 
                kvm_vfio_update_coherency(dev);